diff --git a/src/module/api/__init__.py b/src/module/api/__init__.py index 546d37eb..e90516af 100644 --- a/src/module/api/__init__.py +++ b/src/module/api/__init__.py @@ -1 +1 @@ -from .program import router +from .web import router diff --git a/src/module/api/api.py b/src/module/api/api.py index 8b3af1fd..20e9dab4 100644 --- a/src/module/api/api.py +++ b/src/module/api/api.py @@ -20,11 +20,6 @@ async def get_log(): return Response("Log file not found", status_code=404) -@router.get("/api/v1/resetRule") -def reset_rule(): - pass - - diff --git a/src/module/api/bangumi.py b/src/module/api/bangumi.py index 64c462ea..c7d1596f 100644 --- a/src/module/api/bangumi.py +++ b/src/module/api/bangumi.py @@ -2,16 +2,16 @@ from .api import router from module.models import BangumiData from module.database import BangumiDatabase -from module.manager import set_new_path +from module.manager import TorrentManager -@router.get("/api/v1/bangumi/getData", tags=["bangumi"]) +@router.get("/api/v1/bangumi/getAll", tags=["bangumi"], response_model=list[BangumiData]) async def get_all_data(): with BangumiDatabase() as database: return database.search_all() -@router.get("/api/v1/bangumi/getData/{bangumi_id}", tags=["bangumi"]) +@router.get("/api/v1/bangumi/getData/{bangumi_id}", tags=["bangumi"], response_model=BangumiData) async def get_data(bangumi_id: str): with BangumiDatabase() as database: data = database.search_id(int(bangumi_id)) @@ -21,8 +21,46 @@ async def get_data(bangumi_id: str): return {"": "data not exist"} -@router.post("/api/v1/bangumi/UpdateData", tags=["bangumi"]) +@router.post("/api/v1/bangumi/updateData", tags=["bangumi"]) async def update_data(data: BangumiData): with BangumiDatabase() as database: - database.update(data) - set_new_path(data) + updated = database.update_one(data) + if updated: + with TorrentManager() as torrent: + torrent.set_new_path(data) + return {"status": "ok"} + else: + return {"status": "data not exist"} + + +@router.delete("/api/v1/bangumi/deleteData/{bangumi_id}", tags=["bangumi"]) +async def delete_data(bangumi_id: str): + with BangumiDatabase() as database: + _id = int(bangumi_id) + deleted = database.delete_one(_id) + if deleted: + return {"status": "ok"} + else: + return {"status": "data not exist"} + + +@router.delete("/api/v1/bangumi/deleteRule/{bangumi_id}", tags=["bangumi"]) +async def delete_rule(bangumi_id: str, file: bool = False): + with BangumiDatabase() as database: + _id = int(bangumi_id) + data = database.search_id(_id) + if data: + with TorrentManager() as torrent: + torrent.delete_rule(data) + if file: + torrent.delete_bangumi(data) + return {"status": "ok"} + else: + return {"status": "data not exist"} + + +@router.get("/api/v1/bangumi/resetAll", tags=["bangumi"]) +async def reset_all(): + with BangumiDatabase() as database: + database.delete_all() + return {"status": "ok"} \ No newline at end of file diff --git a/src/module/api/download.py b/src/module/api/download.py index 50849fa5..b254c22b 100644 --- a/src/module/api/download.py +++ b/src/module/api/download.py @@ -9,7 +9,7 @@ def link_process(link): return RSSAnalyser().rss_to_data(link, full_parse=False) -@router.post("/api/v1/collection", tags=["download"]) +@router.post("/api/v1/download/collection", tags=["download"]) async def collection(link: RssLink): data = link_process(link) if data: @@ -20,7 +20,7 @@ async def collection(link: RssLink): return {"status": "Failed to parse link"} -@router.post("/api/v1/subscribe", tags=["download"]) +@router.post("/api/v1/download/subscribe", tags=["download"]) async def subscribe(link: RssLink): data = link_process(link) if data: @@ -29,3 +29,14 @@ async def subscribe(link: RssLink): return data[0] else: return {"status": "Failed to parse link"} + + +@router.post("/api/v1/download/manual", tags=["download"]) +async def manual(link: RssLink): + data = link_process(link) + if data: + with FullSeasonGet() as season: + season.download_manual(data[0], link) + return data[0] + else: + return {"status": "Failed to parse link"} diff --git a/src/module/api/program.py b/src/module/api/program.py index cf4b751c..9ef9eb2b 100644 --- a/src/module/api/program.py +++ b/src/module/api/program.py @@ -2,15 +2,10 @@ import os import signal import logging -from fastapi import Request -from fastapi.responses import HTMLResponse, RedirectResponse -from fastapi.staticfiles import StaticFiles -from fastapi.templating import Jinja2Templates - -from .proxy import router +from .download import router from module.core import start_thread, start_program, stop_thread, stop_event -from module.conf import VERSION, settings, setup_logger +from module.conf import settings, setup_logger logger = logging.getLogger(__name__) @@ -63,17 +58,3 @@ async def shutdown_program(): os.kill(os.getpid(), signal.SIGINT) return {"status": "ok"} - -if VERSION != "DEV_VERSION": - router.mount("/assets", StaticFiles(directory="templates/assets"), name="assets") - templates = Jinja2Templates(directory="templates") - - # HTML Response - @router.get("/{full_path:path}", response_class=HTMLResponse, tags=["html"]) - def index(request: Request): - context = {"request": request} - return templates.TemplateResponse("index.html", context) -else: - @router.get("/", status_code=302, tags=["html"]) - def index(): - return RedirectResponse("/docs") \ No newline at end of file diff --git a/src/module/api/proxy.py b/src/module/api/proxy.py index 314b54f8..b4efc611 100644 --- a/src/module/api/proxy.py +++ b/src/module/api/proxy.py @@ -3,7 +3,7 @@ import logging from fastapi.responses import Response -from .download import router +from .program import router from module.conf import settings from module.network import RequestContent diff --git a/src/module/api/web.py b/src/module/api/web.py new file mode 100644 index 00000000..76dcc91e --- /dev/null +++ b/src/module/api/web.py @@ -0,0 +1,23 @@ +from fastapi import Request +from fastapi.responses import HTMLResponse, RedirectResponse +from fastapi.staticfiles import StaticFiles +from fastapi.templating import Jinja2Templates + +from .proxy import router + +from module.conf import VERSION + + +if VERSION != "DEV_VERSION": + router.mount("/assets", StaticFiles(directory="templates/assets"), name="assets") + templates = Jinja2Templates(directory="templates") + + # HTML Response + @router.get("/{full_path:path}", response_class=HTMLResponse, tags=["html"]) + def index(request: Request): + context = {"request": request} + return templates.TemplateResponse("index.html", context) +else: + @router.get("/", status_code=302, tags=["html"]) + def index(): + return RedirectResponse("/docs") \ No newline at end of file diff --git a/src/module/database/bangumi.py b/src/module/database/bangumi.py index 7dc33e83..6ae9c704 100644 --- a/src/module/database/bangumi.py +++ b/src/module/database/bangumi.py @@ -86,7 +86,7 @@ class BangumiDatabase(DataConnector): logger.debug(f"Add {len(data)} bangumi into database.") self._conn.commit() - def update(self, data: BangumiData) -> bool: + def update_one(self, data: BangumiData) -> bool: db_data = self.__data_to_db(data) update_columns = ", ".join([f"{key} = :{key}" for key in db_data.keys() if key != "id"]) self._cursor.execute(f"UPDATE bangumi SET {update_columns} WHERE id = :id", db_data) @@ -112,6 +112,26 @@ class BangumiDatabase(DataConnector): self._conn.commit() logger.debug(f"Update {title_raw} rss_link to {rss_set}.") + def delete_one(self, _id: int) -> bool: + self._cursor.execute( + """ + DELETE FROM bangumi WHERE id = :id + """, + {"id": _id}, + ) + self._conn.commit() + logger.debug(f"Delete bangumi id: {_id}.") + return self._cursor.rowcount == 1 + + def delete_all(self): + self._cursor.execute( + """ + DELETE FROM bangumi + """ + ) + self._conn.commit() + logger.debug("Delete all bangumi.") + def search_all(self) -> list[BangumiData]: self._cursor.execute( """ diff --git a/src/module/downloader/client/qb_downloader.py b/src/module/downloader/client/qb_downloader.py index e868b806..f503e8a2 100644 --- a/src/module/downloader/client/qb_downloader.py +++ b/src/module/downloader/client/qb_downloader.py @@ -127,3 +127,6 @@ class QbDownloader: def check_connection(self): return self._client.app_version() + + def remove_rule(self, rule_name): + self._client.rss_remove_rule(rule_name) diff --git a/src/module/downloader/download_client.py b/src/module/downloader/download_client.py index 3ac4223d..577786b8 100644 --- a/src/module/downloader/download_client.py +++ b/src/module/downloader/download_client.py @@ -119,7 +119,7 @@ class DownloadClient: def delete_torrent(self, hashes): self.client.torrents_delete(hashes) - logger.info(f"Remove bad torrents.") + logger.info(f"Remove torrents.") def add_torrent(self, torrent: dict): self.client.torrents_add( @@ -141,3 +141,7 @@ class DownloadClient: def set_category(self, hashes, category): self.client.set_category(hashes, category) + + def remove_rule(self, rule_name): + self.client.remove_rule(rule_name) + logger.info(f"Delete rule: {rule_name}") \ No newline at end of file diff --git a/src/module/manager/__init__.py b/src/module/manager/__init__.py index 73979ee7..8c0a8561 100644 --- a/src/module/manager/__init__.py +++ b/src/module/manager/__init__.py @@ -1,3 +1,3 @@ from .eps_complete import FullSeasonGet from .renamer import Renamer -from .repath import set_new_path +from .torrent import TorrentManager diff --git a/src/module/manager/torrent.py b/src/module/manager/torrent.py new file mode 100644 index 00000000..354794f6 --- /dev/null +++ b/src/module/manager/torrent.py @@ -0,0 +1,44 @@ +import logging + +from module.downloader import DownloadClient +from module.conf import settings +from module.models import BangumiData + +logger = logging.getLogger(__name__) + + +class TorrentManager(DownloadClient): + @staticmethod + def __gen_path(data: BangumiData): + download_path = settings.downloader.path + if ":\\" in download_path: + import ntpath as path + else: + import os.path as path + folder = f"{data.official_title}({data.year})" if data.year else data.official_title + path = path.join(download_path, folder, f"Season {data.season}") + return path + + @staticmethod + def __match_torrents_list(title_raw: str) -> list: + with DownloadClient() as client: + torrents = client.get_torrent_info() + return [torrent.hash for torrent in torrents if title_raw in torrent.name] + + def delete_bangumi(self, data: BangumiData): + hash_list = self.__match_torrents_list(data.title_raw) + self.delete_torrent(hash_list) + + def delete_rule(self, data: BangumiData): + rule_name = f"{data.official_title}({data.year})" if data.year else data.title_raw + if settings.bangumi_manage.group_tag: + rule_name = f"[{data.group_name}] {rule_name}" if self.group_tag else rule_name + self.remove_rule(rule_name) + + def set_new_path(self, data: BangumiData): + # set download rule + self.set_rule(data) + # set torrent path + match_list = self.__match_torrents_list(data.title_raw) + path = self.__gen_path(data) + self.move_torrent(match_list, path)