diff --git a/app/chain/download.py b/app/chain/download.py index 18672fb0..04855238 100644 --- a/app/chain/download.py +++ b/app/chain/download.py @@ -292,6 +292,10 @@ class DownloadChain(ChainBase): # 登记下载记录 downloadhis = DownloadHistoryOper() + # 获取应用的识别词(如果有) + custom_words_str = None + if hasattr(_meta, 'apply_words') and _meta.apply_words: + custom_words_str = '\n'.join(_meta.apply_words) downloadhis.add( path=download_path.as_posix(), type=_media.type.value, @@ -315,6 +319,7 @@ class DownloadChain(ChainBase): date=time.strftime("%Y-%m-%d %H:%M:%S", time.localtime()), media_category=_media.category, episode_group=_media.episode_group, + custom_words=custom_words_str, note={"source": source} ) diff --git a/app/chain/transfer.py b/app/chain/transfer.py index 5ec7919a..72a83f22 100755 --- a/app/chain/transfer.py +++ b/app/chain/transfer.py @@ -1080,9 +1080,26 @@ class TransferChain(ChainBase, metaclass=Singleton): err_msgs.append(f"{file_item.name} 已整理过") continue + # 提前获取下载历史,以便获取自定义识别词 + download_history = None + downloadhis = DownloadHistoryOper() + if bluray_dir: + # 蓝光原盘,按目录名查询 + download_history = downloadhis.get_by_path(file_path.as_posix()) + else: + # 按文件全路径查询 + download_file = downloadhis.get_file_by_fullpath(file_path.as_posix()) + if download_file: + download_history = downloadhis.get_by_hash(download_file.download_hash) + + # 获取自定义识别词 + custom_words_list = None + if download_history and download_history.custom_words: + custom_words_list = download_history.custom_words.split('\n') + if not meta: - # 文件元数据 - file_meta = MetaInfoPath(file_path) + # 文件元数据(传入自定义识别词) + file_meta = MetaInfoPath(file_path, custom_words=custom_words_list) else: file_meta = meta @@ -1108,18 +1125,6 @@ class TransferChain(ChainBase, metaclass=Singleton): if end_ep is not None: file_meta.end_episode = end_ep - # 根据父路径获取下载历史 - download_history = None - downloadhis = DownloadHistoryOper() - if bluray_dir: - # 蓝光原盘,按目录名查询 - download_history = downloadhis.get_by_path(file_path.as_posix()) - else: - # 按文件全路径查询 - download_file = downloadhis.get_file_by_fullpath(file_path.as_posix()) - if download_file: - download_history = downloadhis.get_by_hash(download_file.download_hash) - # 获取下载Hash if download_history and (not downloader or not download_hash): downloader = download_history.downloader diff --git a/app/core/metainfo.py b/app/core/metainfo.py index 0074db96..ad4c3985 100644 --- a/app/core/metainfo.py +++ b/app/core/metainfo.py @@ -62,20 +62,21 @@ def MetaInfo(title: str, subtitle: Optional[str] = None, custom_words: List[str] return meta -def MetaInfoPath(path: Path) -> MetaBase: +def MetaInfoPath(path: Path, custom_words: List[str] = None) -> MetaBase: """ 根据路径识别元数据 :param path: 路径 + :param custom_words: 自定义识别词列表 """ # 文件元数据,不包含后缀 - file_meta = MetaInfo(title=path.name) + file_meta = MetaInfo(title=path.name, custom_words=custom_words) # 上级目录元数据 - dir_meta = MetaInfo(title=path.parent.name) + dir_meta = MetaInfo(title=path.parent.name, custom_words=custom_words) if file_meta.type == MediaType.TV or dir_meta.type != MediaType.TV: # 合并元数据 file_meta.merge(dir_meta) # 上上级目录元数据 - root_meta = MetaInfo(title=path.parent.parent.name) + root_meta = MetaInfo(title=path.parent.parent.name, custom_words=custom_words) if file_meta.type == MediaType.TV or root_meta.type != MediaType.TV: # 合并元数据 file_meta.merge(root_meta) diff --git a/app/db/models/downloadhistory.py b/app/db/models/downloadhistory.py index 11d00294..371eae17 100644 --- a/app/db/models/downloadhistory.py +++ b/app/db/models/downloadhistory.py @@ -55,6 +55,8 @@ class DownloadHistory(Base): media_category = Column(String) # 剧集组 episode_group = Column(String) + # 自定义识别词(用于整理时应用) + custom_words = Column(String) @classmethod @db_query diff --git a/database/versions/58edfac72c32_2_2_3.py b/database/versions/58edfac72c32_2_2_3.py new file mode 100644 index 00000000..de44b26f --- /dev/null +++ b/database/versions/58edfac72c32_2_2_3.py @@ -0,0 +1,30 @@ +"""2.2.3 +添加 downloadhistory.custom_words 字段,用于整理时应用订阅识别词 + +Revision ID: 58edfac72c32 +Revises: 41ef1dd7467c +Create Date: 2026-01-19 +""" +from alembic import op +import sqlalchemy as sa + +# revision identifiers, used by Alembic. +revision = "58edfac72c32" +down_revision = "41ef1dd7467c" +branch_labels = None +depends_on = None + + +def upgrade() -> None: + conn = op.get_bind() + inspector = sa.inspect(conn) + + # 检查并添加 downloadhistory.custom_words + dh_columns = inspector.get_columns('downloadhistory') + if not any(c['name'] == 'custom_words' for c in dh_columns): + op.add_column('downloadhistory', sa.Column('custom_words', sa.String, nullable=True)) + + +def downgrade() -> None: + # 降级时删除字段 + op.drop_column('downloadhistory', 'custom_words') diff --git a/tests/run.py b/tests/run.py index 40d2c79f..4872a30b 100644 --- a/tests/run.py +++ b/tests/run.py @@ -13,6 +13,12 @@ if __name__ == '__main__': suite.addTest(MetaInfoTest('test_emby_format_ids')) suite.addTest(ObjectUtilsTest('test_check_method')) + # 测试自定义识别词功能 + suite.addTest(MetaInfoTest('test_metainfopath_with_custom_words')) + suite.addTest(MetaInfoTest('test_metainfopath_without_custom_words')) + suite.addTest(MetaInfoTest('test_metainfopath_with_empty_custom_words')) + suite.addTest(MetaInfoTest('test_custom_words_apply_words_recording')) + # 测试蓝光目录识别 suite.addTest(BluRayTest()) diff --git a/tests/test_metainfo.py b/tests/test_metainfo.py index 6253053b..d976bd1b 100644 --- a/tests/test_metainfo.py +++ b/tests/test_metainfo.py @@ -61,3 +61,38 @@ class MetaInfoTest(TestCase): meta = MetaInfoPath(Path(path_str)) self.assertEqual(meta.tmdbid, expected_tmdbid, f"路径 {path_str} 期望的tmdbid为 {expected_tmdbid},实际识别为 {meta.tmdbid}") + + def test_metainfopath_with_custom_words(self): + """测试 MetaInfoPath 使用自定义识别词""" + # 测试替换词:将"测试替换"替换为空 + custom_words = ["测试替换 => "] + path = Path("/movies/电影测试替换名称 (2024)/movie.mkv") + meta = MetaInfoPath(path, custom_words=custom_words) + # 验证替换生效:cn_name 不应包含"测试替换" + if meta.cn_name: + self.assertNotIn("测试替换", meta.cn_name) + + def test_metainfopath_without_custom_words(self): + """测试 MetaInfoPath 不传入自定义识别词""" + path = Path("/movies/Normal Movie (2024)/movie.mkv") + meta = MetaInfoPath(path) + # 验证正常识别,不报错 + self.assertIsNotNone(meta) + + def test_metainfopath_with_empty_custom_words(self): + """测试 MetaInfoPath 传入空的自定义识别词""" + path = Path("/movies/Test Movie (2024)/movie.mkv") + meta = MetaInfoPath(path, custom_words=[]) + # 验证不报错,正常识别 + self.assertIsNotNone(meta) + + def test_custom_words_apply_words_recording(self): + """测试 apply_words 记录功能""" + custom_words = ["替换词 => 新词"] + title = "电影替换词.2024.mkv" + meta = MetaInfo(title=title, custom_words=custom_words) + # 验证 apply_words 属性存在 + self.assertTrue(hasattr(meta, 'apply_words')) + # 如果替换词被应用,应该记录在 apply_words 中 + if meta.apply_words: + self.assertIn("替换词 => 新词", meta.apply_words)