|
29 | 29 | from app.foundation.crypto import HashUtils |
30 | 30 |
|
31 | 31 |
|
| 32 | +# 专辑名尾部的括号年份标记;重命名模板会独立追加 `({{year}})`, |
| 33 | +# 标签或目录名中自带的尾部年份若不剥离,会生成重复年份的目录名(issue #6355) |
| 34 | +_ALBUM_TRAILING_YEAR_RE = re.compile( |
| 35 | + r"(?:[\s\u3000]*[\(\[(【]\s*(?:19|20)\d{2}\s*[\)\])】])+$" |
| 36 | +) |
| 37 | + |
| 38 | + |
32 | 39 | class AsyncMessageQueryRepository(Protocol): |
33 | 40 | """消息查询用例依赖的异步持久化端口。""" |
34 | 41 |
|
@@ -169,23 +176,32 @@ def _add_media_info( |
169 | 176 | aggregate_music_album |
170 | 177 | and mediainfo.music_type == MUSIC_ENTITY_ALBUM |
171 | 178 | ) |
| 179 | + # 专辑场景以识别结果的专辑名为标题;整专年份以识别结果为准, |
| 180 | + # 逐文件场景沿用 meta 解析年份,保证文件级年份优先。 |
| 181 | + year = ( |
| 182 | + mediainfo.year |
| 183 | + if (is_album_context and mediainfo.year) |
| 184 | + else (context.get("year") or mediainfo.year) |
| 185 | + ) |
172 | 186 | if is_album_context and mediainfo.album: |
173 | | - title = cls.__convert_invalid_characters(mediainfo.album) |
| 187 | + title = cls.__strip_album_trailing_year( |
| 188 | + cls.__convert_invalid_characters(mediainfo.album), year |
| 189 | + ) |
174 | 190 | else: |
175 | 191 | title = context.get("title") or cls.__convert_invalid_characters(mediainfo.title) |
176 | 192 | artists = context.get("artists") or [ |
177 | 193 | cls.__convert_invalid_characters(item) for item in mediainfo.artists |
178 | 194 | ] |
179 | 195 | artist = context.get("artist") or cls.__convert_invalid_characters(mediainfo.artist) |
180 | | - album = context.get("album") or cls.__convert_invalid_characters(mediainfo.album) |
| 196 | + # 标签/目录名自带的尾部年份会被重命名模板的 `({{year}})` 再次追加, |
| 197 | + # 统一剥离避免生成 "专辑 (2018) (2018)" 这类重复年份目录(issue #6355) |
| 198 | + album = cls.__strip_album_trailing_year( |
| 199 | + context.get("album") or cls.__convert_invalid_characters(mediainfo.album), |
| 200 | + year, |
| 201 | + ) |
181 | 202 | album_artist = context.get("album_artist") or cls.__convert_invalid_characters( |
182 | 203 | mediainfo.album_artist |
183 | 204 | ) |
184 | | - year = ( |
185 | | - mediainfo.year |
186 | | - if (is_album_context and mediainfo.year) |
187 | | - else (context.get("year") or mediainfo.year) |
188 | | - ) |
189 | 205 | disc_number = context.get("disc_number") or mediainfo.disc_number |
190 | 206 | track_number = ( |
191 | 207 | None |
@@ -305,7 +321,10 @@ def _add_episode_details( |
305 | 321 | "title": cls.__convert_invalid_characters(meta.title), |
306 | 322 | "artists": [cls.__convert_invalid_characters(item) for item in meta.artists], |
307 | 323 | "artist": cls.__convert_invalid_characters(meta.artist), |
308 | | - "album": cls.__convert_invalid_characters(meta.album), |
| 324 | + # 标签专辑名常自带尾部年份,与模板独立追加的年份去重(issue #6355) |
| 325 | + "album": cls.__strip_album_trailing_year( |
| 326 | + cls.__convert_invalid_characters(meta.album), meta.year |
| 327 | + ), |
309 | 328 | "album_artist": cls.__convert_invalid_characters(meta.album_artist), |
310 | 329 | "year": meta.year, |
311 | 330 | "disc_number": meta.disc_number, |
@@ -513,6 +532,21 @@ def __convert_invalid_characters(filename: str): |
513 | 532 | filename = filename.replace(char, char.translate(translation_table)) |
514 | 533 | return filename |
515 | 534 |
|
| 535 | + @staticmethod |
| 536 | + def __strip_album_trailing_year( |
| 537 | + album: Optional[str], year: Optional[int] |
| 538 | + ) -> Optional[str]: |
| 539 | + """ |
| 540 | + 去除专辑名尾部的括号年份标记(如 ``欲望反光 (2018)`` -> ``欲望反光``)。 |
| 541 | +
|
| 542 | + 音频标签或下载目录常把发行年份写进专辑名,而重命名模板会独立追加 |
| 543 | + ``({{year}})``,两者叠加会生成 "专辑 (2018) (2018)" 这类重复年份目录; |
| 544 | + 仅当存在可独立渲染的年份时才剥离,避免丢失只存在于专辑名中的年份信息。 |
| 545 | + """ |
| 546 | + if not album or not year: |
| 547 | + return album |
| 548 | + return _ALBUM_TRAILING_YEAR_RE.sub("", album) or album |
| 549 | + |
516 | 550 |
|
517 | 551 | class TemplateHelper(metaclass=SingletonClass): |
518 | 552 | """ |
|
0 commit comments