diff --git a/app/chain/transfer.py b/app/chain/transfer.py index c01dba37..2d11c789 100644 --- a/app/chain/transfer.py +++ b/app/chain/transfer.py @@ -2,7 +2,7 @@ from pathlib import Path from typing import List, Optional from app.chain import _ChainBase -from app.core import MetaInfo, MediaInfo +from app.core import MetaInfo, MediaInfo, settings from app.log import logger from app.utils.types import TorrentStatus @@ -18,7 +18,7 @@ class TransferChain(_ChainBase): """ logger.info("开始执行下载器文件转移 ...") # 从下载器获取种子列表 - torrents: Optional[List[dict]] = self.run_module("list_torrents", status=TorrentStatus.COMPLETE) + torrents: Optional[List[dict]] = self.run_module("list_torrents", status=TorrentStatus.TRANSFER) if not torrents: logger.info("没有获取到已完成的下载任务") return False @@ -43,8 +43,15 @@ class TransferChain(_ChainBase): if not dest_path: logger.warn(f"{torrent.get('title')} 转移失败") continue + # 转移完成 + self.run_module("transfer_completed", hashs=torrent.get("hash")) # 刮剥 self.run_module("scrape_metadata", path=dest_path, mediainfo=mediainfo) + # 移动模式删除种子 + if settings.TRANSFER_TYPE == "move": + result = self.run_module("remove_torrents", hashs=torrent.get("hash")) + if result: + logger.info(f"移动模式删除种子成功:{torrent.get('title')} ") logger.info("下载器文件转移执行完成") return True diff --git a/app/core/config.py b/app/core/config.py index 90b227b4..d052aad7 100644 --- a/app/core/config.py +++ b/app/core/config.py @@ -91,6 +91,8 @@ class Settings(BaseSettings): TR_USER: str = None # Transmission密码 TR_PASSWORD: str = None + # 种子标签 + TORRENT_TAG: str = "MP" # 下载保存目录,容器内映射路径需要一致 DOWNLOAD_PATH: str = "/downloads" # 媒体服务器 emby/jellyfin/plex diff --git a/app/helper/sites.cp310-win_amd64.pyd b/app/helper/sites.cp310-win_amd64.pyd index 690af52b..a9c20dc1 100644 Binary files a/app/helper/sites.cp310-win_amd64.pyd and b/app/helper/sites.cp310-win_amd64.pyd differ diff --git a/app/helper/sites.cpython-310-darwin.so b/app/helper/sites.cpython-310-darwin.so index ada4e5b5..24fa06e2 100755 Binary files a/app/helper/sites.cpython-310-darwin.so and b/app/helper/sites.cpython-310-darwin.so differ diff --git a/app/helper/sites.cpython-310-x86_64-linux-gnu.so b/app/helper/sites.cpython-310-x86_64-linux-gnu.so index 6daec739..f08e0192 100644 Binary files a/app/helper/sites.cpython-310-x86_64-linux-gnu.so and b/app/helper/sites.cpython-310-x86_64-linux-gnu.so differ diff --git a/app/modules/__init__.py b/app/modules/__init__.py index 20894d37..57b3201c 100644 --- a/app/modules/__init__.py +++ b/app/modules/__init__.py @@ -157,6 +157,14 @@ class _ModuleBase(metaclass=ABCMeta): """ pass + def transfer_completed(self, hashs: Union[str, list]) -> bool: + """ + 转移完成后的处理 + :param hashs: 种子Hash + :return: 处理状态 + """ + pass + def media_exists(self, mediainfo: MediaInfo) -> Optional[dict]: """ 判断媒体文件是否存在 diff --git a/app/modules/filter/__init__.py b/app/modules/filter/__init__.py index d6399695..94838689 100644 --- a/app/modules/filter/__init__.py +++ b/app/modules/filter/__init__.py @@ -1,8 +1,6 @@ import re from typing import List, Tuple, Union, Dict, Optional -from pyparsing import ParseResults - from app.core import TorrentInfo, settings from app.modules import _ModuleBase from app.modules.filter.RuleParser import RuleParser diff --git a/app/modules/qbittorrent/__init__.py b/app/modules/qbittorrent/__init__.py index e66042db..41ce8b4a 100644 --- a/app/modules/qbittorrent/__init__.py +++ b/app/modules/qbittorrent/__init__.py @@ -30,6 +30,8 @@ class QbittorrentModule(_ModuleBase): return None, f"种子文件不存在:{torrent_path}" # 生成随机Tag tag = StringUtils.generate_random_str(10) + if settings.TORRENT_TAG: + tag = [tag, settings.TORRENT_TAG] # 如果要选择文件则先暂停 is_paused = True if episodes else False # 添加任务 @@ -75,16 +77,22 @@ class QbittorrentModule(_ModuleBase): else: return torrent_hash, "添加下载成功" + def transfer_completed(self, hashs: Union[str, list]) -> bool: + """ + 转移完成后的处理 + :param hashs: 种子Hash + :return: 处理状态 + """ + return self.qbittorrent.set_torrents_tag(ids=hashs, tag=['已整理']) + def list_torrents(self, status: TorrentStatus) -> Optional[List[dict]]: """ 获取下载器种子列表 :param status: 种子状态 :return: 下载器中符合状态的种子列表 """ - if status == TorrentStatus.COMPLETE: - torrents = self.qbittorrent.get_completed_torrents() - elif status == TorrentStatus.DOWNLOADING: - torrents = self.qbittorrent.get_downloading_torrents() + if status == TorrentStatus.TRANSFER: + torrents = self.qbittorrent.get_transfer_torrents(tag=settings.TORRENT_TAG) else: return None return torrents diff --git a/app/modules/qbittorrent/qbittorrent.py b/app/modules/qbittorrent/qbittorrent.py index 1a7e475e..8ae18038 100644 --- a/app/modules/qbittorrent/qbittorrent.py +++ b/app/modules/qbittorrent/qbittorrent.py @@ -1,9 +1,9 @@ import time from pathlib import Path -from typing import Optional, Union, Tuple +from typing import Optional, Union, Tuple, List import qbittorrentapi -from qbittorrentapi import TorrentFilesList +from qbittorrentapi import TorrentFilesList, TorrentDictionary from qbittorrentapi.client import Client from app.core import settings @@ -51,7 +51,8 @@ class Qbittorrent(metaclass=Singleton): return None def get_torrents(self, ids: Union[str, list] = None, - status: Union[str, list] = None, tag: Union[str, list] = None) -> Tuple[list, bool]: + status: Union[str, list] = None, + tag: Union[str, list] = None) -> Tuple[List[TorrentDictionary], bool]: """ 获取种子列表 return: 种子列表, 是否发生异常 @@ -73,14 +74,14 @@ class Qbittorrent(metaclass=Singleton): break if include_flag: results.append(torrent) - return results or [], False + return results, False return torrents or [], False except Exception as err: logger.error(f"获取种子列表出错:{err}") return [], True def get_completed_torrents(self, ids: Union[str, list] = None, - tag: Union[str, list] = None) -> Optional[list]: + tag: Union[str, list] = None) -> Optional[List[TorrentDictionary]]: """ 获取已完成的种子 return: 种子列表, 如发生异常则返回None @@ -91,7 +92,7 @@ class Qbittorrent(metaclass=Singleton): return None if error else torrents or [] def get_downloading_torrents(self, ids: Union[str, list] = None, - tag: Union[str, list] = None) -> Optional[list]: + tag: Union[str, list] = None) -> Optional[List[TorrentDictionary]]: """ 获取正在下载的种子 return: 种子列表, 如发生异常则返回None @@ -116,7 +117,7 @@ class Qbittorrent(metaclass=Singleton): logger.error(f"移除种子Tag出错:{err}") return False - def set_torrents_status(self, ids: Union[str, list]): + def set_torrents_tag(self, ids: Union[str, list], tag: list): """ 设置种子状态为已整理,以及是否强制做种 """ @@ -124,7 +125,7 @@ class Qbittorrent(metaclass=Singleton): return try: # 打标签 - self.qbc.torrents_add_tags(tags="已整理", torrent_hashes=ids) + self.qbc.torrents_add_tags(tags=tag, torrent_hashes=ids) except Exception as err: logger.error(f"设置种子Tag出错:{err}") @@ -137,7 +138,7 @@ class Qbittorrent(metaclass=Singleton): except Exception as err: logger.error(f"设置强制作种出错:{err}") - def get_transfer_task(self, tag: Union[str, list] = None) -> Optional[list]: + def get_transfer_torrents(self, tag: Union[str, list] = None) -> Optional[List[dict]]: """ 获取下载文件转移任务种子 """ @@ -166,8 +167,10 @@ class Qbittorrent(metaclass=Singleton): else: trans_name = torrent.get('name') trans_tasks.append({ + 'title': torrent.get('name'), 'path': Path(settings.DOWNLOAD_PATH) / trans_name, - 'id': torrent.get('hash') + 'id': torrent.get('hash'), + 'tags': torrent.get('tags') }) return trans_tasks diff --git a/app/modules/transmission/__init__.py b/app/modules/transmission/__init__.py index c8a68ad7..0abc8bb8 100644 --- a/app/modules/transmission/__init__.py +++ b/app/modules/transmission/__init__.py @@ -28,10 +28,16 @@ class TransmissionModule(_ModuleBase): """ # 如果要选择文件则先暂停 is_paused = True if episodes else False + # 标签 + if settings.TORRENT_TAG: + labels = [settings.TORRENT_TAG] + else: + labels = None # 添加任务 torrent = self.transmission.add_torrent(content=torrent_path.read_bytes(), download_dir=settings.DOWNLOAD_PATH, is_paused=is_paused, + labels=labels, cookie=cookie) if not torrent: return None, f"添加种子任务失败:{torrent_path}" @@ -70,16 +76,22 @@ class TransmissionModule(_ModuleBase): else: return torrent_hash, "添加下载任务成功" + def transfer_completed(self, hashs: Union[str, list]) -> bool: + """ + 转移完成后的处理 + :param hashs: 种子Hash + :return: 处理状态 + """ + return self.transmission.set_torrent_tag(ids=hashs, tag=['已整理']) + def list_torrents(self, status: TorrentStatus) -> Optional[List[dict]]: """ 获取下载器种子列表 :param status: 种子状态 :return: 下载器中符合状态的种子列表 """ - if status == TorrentStatus.COMPLETE: - torrents = self.transmission.get_completed_torrents() - elif status == TorrentStatus.DOWNLOADING: - torrents = self.transmission.get_completed_torrents() + if status == TorrentStatus.TRANSFER: + torrents = self.transmission.get_transfer_torrents(tag=settings.TORRENT_TAG) else: return None return torrents diff --git a/app/modules/transmission/transmission.py b/app/modules/transmission/transmission.py index 73d78ed6..97811a9c 100644 --- a/app/modules/transmission/transmission.py +++ b/app/modules/transmission/transmission.py @@ -50,7 +50,7 @@ class Transmission(metaclass=Singleton): return None def get_torrents(self, ids: Union[str, list] = None, status: Union[str, list] = None, - tag: Union[str, list] = None) -> Tuple[list, bool]: + tag: Union[str, list] = None) -> Tuple[List[Torrent], bool]: """ 获取种子列表 返回结果 种子列表, 是否有错误 @@ -81,7 +81,8 @@ class Transmission(metaclass=Singleton): ret_torrents.append(torrent) return ret_torrents, False - def get_completed_torrents(self, ids: Union[str, list] = None, tag: Union[str, list] = None) -> Optional[list]: + def get_completed_torrents(self, ids: Union[str, list] = None, + tag: Union[str, list] = None) -> Optional[List[Torrent]]: """ 获取已完成的种子列表 return 种子列表, 发生错误时返回None @@ -96,7 +97,7 @@ class Transmission(metaclass=Singleton): return None def get_downloading_torrents(self, ids: Union[str, list] = None, - tag: Union[str, list] = None) -> Optional[list]: + tag: Union[str, list] = None) -> Optional[List[Torrent]]: """ 获取正在下载的种子列表 return 种子列表, 发生错误时返回None @@ -112,30 +113,7 @@ class Transmission(metaclass=Singleton): logger.error(f"获取正在下载的种子列表出错:{err}") return None - def set_torrents_status(self, ids: Union[str, list], - tags: Union[str, list] = None) -> bool: - """ - 设置种子为已整理状态 - """ - if not self.trc: - return False - # 合成标签 - if tags: - if not isinstance(tags, list): - tags = [tags, "已整理"] - else: - tags.append("已整理") - else: - tags = ["已整理"] - # 打标签 - try: - self.trc.change_torrent(labels=tags, ids=ids) - return True - except Exception as err: - logger.error(f"设置种子为已整理状态出错:{err}") - return False - - def set_torrent_tag(self, ids: str, tag: Union[str, list]) -> bool: + def set_torrent_tag(self, ids: str, tag: list) -> bool: """ 设置种子标签 """ @@ -148,7 +126,7 @@ class Transmission(metaclass=Singleton): logger.error(f"设置种子标签出错:{err}") return False - def get_transfer_task(self, tag: Union[str, list] = None) -> List[dict]: + def get_transfer_torrents(self, tag: Union[str, list] = None) -> List[dict]: """ 获取下载文件转移任务种子 """ @@ -174,6 +152,7 @@ class Transmission(metaclass=Singleton): logger.debug(f"未获取到 {torrent.name} 下载保存路径") continue trans_tasks.append({ + 'title': torrent.name, 'path': Path(settings.DOWNLOAD_PATH) / torrent.name, 'id': torrent.hashString, 'tags': torrent.labels @@ -183,12 +162,14 @@ class Transmission(metaclass=Singleton): def add_torrent(self, content: Union[str, bytes], is_paused: bool = False, download_dir: str = None, + labels=None, cookie=None) -> Optional[Torrent]: """ 添加下载任务 :param content: 种子urls或文件内容 :param is_paused: 添加后暂停 :param download_dir: 下载路径 + :param labels: 标签 :param cookie: 站点Cookie用于辅助下载种子 :return: Torrent """ @@ -196,6 +177,7 @@ class Transmission(metaclass=Singleton): return self.trc.add_torrent(torrent=content, download_dir=download_dir, paused=is_paused, + labels=labels, cookies=cookie) except Exception as err: logger.error(f"添加种子出错:{err}") diff --git a/app/utils/types.py b/app/utils/types.py index 09f4cd9b..0cbee166 100644 --- a/app/utils/types.py +++ b/app/utils/types.py @@ -8,8 +8,7 @@ class MediaType(Enum): class TorrentStatus(Enum): - COMPLETE = "已完成" - DOWNLOADING = "下载中" + TRANSFER = "可转移" # 可监听事件 diff --git a/tests/run.py b/tests/run.py index 4e0d2ef1..5aa52913 100644 --- a/tests/run.py +++ b/tests/run.py @@ -1,12 +1,14 @@ import unittest from tests.test_metainfo import MetaInfoTest +from tests.test_recognize import RecognizeTest if __name__ == '__main__': suite = unittest.TestSuite() # 测试名称识别 suite.addTest(MetaInfoTest('test_metainfo')) - + # 测试媒体识别 + suite.addTest(RecognizeTest('test_recognize')) # 运行测试 runner = unittest.TextTestRunner() runner.run(suite) diff --git a/tests/test_recognize.py b/tests/test_recognize.py new file mode 100644 index 00000000..a687af0d --- /dev/null +++ b/tests/test_recognize.py @@ -0,0 +1,17 @@ +# -*- coding: utf-8 -*- + +from unittest import TestCase + +from app.chain.identify import IdentifyChain + + +class RecognizeTest(TestCase): + def setUp(self) -> None: + pass + + def tearDown(self) -> None: + pass + + def test_recognize(self): + result = IdentifyChain().process(title="我和我的祖国 2019") + self.assertEqual(str(result.media_info.tmdb_id), '612845')