From 0bc25fe00bad8691d1e1f9c0b61b5d62d5a1d466 Mon Sep 17 00:00:00 2001 From: EstrellaXD Date: Wed, 17 May 2023 20:41:07 +0800 Subject: [PATCH] Refactor new program class --- src/main.py | 5 +- src/module/api/program.py | 34 ++-- src/module/checker/__init__.py | 1 + src/module/checker/checker.py | 49 ++++++ src/module/conf/config.py | 3 +- src/module/conf/log.py | 4 +- src/module/core/__init__.py | 2 +- src/module/core/program.py | 48 ++++++ src/module/core/startup.py | 0 src/module/core/status.py | 44 +++++ src/module/core/sub_thread.py | 161 ++++++------------ src/module/inspector/__init__.py | 1 - src/module/inspector/inspector.py | 10 -- src/module/manager/renamer.py | 2 + src/module/rss/rss_analyser.py | 2 +- src/module/update/__init__.py | 0 src/module/{core => update}/data_migration.py | 0 17 files changed, 232 insertions(+), 134 deletions(-) create mode 100644 src/module/checker/__init__.py create mode 100644 src/module/checker/checker.py create mode 100644 src/module/core/program.py create mode 100644 src/module/core/startup.py create mode 100644 src/module/core/status.py delete mode 100644 src/module/inspector/__init__.py delete mode 100644 src/module/inspector/inspector.py create mode 100644 src/module/update/__init__.py rename src/module/{core => update}/data_migration.py (100%) diff --git a/src/main.py b/src/main.py index f808203e..1954fa1b 100644 --- a/src/main.py +++ b/src/main.py @@ -4,8 +4,7 @@ import uvicorn from module.api import router from module.conf import settings, setup_logger -log_level = logging.DEBUG if settings.log.debug_enable else logging.INFO -setup_logger(log_level, reset=True) +setup_logger(reset=True) logger = logging.getLogger(__name__) uvicorn_logging_config = { "version": 1, @@ -13,7 +12,7 @@ uvicorn_logging_config = { "handlers": logger.handlers, "loggers": { "uvicorn": { - "level": log_level, + "level": logger.level, }, "uvicorn.access": { "level": "WARNING", diff --git a/src/module/api/program.py b/src/module/api/program.py index 34564f3d..8ef123c9 100644 --- a/src/module/api/program.py +++ b/src/module/api/program.py @@ -2,46 +2,58 @@ import os import signal import logging +from fastapi.exceptions import HTTPException + from .download import router -from module.core import start_thread, start_program, stop_thread, stop_event, check_status, check_rss, check_downloader +from module.core import Program, check_status, check_rss, check_downloader logger = logging.getLogger(__name__) +program = Program() @router.on_event("startup") async def startup(): - await start_program() + await program.startup() @router.on_event("shutdown") async def shutdown(): - stop_event.set() + await program.stop() logger.info("Stopping program...") @router.get("/api/v1/restart", tags=["program"]) async def restart(): - stop_thread() - start_thread() - return {"status": "ok"} + try: + await program.restart() + return {"status": "ok"} + except Exception as e: + logger.debug(e) + logger.warning("Failed to restart program") + raise HTTPException(status_code=500, detail="Failed to restart program") @router.get("/api/v1/start", tags=["program"]) async def start(): - start_thread() - return {"status": "ok"} + try: + await program.start() + return {"status": "ok"} + except Exception as e: + logger.debug(e) + logger.warning("Failed to start program") + raise HTTPException(status_code=500, detail="Failed to start program") @router.get("/api/v1/stop", tags=["program"]) async def stop(): - stop_thread() + await program.stop() return {"status": "ok"} @router.get("/api/v1/status", tags=["program"]) async def status(): - if stop_event.is_set(): + if not program.is_running: return {"status": "stop"} else: return {"status": "running"} @@ -49,7 +61,7 @@ async def status(): @router.get("/api/v1/shutdown", tags=["program"]) async def shutdown_program(): - stop_thread() + await program.stop() logger.info("Shutting down program...") os.kill(os.getpid(), signal.SIGINT) return {"status": "ok"} diff --git a/src/module/checker/__init__.py b/src/module/checker/__init__.py new file mode 100644 index 00000000..0c9226c5 --- /dev/null +++ b/src/module/checker/__init__.py @@ -0,0 +1 @@ +from .checker import Checker \ No newline at end of file diff --git a/src/module/checker/checker.py b/src/module/checker/checker.py new file mode 100644 index 00000000..a7590134 --- /dev/null +++ b/src/module/checker/checker.py @@ -0,0 +1,49 @@ +import os.path + +from module.downloader import DownloadClient +from module.network import RequestContent +from module.conf import settings, DATA_PATH + + +class Checker: + def __init__(self): + pass + + def check_renamer(self) -> bool: + if self.check_downloader() and\ + settings.bangumi_manage.enable: + return True + else: + return False + + def check_analyser(self) -> bool: + if self.check_torrents() and\ + self.check_downloader() and\ + settings.rss_parser.enable: + return True + else: + return False + + @staticmethod + def check_downloader() -> bool: + with DownloadClient() as client: + if client.authed: + return True + else: + return False + + @staticmethod + def check_torrents() -> bool: + with RequestContent() as req: + torrents = req.get_torrents(settings.rss_link) + if torrents: + return True + else: + return False + + @staticmethod + def check_first_run() -> bool: + if os.path.exists(DATA_PATH): + return False + else: + return True diff --git a/src/module/conf/config.py b/src/module/conf/config.py index 9c9ca63b..7eba3d6e 100644 --- a/src/module/conf/config.py +++ b/src/module/conf/config.py @@ -49,7 +49,8 @@ class Settings(Config): with open(CONFIG_PATH, "w", encoding="utf-8") as f: json.dump(config_dict, f, indent=4) - def rss_link(self): + @property + def rss_link(self) -> str: if "://" not in self.rss_parser.custom_url: return f"https://{self.rss_parser.custom_url}/RSS/MyBangumi?token={self.rss_parser.token}" return ( diff --git a/src/module/conf/log.py b/src/module/conf/log.py index 2c1d1f8f..75463a6f 100644 --- a/src/module/conf/log.py +++ b/src/module/conf/log.py @@ -1,10 +1,12 @@ import os import logging +from .config import settings + LOG_PATH = "data/log.txt" - def setup_logger(level: int = logging.INFO, reset: bool = False): + level = logging.DEBUG if settings.log.debug_enable else level if not os.path.isdir("data"): os.mkdir("data") if reset and os.path.isfile(LOG_PATH): diff --git a/src/module/core/__init__.py b/src/module/core/__init__.py index 2bf029d5..8194e6bb 100644 --- a/src/module/core/__init__.py +++ b/src/module/core/__init__.py @@ -1,2 +1,2 @@ -from .sub_thread import * +from .program import Program from .check import check_status, check_rss, check_downloader \ No newline at end of file diff --git a/src/module/core/program.py b/src/module/core/program.py new file mode 100644 index 00000000..0c587c0b --- /dev/null +++ b/src/module/core/program.py @@ -0,0 +1,48 @@ +import logging + +from .sub_thread import RenameThread, RSSThread + +from module.conf import settings, VERSION + +logger = logging.getLogger(__name__) + + +class Program(RenameThread, RSSThread): + @staticmethod + def __start_info(): + with open("icon", "r") as f: + for line in f.readlines(): + logger.info(line.strip("\n")) + logger.info( + f"Version {VERSION} Author: EstrellaXD Twitter: https://twitter.com/Estrella_Pan" + ) + logger.info("GitHub: https://github.com/EstrellaXD/Auto_Bangumi/") + logger.info("Starting AutoBangumi...") + + async def startup(self): + self.__start_info() + await self.start() + + async def start(self): + self.stop_event.clear() + settings.load() + if self.enable_renamer: + self.rename_start() + logger.info("Renamer started.") + if self.enable_rss: + self.rss_start() + logger.info("RSS started.") + return {"status": "Program started."} + + async def stop(self): + if self.is_running: + self.stop_event.set() + self.rename_stop() + self.rss_stop() + else: + return {"status": "Program is not running."} + + async def restart(self): + await self.stop() + await self.start() + return {"status": "Program restarted."} diff --git a/src/module/core/startup.py b/src/module/core/startup.py new file mode 100644 index 00000000..e69de29b diff --git a/src/module/core/status.py b/src/module/core/status.py new file mode 100644 index 00000000..55a0a866 --- /dev/null +++ b/src/module/core/status.py @@ -0,0 +1,44 @@ +import threading + +from module.checker import Checker + + +class ProgramStatus(Checker): + def __init__(self): + super().__init__() + self.stop_event = threading.Event() + self.lock = threading.Lock() + self._downloader_status = False + self._torrents_status = False + + @property + def is_running(self): + return not self.stop_event.is_set() + + @property + def is_stopped(self): + return self.stop_event.is_set() + + @property + def downloader_status(self): + if not self._downloader_status: + self._downloader_status = self.check_downloader() + return self._downloader_status + + @property + def torrents_status(self): + if not self._torrents_status: + self._torrents_status = self.check_torrents() + return self._torrents_status + + @property + def enable_rss(self): + return self.check_analyser() + + @property + def enable_renamer(self): + return self.check_renamer() + + @property + def first_run(self): + return self.check_first_run() diff --git a/src/module/core/sub_thread.py b/src/module/core/sub_thread.py index fc21c922..f615b800 100644 --- a/src/module/core/sub_thread.py +++ b/src/module/core/sub_thread.py @@ -1,118 +1,69 @@ -import os.path -import time -import logging import threading -from .data_migration import data_migration -from .check import check_status +from .status import ProgramStatus from module.rss import RSSAnalyser, add_rules from module.manager import Renamer, FullSeasonGet -from module.database import BangumiDatabase -from module.downloader import DownloadClient -from module.conf import settings, VERSION, DATA_PATH - -logger = logging.getLogger(__name__) - -stop_event = threading.Event() +from module.conf import settings -def rss_loop(stop_event): - rss_analyser = RSSAnalyser() - rss_link = settings.rss_link() - while not stop_event.is_set(): - rss_analyser.run(rss_link) - add_rules() - if settings.bangumi_manage.eps_complete: - with FullSeasonGet() as full_season_get: - full_season_get.eps_complete() - stop_event.wait(settings.program.rss_time) +class RSSThread(ProgramStatus): + def __init__(self): + super().__init__() + self._rss_thread = threading.Thread( + target=self.rss_loop, + ) + + def rss_loop(self): + rss_analyser = RSSAnalyser() + while not self.stop_event.is_set(): + rss_analyser.run() + add_rules() + if settings.bangumi_manage.eps_complete: + with FullSeasonGet() as full_season_get: + full_season_get.eps_complete() + self.stop_event.wait(settings.program.rss_time) + + def rss_start(self): + self.rss_thread.start() + + def rss_stop(self): + if self._rss_thread.is_alive(): + self._rss_thread.join() + + @property + def rss_thread(self): + if not self._rss_thread.is_alive(): + self._rss_thread = threading.Thread( + target=self.rss_loop, + ) + return self._rss_thread -def rename_loop(stop_event): - while not stop_event.is_set(): - with Renamer() as renamer: - renamer.rename() - stop_event.wait(settings.program.rename_time) +class RenameThread(ProgramStatus): + def __init__(self): + super().__init__() + self._rename_thread = threading.Thread( + target=self.rename_loop, + ) + def rename_loop(self): + while not self.stop_event.is_set(): + with Renamer() as renamer: + renamer.rename() + self.stop_event.wait(settings.program.rename_time) -rss_thread = threading.Thread( - target=rss_loop, - args=(stop_event,), -) - -rename_thread = threading.Thread( - target=rename_loop, - args=(stop_event,), -) - - -def start_info(): - with open("icon", "r") as f: - for line in f.readlines(): - logger.info(line.strip("\n")) - logger.info( - f"Version {VERSION} Author: EstrellaXD Twitter: https://twitter.com/Estrella_Pan" - ) - logger.info("GitHub: https://github.com/EstrellaXD/Auto_Bangumi/") - logger.info("Starting AutoBangumi...") - - -def stop_thread(): - global rss_thread, rename_thread - if not stop_event.is_set(): - stop_event.set() - rename_thread.join() - rss_thread.join() - - -def start_thread(): - global rss_thread, rename_thread - if stop_event.is_set(): - time.sleep(1) - settings.load() - stop_event.clear() - else: - return {"status": "Program is running."} - if not check_status(): - stop_event.set() - logger.info("Program paused.") - return {"status": "start failed"} - rss_thread = threading.Thread(target=rss_loop, args=(stop_event,)) - rename_thread = threading.Thread(target=rename_loop, args=(stop_event,)) - if settings.rss_parser.enable: - rss_thread.start() - if settings.bangumi_manage.enable: - rename_thread.start() - return {"status": "Restart successfully."} - - -def first_run(): - if not os.path.exists(DATA_PATH): - if data_migration(): - logger.info("Updated, data migration completed.") - else: - logger.info("First run, init downloader.") - with DownloadClient() as client: - client.init_downloader() - client.add_rss_feed(settings.rss_link()) - - -async def start_program(): - global rss_thread, rename_thread - start_info() - if not check_status(): - stop_event.set() - logger.info("Program paused.") - else: - first_run() - with BangumiDatabase() as database: - database.update_table() - rss_thread = threading.Thread(target=rss_loop, args=(stop_event,)) - rename_thread = threading.Thread(target=rename_loop, args=(stop_event,)) - if settings.rss_parser.enable: - rss_thread.start() - if settings.bangumi_manage.enable: - rename_thread.start() + def rename_start(self): + self.rename_thread.start() + def rename_stop(self): + if self._rename_thread.is_alive(): + self._rename_thread.join() + @property + def rename_thread(self): + if not self._rename_thread.is_alive(): + self._rename_thread = threading.Thread( + target=self.rename_loop, + ) + return self._rename_thread diff --git a/src/module/inspector/__init__.py b/src/module/inspector/__init__.py deleted file mode 100644 index 7e51f125..00000000 --- a/src/module/inspector/__init__.py +++ /dev/null @@ -1 +0,0 @@ -from .inspector import Inspector \ No newline at end of file diff --git a/src/module/inspector/inspector.py b/src/module/inspector/inspector.py deleted file mode 100644 index 3663958c..00000000 --- a/src/module/inspector/inspector.py +++ /dev/null @@ -1,10 +0,0 @@ -class Inspector: - def __init__(self): - pass - - def check_downloader(self) -> bool: - pass - - def check_link(self, url) -> bool: - pass - \ No newline at end of file diff --git a/src/module/manager/renamer.py b/src/module/manager/renamer.py index 1d028d02..ad7a1b9b 100644 --- a/src/module/manager/renamer.py +++ b/src/module/manager/renamer.py @@ -193,6 +193,7 @@ class Renamer(DownloadClient): def rename(self): # Get torrent info + logger.debug("Start rename process.") download_path = settings.downloader.path rename_method = settings.bangumi_manage.rename_method recent_info, torrent_count = self.rename_info() @@ -237,3 +238,4 @@ class Renamer(DownloadClient): ) else: logger.warning(f"{info.name} has no media file") + logger.debug("Rename process finished.") diff --git a/src/module/rss/rss_analyser.py b/src/module/rss/rss_analyser.py index 1bcbc1f8..552ca884 100644 --- a/src/module/rss/rss_analyser.py +++ b/src/module/rss/rss_analyser.py @@ -67,7 +67,7 @@ class RSSAnalyser: database.insert_list(new_data) return new_data - def run(self, rss_link: str): + def run(self, rss_link: str = settings.rss_link): logger.info("Start collecting RSS info.") try: self.rss_to_data(rss_link) diff --git a/src/module/update/__init__.py b/src/module/update/__init__.py new file mode 100644 index 00000000..e69de29b diff --git a/src/module/core/data_migration.py b/src/module/update/data_migration.py similarity index 100% rename from src/module/core/data_migration.py rename to src/module/update/data_migration.py