From 8af37a0adc7418b7b5044d65919c165faf9dd8f0 Mon Sep 17 00:00:00 2001 From: jxxghp Date: Tue, 15 Oct 2024 13:42:41 +0800 Subject: [PATCH] fix shudown --- app/api/endpoints/system.py | 6 +++--- app/chain/download.py | 10 +++++++++- app/chain/search.py | 5 +++++ app/chain/site.py | 4 +++- app/chain/subscribe.py | 10 +++++++++- app/chain/torrents.py | 6 +++++- app/chain/transfer.py | 6 +++++- app/core/config.py | 1 + app/core/module.py | 2 +- app/db/__init__.py | 7 +++++++ app/factory.py | 6 +++--- app/helper/display.py | 4 ++++ app/monitor.py | 2 ++ app/startup/module_initializer.py | 15 +++++++++++++-- app/utils/system.py | 20 ++++++++++++++++++-- 15 files changed, 88 insertions(+), 16 deletions(-) diff --git a/app/api/endpoints/system.py b/app/api/endpoints/system.py index e4872208..cf91c33a 100644 --- a/app/api/endpoints/system.py +++ b/app/api/endpoints/system.py @@ -232,7 +232,7 @@ def get_progress(process_type: str, _: schemas.TokenPayload = Depends(verify_res def event_generator(): while True: - if global_vars.is_system_stopped(): + if global_vars.is_system_stopped: break detail = progress.get(process_type) yield 'data: %s\n\n' % json.dumps(detail) @@ -281,7 +281,7 @@ def get_message(role: str = "system", _: schemas.TokenPayload = Depends(verify_r def event_generator(): while True: - if global_vars.is_system_stopped(): + if global_vars.is_system_stopped: break detail = message.get(role) yield 'data: %s\n\n' % (detail or '') @@ -312,7 +312,7 @@ def get_logging(length: int = 50, logfile: str = "moviepilot.log", for line in f.readlines()[-max(length, 50):]: yield 'data: %s\n\n' % line while True: - if global_vars.is_system_stopped(): + if global_vars.is_system_stopped: break for t in tailer.follow(open(log_path, 'r', encoding='utf-8')): yield 'data: %s\n\n' % (t or '') diff --git a/app/chain/download.py b/app/chain/download.py index 695f3d42..e75bac12 100644 --- a/app/chain/download.py +++ b/app/chain/download.py @@ -8,7 +8,7 @@ from typing import List, Optional, Tuple, Set, Dict, Union from app import schemas from app.chain import ChainBase -from app.core.config import settings +from app.core.config import settings, global_vars from app.core.context import MediaInfo, TorrentInfo, Context from app.core.event import eventmanager, Event from app.core.meta import MetaBase @@ -463,6 +463,8 @@ class DownloadChain(ChainBase): # 如果是电影,直接下载 for context in contexts: + if global_vars.is_system_stopped: + break if context.media_info.type == MediaType.MOVIE: logger.info(f"开始下载电影 {context.torrent_info.title} ...") if self.download_single(context, save_path=save_path, channel=channel, @@ -491,6 +493,8 @@ class DownloadChain(ChainBase): for need_mid, need_season in need_seasons.items(): # 循环种子 for context in contexts: + if global_vars.is_system_stopped: + break # 媒体信息 media = context.media_info # 识别元数据 @@ -598,6 +602,8 @@ class DownloadChain(ChainBase): need_episodes = list(range(start_episode, total_episode + 1)) # 循环种子 for context in contexts: + if global_vars.is_system_stopped: + break # 媒体信息 media = context.media_info # 识别元数据 @@ -664,6 +670,8 @@ class DownloadChain(ChainBase): continue # 循环种子 for context in contexts: + if global_vars.is_system_stopped: + break # 媒体信息 media = context.media_info # 识别元数据 diff --git a/app/chain/search.py b/app/chain/search.py index 31441e19..08046c6c 100644 --- a/app/chain/search.py +++ b/app/chain/search.py @@ -6,6 +6,7 @@ from typing import Dict from typing import List, Optional from app.chain import ChainBase +from app.core.config import global_vars from app.core.context import Context from app.core.context import MediaInfo, TorrentInfo from app.core.event import eventmanager, Event @@ -210,6 +211,8 @@ class SearchChain(ChainBase): logger.info(f"开始匹配结果 标题:{mediainfo.title},原标题:{mediainfo.original_title},别名:{mediainfo.names}") self.progress.update(value=51, text=f'开始匹配,总 {_total} 个资源 ...', key=ProgressKey.Search) for torrent in torrents: + if global_vars.is_system_stopped: + break _count += 1 self.progress.update(value=(_count / _total) * 96, text=f'正在匹配 {torrent.site_name},已完成 {_count} / {_total} ...', @@ -333,6 +336,8 @@ class SearchChain(ChainBase): # 结果集 results = [] for future in as_completed(all_task): + if global_vars.is_system_stopped: + break finish_count += 1 result = future.result() if result: diff --git a/app/chain/site.py b/app/chain/site.py index 48fd6fa2..cf6d97f4 100644 --- a/app/chain/site.py +++ b/app/chain/site.py @@ -9,7 +9,7 @@ from lxml import etree from ruamel.yaml import CommentedMap from app.chain import ChainBase -from app.core.config import settings +from app.core.config import settings, global_vars from app.core.event import eventmanager, Event, EventManager from app.db.models.site import Site from app.db.site_oper import SiteOper @@ -74,6 +74,8 @@ class SiteChain(ChainBase): """ sites = self.siteshelper.get_indexers() for site in sites: + if global_vars.is_system_stopped: + break if site.get("is_active"): self.refresh_userdata(site) diff --git a/app/chain/subscribe.py b/app/chain/subscribe.py index c31500f7..7276998b 100644 --- a/app/chain/subscribe.py +++ b/app/chain/subscribe.py @@ -10,7 +10,7 @@ from app.chain.media import MediaChain from app.chain.search import SearchChain from app.chain.tmdb import TmdbChain from app.chain.torrents import TorrentsChain -from app.core.config import settings +from app.core.config import settings, global_vars from app.core.context import TorrentInfo, Context, MediaInfo from app.core.event import eventmanager, Event, EventManager from app.core.meta import MetaBase @@ -242,6 +242,8 @@ class SubscribeChain(ChainBase): subscribes = self.subscribeoper.list(state) # 遍历订阅 for subscribe in subscribes: + if global_vars.is_system_stopped: + break mediakey = subscribe.tmdbid or subscribe.doubanid custom_word_list = subscribe.custom_words.split("\n") if subscribe.custom_words else None # 校验当前时间减订阅创建时间是否大于1分钟,否则跳过先,留出编辑订阅的时间 @@ -530,6 +532,8 @@ class SubscribeChain(ChainBase): subscribes = self.subscribeoper.list('R') # 遍历订阅 for subscribe in subscribes: + if global_vars.is_system_stopped: + break logger.info(f'开始匹配订阅,标题:{subscribe.name} ...') mediakey = subscribe.tmdbid or subscribe.doubanid # 生成元数据 @@ -606,6 +610,8 @@ class SubscribeChain(ChainBase): # 遍历缓存种子 _match_context = [] for domain, contexts in torrents.items(): + if global_vars.is_system_stopped: + break if domains and domain not in domains: continue logger.debug(f'开始匹配站点:{domain},共缓存了 {len(contexts)} 个种子...') @@ -776,6 +782,8 @@ class SubscribeChain(ChainBase): return # 遍历订阅 for subscribe in subscribes: + if global_vars.is_system_stopped: + break logger.info(f'开始更新订阅元数据:{subscribe.name} ...') # 生成元数据 meta = MetaInfo(subscribe.name) diff --git a/app/chain/torrents.py b/app/chain/torrents.py index 84ad90d8..a2b5c9db 100644 --- a/app/chain/torrents.py +++ b/app/chain/torrents.py @@ -6,7 +6,7 @@ from cachetools import cached, TTLCache from app.chain import ChainBase from app.chain.media import MediaChain -from app.core.config import settings +from app.core.config import settings, global_vars from app.core.context import TorrentInfo, Context, MediaInfo from app.core.metainfo import MetaInfo from app.db.site_oper import SiteOper @@ -158,6 +158,8 @@ class TorrentsChain(ChainBase, metaclass=Singleton): domains = [] # 遍历站点缓存资源 for indexer in indexers: + if global_vars.is_system_stopped: + break # 未开启的站点不刷新 if sites and indexer.get("id") not in sites: continue @@ -185,6 +187,8 @@ class TorrentsChain(ChainBase, metaclass=Singleton): logger.info(f'{indexer.get("name")} 没有新种子') continue for torrent in torrents: + if global_vars.is_system_stopped: + break logger.info(f'处理资源:{torrent.title} ...') # 识别 meta = MetaInfo(title=torrent.title, subtitle=torrent.description) diff --git a/app/chain/transfer.py b/app/chain/transfer.py index 701e6851..a129f1cc 100644 --- a/app/chain/transfer.py +++ b/app/chain/transfer.py @@ -7,7 +7,7 @@ from app.chain import ChainBase from app.chain.media import MediaChain from app.chain.storage import StorageChain from app.chain.tmdb import TmdbChain -from app.core.config import settings +from app.core.config import settings, global_vars from app.core.context import MediaInfo from app.core.meta import MetaBase from app.core.metainfo import MetaInfoPath @@ -84,6 +84,8 @@ class TransferChain(ChainBase): logger.info(f"获取到 {len(torrents)} 个已完成的下载任务") for torrent in torrents: + if global_vars.is_system_stopped: + break # 文件路径 file_path = torrent.path if not file_path.exists(): @@ -243,6 +245,8 @@ class TransferChain(ChainBase): # 整理所有文件 for file_item in file_items: + if global_vars.is_system_stopped: + break file_path = Path(file_item.path) # 回收站及隐藏的文件不处理 if file_item.path.find('/@Recycle/') != -1 \ diff --git a/app/core/config.py b/app/core/config.py index 445e71e5..a9cffa29 100644 --- a/app/core/config.py +++ b/app/core/config.py @@ -510,6 +510,7 @@ class GlobalVar(object): """ self.STOP_EVENT.set() + @property def is_system_stopped(self): """ 是否停止 diff --git a/app/core/module.py b/app/core/module.py index ea3cd949..27b9831c 100644 --- a/app/core/module.py +++ b/app/core/module.py @@ -61,7 +61,7 @@ class ModuleManager(metaclass=Singleton): logger.info(f"Moudle Stoped:{module_id}") except Exception as err: logger.error(f"Stop Moudle Error:{module_id},{str(err)} - {traceback.format_exc()}", exc_info=True) - logger.info("模块停止完成") + logger.info("所有模块停止完成") def reload(self): """ diff --git a/app/db/__init__.py b/app/db/__init__.py index 2c8f9be9..0fdb0195 100644 --- a/app/db/__init__.py +++ b/app/db/__init__.py @@ -41,6 +41,13 @@ def get_db() -> Generator: db.close() +def close_database(): + """ + 关闭所有数据库连接 + """ + Engine.dispose() + + def get_args_db(args: tuple, kwargs: dict) -> Optional[Session]: """ 从参数中获取数据库Session对象 diff --git a/app/factory.py b/app/factory.py index 78d43546..c2d20ec6 100644 --- a/app/factory.py +++ b/app/factory.py @@ -9,14 +9,14 @@ def create_app() -> FastAPI: """ 创建并配置 FastAPI 应用实例。 """ - app = FastAPI( + _app = FastAPI( title=settings.PROJECT_NAME, openapi_url=f"{settings.API_V1_STR}/openapi.json", lifespan=lifespan ) # 配置 CORS 中间件 - app.add_middleware( + _app.add_middleware( CORSMiddleware, allow_origins=settings.ALLOWED_HOSTS, allow_credentials=True, @@ -24,7 +24,7 @@ def create_app() -> FastAPI: allow_headers=["*"], ) - return app + return _app # 创建 FastAPI 应用实例 diff --git a/app/helper/display.py b/app/helper/display.py index 21594543..c1056c1c 100644 --- a/app/helper/display.py +++ b/app/helper/display.py @@ -6,6 +6,7 @@ from app.utils.system import SystemUtils import os + class DisplayHelper(metaclass=Singleton): _display: Display = None @@ -20,4 +21,7 @@ class DisplayHelper(metaclass=Singleton): def stop(self): if self._display: + logger.info("正在停止虚拟显示...") self._display.stop() + logger.info("虚拟显示已停止") + diff --git a/app/monitor.py b/app/monitor.py index e7e39212..cdaafff0 100644 --- a/app/monitor.py +++ b/app/monitor.py @@ -463,8 +463,10 @@ class Monitor(metaclass=Singleton): if self._observers: for observer in self._observers: try: + logger.info(f"正在停止目录监控服务:{observer}...") observer.stop() observer.join() + logger.info(f"{observer} 目录监控已停止") except Exception as e: logger.error(f"停止目录监控服务出现了错误:{e}") self._observers = [] diff --git a/app/startup/module_initializer.py b/app/startup/module_initializer.py index 608f76b0..08599426 100644 --- a/app/startup/module_initializer.py +++ b/app/startup/module_initializer.py @@ -26,6 +26,7 @@ from app.scheduler import Scheduler from app.monitor import Monitor from app.command import Command, CommandChian from app.schemas import Notification, NotificationType +from app.db import close_database def start_frontend(): @@ -63,6 +64,14 @@ def stop_frontend(): subprocess.Popen(f"taskkill /f /im nginx.exe", shell=True) +def clear_temp(): + """ + 清理临时目录中3天前的文件 + """ + # 清理3天前的文件 + SystemUtils.clear(settings.TEMP_PATH, days=3) + + def check_auth(): """ 检查认证状态 @@ -97,7 +106,7 @@ def singal_handle(): signal.signal(signal.SIGINT, stop_event) -def shutdown_modules(app: FastAPI): +def shutdown_modules(_: FastAPI): """ 服务关闭 """ @@ -116,11 +125,13 @@ def shutdown_modules(app: FastAPI): Monitor().stop() # 停止线程池 ThreadHelper().shutdown() + # 停止数据库连接 + close_database() # 停止前端服务 stop_frontend() -def start_modules(app: FastAPI): +def start_modules(_: FastAPI): """ 启动模块 """ diff --git a/app/utils/system.py b/app/utils/system.py index 95f76538..19923058 100644 --- a/app/utils/system.py +++ b/app/utils/system.py @@ -163,7 +163,8 @@ class SystemUtils: return -1, str(err) @staticmethod - def list_files(directory: Path, extensions: list, min_filesize: int = 0, recursive: bool = True) -> List[Path]: + def list_files(directory: Path, extensions: list = None, + min_filesize: int = 0, recursive: bool = True) -> List[Path]: """ 获取目录下所有指定扩展名的文件(包括子目录) :param directory: 指定的父目录 @@ -186,7 +187,10 @@ class SystemUtils: min_filesize = 0 files = [] - pattern = r".*(" + "|".join(extensions) + ")$" + if extensions: + pattern = r".*(" + "|".join(extensions) + ")$" + else: + pattern = r".*" # 遍历目录及子目录 for matched_glob in glob(str(directory / '**'), recursive=recursive, include_hidden=True): @@ -529,3 +533,15 @@ class SystemUtils: 获取配置路径 """ return SystemUtils.get_config_path() / "app.env" + + @staticmethod + def clear(temp_path: Path, days: int): + """ + 清理临时目录中指定天数前的文件 + """ + if not temp_path.exists(): + return + for file in temp_path.glob('*'): + if file.is_file() \ + and (datetime.datetime.now() - datetime.datetime.fromtimestamp(file.stat().st_mtime)).days > days: + file.unlink()