mirror of
https://github.com/EstrellaXD/Auto_Bangumi.git
synced 2026-04-09 05:29:51 +08:00
2
.gitignore
vendored
2
.gitignore
vendored
@@ -173,7 +173,7 @@ cython_debug/
|
||||
|
||||
test.*
|
||||
.run
|
||||
/dev.sh
|
||||
/src/templates/
|
||||
/src/config/
|
||||
/src/debuger.py
|
||||
/src/dist.zip
|
||||
|
||||
24
dev.sh
Normal file
24
dev.sh
Normal file
@@ -0,0 +1,24 @@
|
||||
#!/bin/bash
|
||||
|
||||
|
||||
# This script is used to run the development environment.
|
||||
|
||||
python3 -m pip install -i https://pypi.tuna.tsinghua.edu.cn/simple install -r requirements.txt
|
||||
|
||||
cd src || exit
|
||||
|
||||
CONFIG_DIR="config"
|
||||
|
||||
if [ ! -d "$CONFIG_DIR" ]; then
|
||||
echo "The directory '$CONFIG_DIR' is missing."
|
||||
mkdir config
|
||||
fi
|
||||
|
||||
VERSION_FILE="module/__version__.py"
|
||||
|
||||
if [ ! -f "$VERSION_FILE" ]; then
|
||||
echo "The file '$VERSION_FILE' is missing."
|
||||
echo "VERSION='DEV_VERSION'" >> "$VERSION_FILE"
|
||||
fi
|
||||
|
||||
python3 main.py
|
||||
@@ -1,9 +1,9 @@
|
||||
from fastapi import Depends, HTTPException, status
|
||||
from fastapi.responses import JSONResponse
|
||||
|
||||
from .log import router
|
||||
|
||||
from module.models import BangumiData
|
||||
from module.database import BangumiDatabase
|
||||
from module.manager import TorrentManager
|
||||
from module.security import get_current_user
|
||||
|
||||
@@ -33,7 +33,7 @@ async def get_data(bangumi_id: str, current_user=Depends(get_current_user)):
|
||||
|
||||
|
||||
@router.post("/api/v1/bangumi/updateRule", tags=["bangumi"])
|
||||
async def update_data(data: BangumiData, current_user=Depends(get_current_user)):
|
||||
async def update_rule(data: BangumiData, current_user=Depends(get_current_user)):
|
||||
if not current_user:
|
||||
raise HTTPException(
|
||||
status_code=status.HTTP_401_UNAUTHORIZED, detail="invalid token"
|
||||
@@ -43,7 +43,7 @@ async def update_data(data: BangumiData, current_user=Depends(get_current_user))
|
||||
|
||||
|
||||
@router.delete("/api/v1/bangumi/deleteRule/{bangumi_id}", tags=["bangumi"])
|
||||
async def delete_data(bangumi_id: str, file:bool = False, current_user=Depends(get_current_user)):
|
||||
async def delete_rule(bangumi_id: str, file: bool = False, current_user=Depends(get_current_user)):
|
||||
if not current_user:
|
||||
raise HTTPException(
|
||||
status_code=status.HTTP_401_UNAUTHORIZED, detail="invalid token"
|
||||
@@ -53,7 +53,7 @@ async def delete_data(bangumi_id: str, file:bool = False, current_user=Depends(g
|
||||
|
||||
|
||||
@router.delete("/api/v1/bangumi/disableRule/{bangumi_id}", tags=["bangumi"])
|
||||
async def delete_rule(
|
||||
async def disable_rule(
|
||||
bangumi_id: str, file: bool = False, current_user=Depends(get_current_user)
|
||||
):
|
||||
if not current_user:
|
||||
@@ -80,6 +80,6 @@ async def reset_all(current_user=Depends(get_current_user)):
|
||||
raise HTTPException(
|
||||
status_code=status.HTTP_401_UNAUTHORIZED, detail="invalid token"
|
||||
)
|
||||
with BangumiDatabase() as database:
|
||||
database.delete_all()
|
||||
return {"status": "ok"}
|
||||
with TorrentManager() as torrent:
|
||||
torrent.delete_all()
|
||||
return JSONResponse(status_code=200, content={"message": "OK"})
|
||||
|
||||
@@ -54,8 +54,8 @@ async def get_search_result(searchstr: str):
|
||||
|
||||
|
||||
@router.get("/RSS/Bangumi", tags=["proxy"])
|
||||
async def get_bangumi(bangumiId: str, groupid: str):
|
||||
full_path = "Bangumi?bangumiId=" + bangumiId + "&groupid=" + groupid
|
||||
async def get_bangumi(bangumiId: str, subgroupid: str):
|
||||
full_path = "Bangumi?bangumiId=" + bangumiId + "&subgroupid=" + subgroupid
|
||||
content = get_rss_content(full_path)
|
||||
return Response(content, media_type="application/xml")
|
||||
|
||||
|
||||
@@ -9,14 +9,16 @@ class Checker:
|
||||
def __init__(self):
|
||||
pass
|
||||
|
||||
def check_renamer(self) -> bool:
|
||||
if self.check_downloader() and settings.bangumi_manage.enable:
|
||||
@staticmethod
|
||||
def check_renamer() -> bool:
|
||||
if settings.bangumi_manage.enable:
|
||||
return True
|
||||
else:
|
||||
return False
|
||||
|
||||
def check_analyser(self) -> bool:
|
||||
if self.check_downloader() and settings.rss_parser.enable:
|
||||
@staticmethod
|
||||
def check_analyser() -> bool:
|
||||
if settings.rss_parser.enable:
|
||||
return True
|
||||
else:
|
||||
return False
|
||||
|
||||
@@ -31,7 +31,6 @@ class Program(RenameThread, RSSThread):
|
||||
"Legacy data detected, starting data migration, please wait patiently."
|
||||
)
|
||||
data_migration()
|
||||
add_rss_feed()
|
||||
self.start()
|
||||
|
||||
def start(self):
|
||||
@@ -39,12 +38,16 @@ class Program(RenameThread, RSSThread):
|
||||
return {"status": "Not ready to start."}
|
||||
self.stop_event.clear()
|
||||
settings.load()
|
||||
if self.enable_renamer:
|
||||
self.rename_start()
|
||||
if self.enable_rss:
|
||||
self.rss_start()
|
||||
logger.info("Program running.")
|
||||
return {"status": "Program started."}
|
||||
if self.downloader_status:
|
||||
if self.enable_renamer:
|
||||
self.rename_start()
|
||||
if self.enable_rss:
|
||||
add_rss_feed()
|
||||
self.rss_start()
|
||||
logger.info("Program running.")
|
||||
return {"status": "Program started."}
|
||||
else:
|
||||
return {"status": "Can't connect to downloader. Program not paused."}
|
||||
|
||||
def stop(self):
|
||||
if self.is_running:
|
||||
|
||||
@@ -9,7 +9,6 @@ from qbittorrentapi.exceptions import (
|
||||
)
|
||||
|
||||
from module.ab_decorator import qb_connect_failed_wait
|
||||
from module.downloader.exceptions import ConflictError
|
||||
|
||||
logger = logging.getLogger(__name__)
|
||||
|
||||
@@ -27,9 +26,9 @@ class QbDownloader:
|
||||
self.host = host
|
||||
self.username = username
|
||||
|
||||
def auth(self):
|
||||
def auth(self, retry=3):
|
||||
times = 0
|
||||
while times < 3:
|
||||
while times < retry:
|
||||
try:
|
||||
self._client.auth_log_in()
|
||||
return True
|
||||
@@ -46,7 +45,8 @@ class QbDownloader:
|
||||
except APIConnectionError:
|
||||
logger.error(f"Cannot connect to qBittorrent Server")
|
||||
logger.info(f"Please check the IP and port in WebUI settings")
|
||||
time.sleep(30)
|
||||
time.sleep(10)
|
||||
times += 1
|
||||
except Exception as e:
|
||||
logger.error(f"Unknown error: {e}")
|
||||
break
|
||||
@@ -55,6 +55,16 @@ class QbDownloader:
|
||||
def logout(self):
|
||||
self._client.auth_log_out()
|
||||
|
||||
def check_host(self):
|
||||
try:
|
||||
self._client.app_version()
|
||||
return True
|
||||
except APIConnectionError:
|
||||
return False
|
||||
|
||||
def check_rss(self, rss_link: str):
|
||||
pass
|
||||
|
||||
@qb_connect_failed_wait
|
||||
def prefs_init(self, prefs):
|
||||
return self._client.app_set_preferences(prefs=prefs)
|
||||
@@ -93,15 +103,16 @@ class QbDownloader:
|
||||
return False
|
||||
|
||||
def rss_add_feed(self, url, item_path):
|
||||
self._client.rss_add_feed(url, item_path)
|
||||
try:
|
||||
self._client.rss_add_feed(url, item_path)
|
||||
except Conflict409Error:
|
||||
logger.warning(f"[Downloader] RSS feed {url} already exists")
|
||||
|
||||
def rss_remove_item(self, item_path):
|
||||
try:
|
||||
self._client.rss_remove_item(item_path)
|
||||
except Conflict409Error as e:
|
||||
logger.debug(e)
|
||||
logger.info("Add new RSS")
|
||||
raise ConflictError()
|
||||
except Conflict409Error:
|
||||
logger.warning(f"[Downloader] RSS item {item_path} does not exist")
|
||||
|
||||
def rss_get_feeds(self):
|
||||
return self._client.rss_items()
|
||||
|
||||
@@ -33,6 +33,8 @@ class DownloadClient(TorrentPath):
|
||||
def __enter__(self):
|
||||
if not self.authed:
|
||||
self.auth()
|
||||
else:
|
||||
logger.error("[Downloader] Already authed.")
|
||||
return self
|
||||
|
||||
def __exit__(self, exc_type, exc_val, exc_tb):
|
||||
@@ -42,7 +44,13 @@ class DownloadClient(TorrentPath):
|
||||
|
||||
def auth(self):
|
||||
self.authed = self.client.auth()
|
||||
logger.debug("Authed.")
|
||||
if self.authed:
|
||||
logger.info("[Downloader] Authed.")
|
||||
else:
|
||||
logger.error("[Downloader] Auth failed.")
|
||||
|
||||
def check_host(self):
|
||||
return self.client.check_host()
|
||||
|
||||
def init_downloader(self):
|
||||
prefs = {
|
||||
|
||||
@@ -13,8 +13,8 @@ logger = logging.getLogger(__name__)
|
||||
|
||||
|
||||
class TorrentPath:
|
||||
def __init__(self):
|
||||
self.download_path = settings.downloader.path
|
||||
def __init__(self, download_path: str = settings.downloader.path):
|
||||
self.download_path = download_path
|
||||
|
||||
@staticmethod
|
||||
def check_files(info):
|
||||
@@ -44,11 +44,11 @@ class TorrentPath:
|
||||
return bangumi_name, season
|
||||
|
||||
@staticmethod
|
||||
def _file_depth(path):
|
||||
return len(path.split(path.sep))
|
||||
def _file_depth(file_path):
|
||||
return len(file_path.split(path.sep))
|
||||
|
||||
def is_ep(self, path):
|
||||
return self._file_depth(path) <= 2
|
||||
def is_ep(self, file_path):
|
||||
return self._file_depth(file_path) <= 2
|
||||
|
||||
def _gen_save_path(self, data: BangumiData):
|
||||
folder = (
|
||||
|
||||
@@ -1,5 +1,7 @@
|
||||
import logging
|
||||
|
||||
from fastapi.responses import JSONResponse
|
||||
|
||||
from module.downloader import DownloadClient
|
||||
from module.models import BangumiData
|
||||
from module.database import BangumiDatabase
|
||||
@@ -31,9 +33,9 @@ class SeasonCollector(DownloadClient):
|
||||
with BangumiDatabase() as db:
|
||||
data.added = True
|
||||
data.eps_collect = True
|
||||
self.set_rule(data)
|
||||
db.insert(data)
|
||||
self.add_rss_feed(data.rss_link[0], item_path=data.official_title)
|
||||
self.set_rule(data)
|
||||
|
||||
|
||||
def eps_complete():
|
||||
|
||||
@@ -1,4 +1,5 @@
|
||||
import logging
|
||||
from fastapi.responses import JSONResponse
|
||||
|
||||
from module.downloader import DownloadClient
|
||||
from module.models import BangumiData
|
||||
@@ -20,49 +21,30 @@ class TorrentManager(BangumiDatabase):
|
||||
if hash_list:
|
||||
client.delete_torrent(hash_list)
|
||||
logger.info(f"Delete rule and torrents for {data.official_title}")
|
||||
return {
|
||||
"status": "success",
|
||||
"msg": f"Delete torrents for {data.official_title}",
|
||||
}
|
||||
return f"Delete {data.official_title} torrents."
|
||||
else:
|
||||
return {
|
||||
"status": "error",
|
||||
"msg": f"Can't find torrents for {data.official_title}",
|
||||
}
|
||||
return f"Can't find {data.official_title} torrents."
|
||||
|
||||
def delete_rule(self, _id: int | str, file: bool = False):
|
||||
data = self.search_id(int(_id))
|
||||
if isinstance(data, BangumiData):
|
||||
with DownloadClient() as client:
|
||||
client.remove_rule(data.rule_name)
|
||||
client.remove_rss_feed(data.official_title)
|
||||
self.delete_one(int(_id))
|
||||
if file:
|
||||
self.delete_torrents(data, client)
|
||||
return {
|
||||
"status": "success",
|
||||
"msg": f"Delete rule and torrents for {data.official_title}",
|
||||
}
|
||||
torrent_message = self.delete_torrents(data, client)
|
||||
return JSONResponse(status_code=200, content={
|
||||
"msg": f"Delete {data.official_title} rule. {torrent_message}"
|
||||
})
|
||||
logger.info(f"[Manager] Delete rule for {data.official_title}")
|
||||
return {
|
||||
"status": "success",
|
||||
"msg": f"Delete rule for {data.official_title}",
|
||||
}
|
||||
return JSONResponse(status_code=200, content={
|
||||
"msg": f"Delete rule for {data.official_title}"
|
||||
})
|
||||
else:
|
||||
return {"status": "error", "msg": f"Can't find id {_id}"}
|
||||
# data = self.search_id(int(_id))
|
||||
# if isinstance(data, BangumiData):
|
||||
# self.delete_one(int(_id))
|
||||
# if file:
|
||||
# self.delete_torrents(data)
|
||||
# logger.info(f"Delete {data.official_title} and torrents.")
|
||||
# return {
|
||||
# "status": "success",
|
||||
# "msg": f"Delete {data.official_title} and torrents.",
|
||||
# }
|
||||
# logger.info(f"Delete {data.official_title}")
|
||||
# return {"status": "success", "msg": f"Delete {data.official_title}"}
|
||||
# else:
|
||||
# return data
|
||||
return JSONResponse(status_code=406, content={
|
||||
"msg": f"Can't find id {_id}"
|
||||
})
|
||||
|
||||
def disable_rule(self, _id: str | int, file: bool = False):
|
||||
data = self.search_id(int(_id))
|
||||
@@ -72,18 +54,18 @@ class TorrentManager(BangumiDatabase):
|
||||
data.deleted = True
|
||||
self.update_one(data)
|
||||
if file:
|
||||
self.delete_torrents(data, client)
|
||||
return {
|
||||
"status": "success",
|
||||
"msg": f"Disable rule and delete torrents for {data.official_title}",
|
||||
}
|
||||
torrent_message = self.delete_torrents(data, client)
|
||||
return JSONResponse(status_code=200, content={
|
||||
"msg": f"Disable {data.official_title} rule. {torrent_message}"
|
||||
})
|
||||
logger.info(f"[Manager] Disable rule for {data.official_title}")
|
||||
return {
|
||||
"status": "success",
|
||||
"msg": f"Disable rule for {data.official_title}",
|
||||
}
|
||||
return JSONResponse(status_code=200, content={
|
||||
"msg": f"Disable {data.official_title} rule.",
|
||||
})
|
||||
else:
|
||||
return {"status": "error", "msg": f"Can't find data with id {_id}"}
|
||||
return JSONResponse(status_code=406, content={
|
||||
"msg": f"Can't find id {_id}"
|
||||
})
|
||||
|
||||
def enable_rule(self, _id: str | int):
|
||||
data = self.search_id(int(_id))
|
||||
@@ -93,18 +75,23 @@ class TorrentManager(BangumiDatabase):
|
||||
with DownloadClient() as client:
|
||||
client.set_rule(data)
|
||||
logger.info(f"[Manager] Enable rule for {data.official_title}")
|
||||
return {
|
||||
"status": "success",
|
||||
"msg": f"Enable rule for {data.official_title}",
|
||||
}
|
||||
return JSONResponse(status_code=200, content={
|
||||
"msg": f"Enable {data.official_title} rule.",
|
||||
})
|
||||
else:
|
||||
return JSONResponse(status_code=406, content={
|
||||
"msg": f"Can't find bangumi id {_id}"
|
||||
})
|
||||
|
||||
def update_rule(self, data: BangumiData):
|
||||
old_data = self.search_id(data.id)
|
||||
if not old_data:
|
||||
logger.error(f"[Manager] Can't find data with id {data.id}")
|
||||
return {"status": "error", "msg": f"Can't find data with id {data.id}"}
|
||||
logger.error(f"[Manager] Can't find data with {data.id}")
|
||||
return JSONResponse(status_code=406, content={
|
||||
"msg": f"Can't find data with {data.id}"
|
||||
})
|
||||
else:
|
||||
# Set torrent path
|
||||
# Move torrent
|
||||
match_list = self.__match_torrents_list(data)
|
||||
with DownloadClient() as client:
|
||||
path = client._gen_save_path(data)
|
||||
@@ -114,10 +101,9 @@ class TorrentManager(BangumiDatabase):
|
||||
client.remove_rule(data.rule_name)
|
||||
client.set_rule(data)
|
||||
self.update_one(data)
|
||||
return {
|
||||
"status": "success",
|
||||
return JSONResponse(status_code=200, content={
|
||||
"msg": f"Set new path for {data.official_title}",
|
||||
}
|
||||
})
|
||||
|
||||
def search_all_bangumi(self):
|
||||
datas = self.search_all()
|
||||
@@ -128,7 +114,7 @@ class TorrentManager(BangumiDatabase):
|
||||
def search_one(self, _id: int | str):
|
||||
data = self.search_id(int(_id))
|
||||
if not data:
|
||||
logger.error(f"[Manager] Can't find data with id {_id}")
|
||||
return {"status": "error", "msg": f"Can't find data with id {_id}"}
|
||||
logger.error(f"[Manager] Can't find data with {_id}")
|
||||
return {"status": "error", "msg": f"Can't find data with {_id}"}
|
||||
else:
|
||||
return data
|
||||
|
||||
Reference in New Issue
Block a user