mirror of
https://github.com/jxxghp/MoviePilot.git
synced 2026-10-31 20:34:48 +08:00
fix(music): 识别碟号后缀目录,修复多碟专辑音轨键塌陷
整专下载完成度按 `["<disc>", "<track>"]` 键集累计,而碟片识别只接受目录名整体 为 `CD1`/`Disc 2`。把碟号写在专辑目录名末尾的资源(`陈奕迅 - 十年经典 CD1`) 解析不到 disc_number,音轨键生成回退到 `disc_number or 1`,两张碟的同曲序互相 覆盖,键集直接减半(30 首只记到 15 个键),订阅永远判定未完成。 只补碟号,不改变专辑根推断:该目录仍按专辑目录解析,`parse_disc_dir` 的 11 处 结构性调用语义不变,入库目标目录(`Disc 1` 布局)也不受影响。
This commit is contained in:
@@ -468,6 +468,11 @@ _MUSIC_DISC_DIR_RE = re.compile(
|
||||
r"^\s*(?:cd|disc|disk)\s*(?P<num>\d{1,2})\s*$",
|
||||
re.IGNORECASE,
|
||||
)
|
||||
# 碟号后缀在目录名末尾的碟片目录:陈奕迅 - 十年经典 CD1、专辑名 Disc 2
|
||||
_MUSIC_DISC_DIR_SUFFIX_RE = re.compile(
|
||||
r"^(?:.*[\s\-–—_.,、/\\])?(?:cd|disc|disk)\s*(?P<num>\d{1,2})\s*$",
|
||||
re.IGNORECASE,
|
||||
)
|
||||
# 目录名中的年份:(2004)、[2004]
|
||||
_MUSIC_DIR_YEAR_RE = re.compile(r"[(\[]\s*(?P<year>(?:19|20)\d{2})\s*[)\]]")
|
||||
_MUSIC_DIR_PREFIX_YEAR_RE = re.compile(
|
||||
@@ -2174,6 +2179,14 @@ class MetaMusic(MetaBase):
|
||||
match = _MUSIC_DISC_DIR_RE.match(str(name or "").strip())
|
||||
return int(match.group("num")) if match and int(match.group("num")) > 0 else None
|
||||
|
||||
@classmethod
|
||||
def parse_disc_dir_suffix(cls, name: str) -> Optional[int]:
|
||||
"""
|
||||
识别把碟号后缀在目录名末尾的碟片目录并返回碟号,如 `陈奕迅 - 十年经典 CD1`。
|
||||
"""
|
||||
match = _MUSIC_DISC_DIR_SUFFIX_RE.match(str(name or "").strip())
|
||||
return int(match.group("num")) if match and int(match.group("num")) > 0 else None
|
||||
|
||||
@staticmethod
|
||||
def _normalize_album_year(value: str) -> str:
|
||||
"""
|
||||
@@ -2292,6 +2305,10 @@ class MetaMusic(MetaBase):
|
||||
self.disc_number = parent_disc
|
||||
self.field_sources["disc_number"] = "directory"
|
||||
album_dir = parent.parent
|
||||
elif self.disc_number is None and (suffix_disc := self.parse_disc_dir_suffix(parent.name)) is not None:
|
||||
# 碟号写进专辑目录名末尾时只补碟号,该目录仍是专辑目录,不能上移专辑根。
|
||||
self.disc_number = suffix_disc
|
||||
self.field_sources["disc_number"] = "directory"
|
||||
dir_info = self.parse_album_dir(album_dir.name)
|
||||
if dir_info:
|
||||
# 文件已明确歌手时,纯专辑名目录也可补足检索线索;通用监控根目录仍须排除。
|
||||
|
||||
@@ -605,6 +605,41 @@ def test_parse_disc_dir():
|
||||
assert MetaMusic.parse_disc_dir("无损音乐") is None
|
||||
|
||||
|
||||
def test_parse_disc_dir_suffix():
|
||||
"""
|
||||
碟号后缀在专辑目录名末尾时识别碟号,且不得误读非碟片后缀的目录名。
|
||||
"""
|
||||
assert MetaMusic.parse_disc_dir_suffix("陈奕迅 - 十年经典 CD1") == 1
|
||||
assert MetaMusic.parse_disc_dir_suffix("周杰伦 哎哟不错哦 Disc 2") == 2
|
||||
assert MetaMusic.parse_disc_dir_suffix("陈奕迅 DUO 演唱会 2CD") is None
|
||||
assert MetaMusic.parse_disc_dir_suffix("2CD1") is None
|
||||
assert MetaMusic.parse_disc_dir_suffix("某某专辑 CD100") is None
|
||||
assert MetaMusic.parse_disc_dir_suffix("Discipline 1") is None
|
||||
assert MetaMusic.parse_disc_dir_suffix("The Best disco") is None
|
||||
|
||||
|
||||
def test_apply_path_context_reads_suffix_disc_without_moving_album_root():
|
||||
"""
|
||||
碟号后缀目录只补碟号,专辑线索仍来自该目录本身,多碟同曲序不会互相覆盖。
|
||||
"""
|
||||
disc_two = MetaMusic(
|
||||
org_string="01 你的背包.flac",
|
||||
title="01 你的背包",
|
||||
).apply_path_context(Path("陈奕迅 - 十年经典 CD2/01 你的背包.flac"))
|
||||
album_root = MetaMusic(
|
||||
org_string="01 你的背包.flac",
|
||||
title="01 你的背包",
|
||||
).apply_path_context(Path("陈奕迅 - 十年经典/CD2/01 你的背包.flac"))
|
||||
|
||||
assert disc_two.disc_number == 2
|
||||
assert disc_two.track_number == 1
|
||||
assert disc_two.field_sources["disc_number"] == "directory"
|
||||
assert disc_two.album == "十年经典 CD2"
|
||||
# 独立碟片子目录仍把专辑根上移一级,两种布局的碟号证据都必须可用。
|
||||
assert album_root.disc_number == 2
|
||||
assert album_root.album == "十年经典"
|
||||
|
||||
|
||||
def test_parse_album_dir_extracts_artist_album_year():
|
||||
"""
|
||||
专辑目录名应提取歌手、专辑、年份和音质描述。
|
||||
|
||||
@@ -139,6 +139,36 @@ def test_album_resource_dedupes_same_track_in_different_formats():
|
||||
assert context.confirmed_full_coverage is False
|
||||
|
||||
|
||||
def test_album_resource_keeps_suffix_disc_directory_tracks_separate():
|
||||
"""
|
||||
碟号后缀在顶层目录名中的多碟专辑,两盘同曲序不能压成同一音轨键。
|
||||
"""
|
||||
context = Context(media_info=_album_info(total_tracks=6))
|
||||
|
||||
DownloadChain._record_music_album_track_keys(
|
||||
context,
|
||||
[
|
||||
"陈奕迅 - 十年经典 CD1/01 K歌之王.flac",
|
||||
"陈奕迅 - 十年经典 CD1/02 富士山下.flac",
|
||||
"陈奕迅 - 十年经典 CD1/03 你的背包.flac",
|
||||
"陈奕迅 - 十年经典 CD2/01 你的背包.flac",
|
||||
"陈奕迅 - 十年经典 CD2/02 Shall We Talk.flac",
|
||||
"陈奕迅 - 十年经典 CD2/03 不如不见.flac",
|
||||
],
|
||||
)
|
||||
|
||||
assert context.music_track_keys == ["[1,1]", "[1,2]", "[1,3]", "[2,1]", "[2,2]", "[2,3]"]
|
||||
|
||||
# 独立碟片子目录的既有布局必须保持同样的键集,修复不能改变已正确的解析。
|
||||
nested = Context(media_info=_album_info(total_tracks=6))
|
||||
DownloadChain._record_music_album_track_keys(
|
||||
nested,
|
||||
[f"十年经典/CD{disc}/{track:02d} 曲目.flac" for disc in (1, 2) for track in range(1, 4)],
|
||||
)
|
||||
assert nested.music_track_keys == context.music_track_keys
|
||||
assert context.confirmed_full_coverage is False
|
||||
|
||||
|
||||
def test_download_single_prepares_partial_album_for_client_submission():
|
||||
"""
|
||||
下载入口允许不完整专辑进入下载器,并把本轮音轨事实附着到上下文。
|
||||
|
||||
Reference in New Issue
Block a user