diff --git a/docs/TAGGING_CONVENTIONS.md b/docs/TAGGING_CONVENTIONS.md index 5373980..c582711 100644 --- a/docs/TAGGING_CONVENTIONS.md +++ b/docs/TAGGING_CONVENTIONS.md @@ -135,7 +135,7 @@ world, Rosé will support reading from additional fields. | Release Artists | `aART` | | | Release Type | `----:com.apple.iTunes:RELEASETYPE` | `----:com.apple.iTunes:MusicBrainz Album Type` | | Release Year | `\xa9day` | | -| Original Year | `----:net.sunsetglow.rose:ORIGINALYEAR` | `----:com.apple.iTunes:ORIGINALYEAR` | +| Original Year | `----:net.sunsetglow.rose:ORIGINALDATE` | `----:com.apple.iTunes:ORIGINALDATE`, `----:com.apple.iTunes:ORIGINALYEAR` | | Composition Year | `----:net.sunsetglow.rose:COMPOSITIONDATE` | | | Genre | `\xa9gen` | | | Secondary Genre | `----:net.sunsetglow.rose:SECONDARYGENRE` | | diff --git a/rose/audiotags.py b/rose/audiotags.py index 3c01b07..7a23a4e 100644 --- a/rose/audiotags.py +++ b/rose/audiotags.py @@ -85,24 +85,28 @@ class UnsupportedTagValueTypeError(RoseExpectedError): class AudioTags: id: str | None release_id: str | None - title: str | None - releaseyear: int | None - compositionyear: int | None + + tracktitle: str | None tracknumber: str | None tracktotal: int | None discnumber: str | None disctotal: int | None - release: str | None + trackartists: ArtistMapping + + releasetitle: str | None + releasetype: str + releaseyear: int | None + originalyear: int | None + compositionyear: int | None genre: list[str] + secondarygenre: list[str] + descriptor: list[str] + edition: str | None label: list[str] catalognumber: str | None - releasetype: str - releaseartists: ArtistMapping - trackartists: ArtistMapping duration_sec: int - path: Path @classmethod @@ -144,17 +148,21 @@ def _get_paired_frame(x: str) -> str | None: return AudioTags( id=_get_tag(m.tags, ["TXXX:ROSEID"], first=True), release_id=_get_tag(m.tags, ["TXXX:ROSERELEASEID"], first=True), - title=_get_tag(m.tags, ["TIT2"]), + tracktitle=_get_tag(m.tags, ["TIT2"]), releaseyear=_parse_year(_get_tag(m.tags, ["TDRC", "TYER", "TDAT"])), + originalyear=_parse_year(_get_tag(m.tags, ["TDOR", "TORY"])), compositionyear=_parse_year(_get_tag(m.tags, ["TXXX:COMPOSITIONDATE"], first=True)), tracknumber=tracknumber, tracktotal=tracktotal, discnumber=discnumber, disctotal=disctotal, - release=_get_tag(m.tags, ["TALB"]), + releasetitle=_get_tag(m.tags, ["TALB"]), genre=_split_tag(_get_tag(m.tags, ["TCON"], split=True)), + secondarygenre=_split_tag(_get_tag(m.tags, ["TXXX:SECONDARYGENRE"], split=True)), + descriptor=_split_tag(_get_tag(m.tags, ["TXXX:DESCRIPTOR"], split=True)), label=_split_tag(_get_tag(m.tags, ["TPUB"], split=True)), catalognumber=_get_tag(m.tags, ["TXXX:CATALOGNUMBER"], first=True), + edition=_get_tag(m.tags, ["TXXX:EDITION"], first=True), releasetype=_normalize_rtype( _get_tag( m.tags, ["TXXX:RELEASETYPE", "TXXX:MusicBrainz Album Type"], first=True @@ -184,8 +192,18 @@ def _get_paired_frame(x: str) -> str | None: return AudioTags( id=_get_tag(m.tags, ["----:net.sunsetglow.rose:ID"]), release_id=_get_tag(m.tags, ["----:net.sunsetglow.rose:RELEASEID"]), - title=_get_tag(m.tags, ["\xa9nam"]), + tracktitle=_get_tag(m.tags, ["\xa9nam"]), releaseyear=_parse_year(_get_tag(m.tags, ["\xa9day"])), + originalyear=_parse_year( + _get_tag( + m.tags, + [ + "----:net.sunsetglow.rose:ORIGINALDATE", + "----:com.apple.iTunes:ORIGINALDATE", + "----:com.apple.iTunes:ORIGINALYEAR", + ], + ) + ), compositionyear=_parse_year( _get_tag(m.tags, ["----:net.sunsetglow.rose:COMPOSITIONDATE"]) ), @@ -193,10 +211,17 @@ def _get_paired_frame(x: str) -> str | None: tracktotal=tracktotal, discnumber=str(discnumber), disctotal=disctotal, - release=_get_tag(m.tags, ["\xa9alb"]), + releasetitle=_get_tag(m.tags, ["\xa9alb"]), genre=_split_tag(_get_tag(m.tags, ["\xa9gen"], split=True)), + secondarygenre=_split_tag( + _get_tag(m.tags, ["----:net.sunsetglow.rose:SECONDARYGENRE"], split=True) + ), + descriptor=_split_tag( + _get_tag(m.tags, ["----:net.sunsetglow.rose:DESCRIPTOR"], split=True) + ), label=_split_tag(_get_tag(m.tags, ["----:com.apple.iTunes:LABEL"], split=True)), catalognumber=_get_tag(m.tags, ["----:com.apple.iTunes:CATALOGNUMBER"]), + edition=_get_tag(m.tags, ["----:net.sunsetglow.rose:EDITION"]), releasetype=_normalize_rtype( _get_tag( m.tags, @@ -223,19 +248,23 @@ def _get_paired_frame(x: str) -> str | None: return AudioTags( id=_get_tag(m.tags, ["roseid"]), release_id=_get_tag(m.tags, ["rosereleaseid"]), - title=_get_tag(m.tags, ["title"]), + tracktitle=_get_tag(m.tags, ["title"]), releaseyear=_parse_year(_get_tag(m.tags, ["date", "year"])), + originalyear=_parse_year(_get_tag(m.tags, ["originaldate", "originalyear"])), compositionyear=_parse_year(_get_tag(m.tags, ["compositiondate"])), tracknumber=_get_tag(m.tags, ["tracknumber"], first=True), tracktotal=_parse_int(_get_tag(m.tags, ["tracktotal"], first=True)), discnumber=_get_tag(m.tags, ["discnumber"], first=True), disctotal=_parse_int(_get_tag(m.tags, ["disctotal"], first=True)), - release=_get_tag(m.tags, ["album"]), + releasetitle=_get_tag(m.tags, ["album"]), genre=_split_tag(_get_tag(m.tags, ["genre"], split=True)), + secondarygenre=_split_tag(_get_tag(m.tags, ["secondarygenre"], split=True)), + descriptor=_split_tag(_get_tag(m.tags, ["descriptor"], split=True)), label=_split_tag( _get_tag(m.tags, ["label", "organization", "recordlabel"], split=True) ), catalognumber=_get_tag(m.tags, ["catalognumber"]), + edition=_get_tag(m.tags, ["edition"]), releasetype=_normalize_rtype(_get_tag(m.tags, ["releasetype"], first=True)), releaseartists=parse_artist_string( main=_get_tag(m.tags, ["albumartist"], split=True) @@ -291,15 +320,19 @@ def _write_tag_with_description(name: str, value: str | None) -> None: _write_tag_with_description("TXXX:ROSEID", self.id) _write_tag_with_description("TXXX:ROSERELEASEID", self.release_id) - _write_standard_tag("TIT2", self.title) + _write_standard_tag("TIT2", self.tracktitle) _write_standard_tag("TDRC", str(self.releaseyear).zfill(4)) + _write_standard_tag("TDOR", str(self.originalyear).zfill(4)) _write_tag_with_description("TXXX:COMPOSITIONDATE", self.compositionyear) _write_standard_tag("TRCK", self.tracknumber) _write_standard_tag("TPOS", self.discnumber) - _write_standard_tag("TALB", self.release) + _write_standard_tag("TALB", self.releasetitle) _write_standard_tag("TCON", ";".join(self.genre)) + _write_tag_with_description("TXXX:SECONDARYGENRE", ";".join(self.secondarygenre)) + _write_tag_with_description("TXXX:DESCRIPTOR", ";".join(self.descriptor)) _write_standard_tag("TPUB", ";".join(self.label)) _write_tag_with_description("TXXX:CATALOGNUMBER", self.catalognumber) + _write_tag_with_description("TXXX:EDITION", self.edition) _write_tag_with_description("TXXX:RELEASETYPE", self.releasetype) _write_standard_tag("TPE2", format_artist_string(self.releaseartists)) _write_standard_tag("TPE1", format_artist_string(self.trackartists)) @@ -318,15 +351,24 @@ def _write_tag_with_description(name: str, value: str | None) -> None: m.tags = mutagen.mp4.MP4Tags() m.tags["----:net.sunsetglow.rose:ID"] = (self.id or "").encode() m.tags["----:net.sunsetglow.rose:RELEASEID"] = (self.release_id or "").encode() - m.tags["\xa9nam"] = self.title or "" + m.tags["\xa9nam"] = self.tracktitle or "" m.tags["\xa9day"] = str(self.releaseyear).zfill(4) + m.tags["----:net.sunsetglow.rose:ORIGINALDATE"] = ( + str(self.originalyear).zfill(4).encode() + ) m.tags["----:net.sunsetglow.rose:COMPOSITIONDATE"] = ( str(self.compositionyear).zfill(4).encode() ) - m.tags["\xa9alb"] = self.release or "" + m.tags["\xa9alb"] = self.releasetitle or "" + m.tags["\xa9gen"] = ";".join(self.genre) + m.tags["----:net.sunsetglow.rose:SECONDARYGENRE"] = ";".join( + self.secondarygenre + ).encode() + m.tags["----:net.sunsetglow.rose:DESCRIPTOR"] = ";".join(self.descriptor).encode() m.tags["\xa9gen"] = ";".join(self.genre) m.tags["----:com.apple.iTunes:LABEL"] = ";".join(self.label).encode() m.tags["----:com.apple.iTunes:CATALOGNUMBER"] = (self.catalognumber or "").encode() + m.tags["----:net.sunsetglow.rose:EDITION"] = (self.edition or "").encode() m.tags["----:com.apple.iTunes:RELEASETYPE"] = self.releasetype.encode() m.tags["aART"] = format_artist_string(self.releaseartists) m.tags["\xa9ART"] = format_artist_string(self.trackartists) @@ -376,15 +418,19 @@ def _write_tag_with_description(name: str, value: str | None) -> None: assert not isinstance(m.tags, mutagen.flac.MetadataBlock) m.tags["roseid"] = self.id or "" m.tags["rosereleaseid"] = self.release_id or "" - m.tags["title"] = self.title or "" + m.tags["title"] = self.tracktitle or "" m.tags["date"] = str(self.releaseyear).zfill(4) + m.tags["originaldate"] = str(self.originalyear).zfill(4) m.tags["compositiondate"] = str(self.compositionyear).zfill(4) m.tags["tracknumber"] = self.tracknumber or "" m.tags["discnumber"] = self.discnumber or "" - m.tags["album"] = self.release or "" + m.tags["album"] = self.releasetitle or "" m.tags["genre"] = ";".join(self.genre) + m.tags["secondarygenre"] = ";".join(self.secondarygenre) + m.tags["descriptor"] = ";".join(self.descriptor) m.tags["label"] = ";".join(self.label) m.tags["catalognumber"] = self.catalognumber or "" + m.tags["edition"] = self.edition or "" m.tags["releasetype"] = self.releasetype m.tags["albumartist"] = format_artist_string(self.releaseartists) m.tags["artist"] = format_artist_string(self.trackartists) diff --git a/rose/audiotags_test.py b/rose/audiotags_test.py index db077cd..730819c 100644 --- a/rose/audiotags_test.py +++ b/rose/audiotags_test.py @@ -26,13 +26,17 @@ ) def test_getters(filename: str, track_num: str, duration: int) -> None: af = AudioTags.from_file(TEST_TAGGER / filename) - assert af.release == "A Cool Album" + assert af.releasetitle == "A Cool Album" assert af.releasetype == "album" assert af.releaseyear == 1990 + assert af.originalyear == 1990 assert af.compositionyear == 1984 assert af.genre == ["Electronic", "House"] + assert af.secondarygenre == ["Minimal", "Ambient"] + assert af.descriptor == ["Lush", "Warm"] assert af.label == ["A Cool Label"] assert af.catalognumber == "DN-420" + assert af.edition == "Japan" assert af.releaseartists.main == [Artist("Artist A"), Artist("Artist B")] assert af.tracknumber == track_num @@ -40,7 +44,7 @@ def test_getters(filename: str, track_num: str, duration: int) -> None: assert af.discnumber == "1" assert af.disctotal == 1 - assert af.title == f"Track {track_num}" + assert af.tracktitle == f"Track {track_num}" assert af.trackartists == ArtistMapping( main=[Artist("Artist A"), Artist("Artist B")], guest=[Artist("Artist C"), Artist("Artist D")], @@ -74,19 +78,23 @@ def test_flush(isolated_dir: Path, filename: str, track_num: str, duration: int) af.flush() af = AudioTags.from_file(fpath) - assert af.release == "A Cool Album" + assert af.releasetitle == "A Cool Album" assert af.releasetype == "album" assert af.releaseyear == 1990 + assert af.originalyear == 1990 assert af.compositionyear == 1984 assert af.genre == ["Electronic", "House"] + assert af.secondarygenre == ["Minimal", "Ambient"] + assert af.descriptor == ["Lush", "Warm"] assert af.label == ["A Cool Label"] assert af.catalognumber == "DN-420" + assert af.edition == "Japan" assert af.releaseartists.main == [Artist("Artist A"), Artist("Artist B")] assert af.tracknumber == track_num assert af.discnumber == "1" - assert af.title == f"Track {track_num}" + assert af.tracktitle == f"Track {track_num}" assert af.trackartists == ArtistMapping( main=[Artist("Artist A"), Artist("Artist B")], guest=[Artist("Artist C"), Artist("Artist D")], diff --git a/rose/cache.py b/rose/cache.py index 072bc64..43e4acd 100644 --- a/rose/cache.py +++ b/rose/cache.py @@ -782,7 +782,7 @@ def _update_cache_for_releases_executor( # formatted artist string. if not pulled_release_tags: pulled_release_tags = True - release_title = tags.release or "Unknown Release" + release_title = tags.releasetitle or "Unknown Release" if release_title != release.releasetitle: logger.debug(f"Release title change detected for {source_path}, updating") release.releasetitle = release_title @@ -862,7 +862,7 @@ def _update_cache_for_releases_executor( id=track_id, source_path=Path(f), source_mtime=track_mtime, - tracktitle=tags.title or "Unknown Title", + tracktitle=tags.tracktitle or "Unknown Title", # Remove `.` here because we use `.` to parse out discno/trackno in the virtual # filesystem. It should almost never happen, but better to be safe. We set the # totals on all tracks the end of the loop. diff --git a/rose/releases.py b/rose/releases.py index 0cf6e5a..15773b3 100644 --- a/rose/releases.py +++ b/rose/releases.py @@ -367,8 +367,8 @@ def edit_release( tags.discnumber = track_meta.discnumber dirty = True logger.debug(f"Modified tag detected for {t.source_path}: discnumber") - if tags.title != track_meta.title: - tags.title = track_meta.title + if tags.tracktitle != track_meta.title: + tags.tracktitle = track_meta.title dirty = True logger.debug(f"Modified tag detected for {t.source_path}: title") tart = MetadataArtist.to_mapping(track_meta.artists) @@ -378,8 +378,8 @@ def edit_release( logger.debug(f"Modified tag detected for {t.source_path}: artists") # Album tags. - if tags.release != release_meta.title: - tags.release = release_meta.title + if tags.releasetitle != release_meta.title: + tags.releasetitle = release_meta.title dirty = True logger.debug(f"Modified tag detected for {t.source_path}: release") if tags.releasetype != release_meta.releasetype: @@ -468,7 +468,7 @@ def create_single_release(c: Config, track_path: Path) -> None: # Step 1. Compute the new directory name for the single. af = AudioTags.from_file(track_path) - title = (af.title or "Unknown Title").strip() + title = (af.tracktitle or "Unknown Title").strip() dirname = f"{artistsfmt(af.trackartists)} - " if af.releaseyear: @@ -494,7 +494,7 @@ def create_single_release(c: Config, track_path: Path) -> None: break # Step 3. Update the tags of the new track. Clear the Rose IDs too: this is a brand new track. af = AudioTags.from_file(new_track_path) - af.release = title + af.releasetitle = title af.releasetype = "single" af.releaseartists = af.trackartists af.tracknumber = "1" diff --git a/rose/releases_test.py b/rose/releases_test.py index 609d92a..2a73269 100644 --- a/rose/releases_test.py +++ b/rose/releases_test.py @@ -393,7 +393,7 @@ def test_extract_single_release(config: Config) -> None: assert (source_path / "01. Track 2.m4a").is_file() assert (source_path / "cover.jpg").is_file() af = AudioTags.from_file(source_path / "01. Track 2.m4a") - assert af.release == "Track 2" + assert af.releasetitle == "Track 2" assert af.tracknumber == "1" assert af.discnumber == "1" assert af.releasetype == "single" @@ -404,7 +404,7 @@ def test_extract_single_release_with_trailing_space(config: Config) -> None: release_dir = config.music_source_dir / TEST_RELEASE_1.name shutil.copytree(TEST_RELEASE_1, release_dir) af = AudioTags.from_file(release_dir / "02.m4a") - af.title = "Trailing Space " + af.tracktitle = "Trailing Space " af.flush() update_cache(config) create_single_release(config, release_dir / "02.m4a") @@ -724,4 +724,4 @@ def test_run_action_on_release(config: Config, source_dir: Path) -> None: action = MetadataAction.parse("tracktitle/replace:Bop") run_actions_on_release(config, "ilovecarly", [action]) af = AudioTags.from_file(source_dir / "Test Release 2" / "01.m4a") - assert af.title == "Bop" + assert af.tracktitle == "Bop" diff --git a/rose/rules.py b/rose/rules.py index 384e0aa..8b769b6 100644 --- a/rose/rules.py +++ b/rose/rules.py @@ -226,7 +226,7 @@ def filter_track_false_positives_using_tags( for field in matcher.tags: match = False # fmt: off - match = match or (field == "tracktitle" and matches_pattern(matcher.pattern, tags.title)) + match = match or (field == "tracktitle" and matches_pattern(matcher.pattern, tags.tracktitle)) match = match or (field == "releaseyear" and matches_pattern(matcher.pattern, tags.releaseyear)) match = match or (field == "compositionyear" and matches_pattern(matcher.pattern, tags.compositionyear)) match = match or (field == "catalognumber" and matches_pattern(matcher.pattern, tags.catalognumber)) @@ -234,7 +234,7 @@ def filter_track_false_positives_using_tags( match = match or (field == "tracktotal" and matches_pattern(matcher.pattern, tags.tracktotal)) match = match or (field == "discnumber" and matches_pattern(matcher.pattern, tags.discnumber)) match = match or (field == "disctotal" and matches_pattern(matcher.pattern, tags.disctotal)) - match = match or (field == "releasetitle" and matches_pattern(matcher.pattern, tags.release)) + match = match or (field == "releasetitle" and matches_pattern(matcher.pattern, tags.releasetitle)) match = match or (field == "releasetype" and matches_pattern(matcher.pattern, tags.releasetype)) match = match or (field == "genre" and any(matches_pattern(matcher.pattern, x) for x in tags.genre)) match = match or (field == "label" and any(matches_pattern(matcher.pattern, x) for x in tags.label)) @@ -260,7 +260,7 @@ def filter_track_false_positives_using_tags( skip = False for i in ignore: # fmt: off - skip = skip or (field == "tracktitle" and matches_pattern(i.pattern, tags.title)) + skip = skip or (field == "tracktitle" and matches_pattern(i.pattern, tags.tracktitle)) skip = skip or (field == "releaseyear" and matches_pattern(i.pattern, tags.releaseyear)) skip = skip or (field == "compositionyear" and matches_pattern(i.pattern, tags.compositionyear)) skip = skip or (field == "catalognumber" and matches_pattern(i.pattern, tags.catalognumber)) @@ -268,7 +268,7 @@ def filter_track_false_positives_using_tags( skip = skip or (field == "tracktotal" and matches_pattern(i.pattern, tags.tracktotal)) skip = skip or (field == "discnumber" and matches_pattern(i.pattern, tags.discnumber)) skip = skip or (field == "disctotal" and matches_pattern(i.pattern, tags.disctotal)) - skip = skip or (field == "releasetitle" and matches_pattern(i.pattern, tags.release)) + skip = skip or (field == "releasetitle" and matches_pattern(i.pattern, tags.releasetitle)) skip = skip or (field == "releasetype" and matches_pattern(i.pattern, tags.releasetype)) skip = skip or (field == "genre" and any(matches_pattern(i.pattern, x) for x in tags.genre)) skip = skip or (field == "label" and any(matches_pattern(i.pattern, x) for x in tags.label)) @@ -337,8 +337,8 @@ def artists(xs: list[str]) -> list[Artist]: for field in fields_to_update: # fmt: off if field == "tracktitle": - tags.title = execute_single_action(act, tags.title) - potential_changes.append(("title", origtags.title, tags.title)) + tags.tracktitle = execute_single_action(act, tags.tracktitle) + potential_changes.append(("title", origtags.tracktitle, tags.tracktitle)) elif field == "releaseyear": v = execute_single_action(act, tags.releaseyear) try: @@ -367,8 +367,8 @@ def artists(xs: list[str]) -> list[Artist]: tags.discnumber = execute_single_action(act, tags.discnumber) potential_changes.append(("discnumber", origtags.discnumber, tags.discnumber)) elif field == "releasetitle": - tags.release = execute_single_action(act, tags.release) - potential_changes.append(("release", origtags.release, tags.release)) + tags.releasetitle = execute_single_action(act, tags.releasetitle) + potential_changes.append(("release", origtags.releasetitle, tags.releasetitle)) elif field == "releasetype": tags.releasetype = execute_single_action(act, tags.releasetype) or "unknown" potential_changes.append(("releasetype", origtags.releasetype, tags.releasetype)) diff --git a/rose/rules_test.py b/rose/rules_test.py index b9202b4..204a0be 100644 --- a/rose/rules_test.py +++ b/rose/rules_test.py @@ -31,13 +31,13 @@ def test_rules_execution_match_substring(config: Config, source_dir: Path) -> No rule = MetadataRule.parse("tracktitle:bbb", ["replace:lalala"]) execute_metadata_rule(config, rule, confirm_yes=False) af = AudioTags.from_file(source_dir / "Test Release 1" / "01.m4a") - assert af.title != "lalala" + assert af.tracktitle != "lalala" # Match rule = MetadataRule.parse("tracktitle:rack", ["replace:lalala"]) execute_metadata_rule(config, rule, confirm_yes=False) af = AudioTags.from_file(source_dir / "Test Release 1" / "01.m4a") - assert af.title == "lalala" + assert af.tracktitle == "lalala" def test_rules_execution_match_beginnning(config: Config, source_dir: Path) -> None: @@ -45,13 +45,13 @@ def test_rules_execution_match_beginnning(config: Config, source_dir: Path) -> N rule = MetadataRule.parse("tracktitle:^rack", ["replace:lalala"]) execute_metadata_rule(config, rule, confirm_yes=False) af = AudioTags.from_file(source_dir / "Test Release 1" / "01.m4a") - assert af.title != "lalala" + assert af.tracktitle != "lalala" # Match rule = MetadataRule.parse("tracktitle:^Track", ["replace:lalala"]) execute_metadata_rule(config, rule, confirm_yes=False) af = AudioTags.from_file(source_dir / "Test Release 1" / "01.m4a") - assert af.title == "lalala" + assert af.tracktitle == "lalala" def test_rules_execution_match_end(config: Config, source_dir: Path) -> None: @@ -59,13 +59,13 @@ def test_rules_execution_match_end(config: Config, source_dir: Path) -> None: rule = MetadataRule.parse("tracktitle:rack$", ["replace:lalala"]) execute_metadata_rule(config, rule, confirm_yes=False) af = AudioTags.from_file(source_dir / "Test Release 1" / "01.m4a") - assert af.title != "lalala" + assert af.tracktitle != "lalala" # Match rule = MetadataRule.parse("tracktitle:rack 1$", ["replace:lalala"]) execute_metadata_rule(config, rule, confirm_yes=False) af = AudioTags.from_file(source_dir / "Test Release 1" / "01.m4a") - assert af.title == "lalala" + assert af.tracktitle == "lalala" def test_rules_execution_match_superstrict(config: Config, source_dir: Path) -> None: @@ -73,18 +73,18 @@ def test_rules_execution_match_superstrict(config: Config, source_dir: Path) -> rule = MetadataRule.parse("tracktitle:^Track $", ["replace:lalala"]) execute_metadata_rule(config, rule, confirm_yes=False) af = AudioTags.from_file(source_dir / "Test Release 1" / "01.m4a") - assert af.title != "lalala" + assert af.tracktitle != "lalala" # Match rule = MetadataRule.parse("tracktitle:^Track 1$", ["replace:lalala"]) execute_metadata_rule(config, rule, confirm_yes=False) af = AudioTags.from_file(source_dir / "Test Release 1" / "01.m4a") - assert af.title == "lalala" + assert af.tracktitle == "lalala" def test_rules_execution_match_escaped_superstrict(config: Config, source_dir: Path) -> None: af = AudioTags.from_file(source_dir / "Test Release 1" / "01.m4a") - af.title = "hi^Test$bye" + af.tracktitle = "hi^Test$bye" af.flush() update_cache(config) @@ -92,27 +92,27 @@ def test_rules_execution_match_escaped_superstrict(config: Config, source_dir: P rule = MetadataRule.parse("tracktitle:^Test$", ["replace:lalala"]) execute_metadata_rule(config, rule, confirm_yes=False) af = AudioTags.from_file(source_dir / "Test Release 1" / "01.m4a") - assert af.title != "lalala" + assert af.tracktitle != "lalala" # Match rule = MetadataRule.parse(r"tracktitle:\^Test\$", ["replace:lalala"]) execute_metadata_rule(config, rule, confirm_yes=False) af = AudioTags.from_file(source_dir / "Test Release 1" / "01.m4a") - assert af.title == "lalala" + assert af.tracktitle == "lalala" def test_rules_execution_match_case_insensitive(config: Config, source_dir: Path) -> None: rule = MetadataRule.parse("tracktitle:tRaCk:i", ["replace:lalala"]) execute_metadata_rule(config, rule, confirm_yes=False) af = AudioTags.from_file(source_dir / "Test Release 1" / "01.m4a") - assert af.title == "lalala" + assert af.tracktitle == "lalala" def test_rules_fields_match_tracktitle(config: Config, source_dir: Path) -> None: rule = MetadataRule.parse("tracktitle:Track", ["replace:8"]) execute_metadata_rule(config, rule, confirm_yes=False) af = AudioTags.from_file(source_dir / "Test Release 1" / "01.m4a") - assert af.title == "8" + assert af.tracktitle == "8" def test_rules_fields_match_releaseyear(config: Config, source_dir: Path) -> None: @@ -140,7 +140,7 @@ def test_rules_fields_match_tracktotal(config: Config, source_dir: Path) -> None rule = MetadataRule.parse("tracktotal:2", ["tracktitle/replace:8"]) execute_metadata_rule(config, rule, confirm_yes=False) af = AudioTags.from_file(source_dir / "Test Release 1" / "01.m4a") - assert af.title == "8" + assert af.tracktitle == "8" def test_rules_fields_match_discnumber(config: Config, source_dir: Path) -> None: @@ -154,14 +154,14 @@ def test_rules_fields_match_disctotal(config: Config, source_dir: Path) -> None: rule = MetadataRule.parse("disctotal:1", ["tracktitle/replace:8"]) execute_metadata_rule(config, rule, confirm_yes=False) af = AudioTags.from_file(source_dir / "Test Release 1" / "01.m4a") - assert af.title == "8" + assert af.tracktitle == "8" def test_rules_fields_match_releasetitle(config: Config, source_dir: Path) -> None: rule = MetadataRule.parse("releasetitle:Love Blackpink", ["replace:8"]) execute_metadata_rule(config, rule, confirm_yes=False) af = AudioTags.from_file(source_dir / "Test Release 1" / "01.m4a") - assert af.release == "8" + assert af.releasetitle == "8" def test_rules_fields_match_genre(config: Config, source_dir: Path) -> None: @@ -194,14 +194,14 @@ def test_rules_fields_match_trackartist(config: Config, source_dir: Path) -> Non def test_match_backslash(config: Config, source_dir: Path) -> None: af = AudioTags.from_file(source_dir / "Test Release 1" / "01.m4a") - af.title = r"X \\ Y" + af.tracktitle = r"X \\ Y" af.flush() update_cache(config) rule = MetadataRule.parse(r"tracktitle: \\ ", [r"sed: \\\\ : // "]) execute_metadata_rule(config, rule, confirm_yes=False) af = AudioTags.from_file(source_dir / "Test Release 1" / "01.m4a") - assert af.title == "X / Y" + assert af.tracktitle == "X / Y" def test_action_replace_with_delimiter(config: Config, source_dir: Path) -> None: @@ -222,7 +222,7 @@ def test_sed_action(config: Config, source_dir: Path) -> None: rule = MetadataRule.parse("tracktitle:Track", ["sed:ack:ip"]) execute_metadata_rule(config, rule, confirm_yes=False) af = AudioTags.from_file(source_dir / "Test Release 1" / "01.m4a") - assert af.title == "Trip 1" + assert af.tracktitle == "Trip 1" def test_sed_no_pattern(config: Config, source_dir: Path) -> None: @@ -310,7 +310,7 @@ def test_confirmation_yes(monkeypatch: Any, config: Config, source_dir: Path) -> monkeypatch.setattr("rose.rules.click.confirm", lambda *_, **__: True) execute_metadata_rule(config, rule, confirm_yes=True) af = AudioTags.from_file(source_dir / "Test Release 1" / "01.m4a") - assert af.title == "lalala" + assert af.tracktitle == "lalala" @pytest.mark.timeout(2) @@ -319,7 +319,7 @@ def test_confirmation_no(monkeypatch: Any, config: Config, source_dir: Path) -> monkeypatch.setattr("rose.rules.click.confirm", lambda *_, **__: False) execute_metadata_rule(config, rule, confirm_yes=True) af = AudioTags.from_file(source_dir / "Test Release 1" / "01.m4a") - assert af.title != "lalala" + assert af.tracktitle != "lalala" @pytest.mark.timeout(2) @@ -329,19 +329,19 @@ def test_confirmation_count(monkeypatch: Any, config: Config, source_dir: Path) # Abort. execute_metadata_rule(config, rule, confirm_yes=True, enter_number_to_confirm_above_count=1) af = AudioTags.from_file(source_dir / "Test Release 1" / "01.m4a") - assert af.title != "lalala" + assert af.tracktitle != "lalala" # Success in two arguments. execute_metadata_rule(config, rule, confirm_yes=True, enter_number_to_confirm_above_count=1) af = AudioTags.from_file(source_dir / "Test Release 1" / "01.m4a") - assert af.title == "lalala" + assert af.tracktitle == "lalala" def test_dry_run(config: Config, source_dir: Path) -> None: rule = MetadataRule.parse("tracktitle:Track", ["replace:lalala"]) execute_metadata_rule(config, rule, dry_run=True, confirm_yes=False) af = AudioTags.from_file(source_dir / "Test Release 1" / "01.m4a") - assert af.title != "lalala" + assert af.tracktitle != "lalala" def test_run_stored_rules(config: Config, source_dir: Path) -> None: @@ -352,7 +352,7 @@ def test_run_stored_rules(config: Config, source_dir: Path) -> None: execute_stored_metadata_rules(config) af = AudioTags.from_file(source_dir / "Test Release 1" / "01.m4a") - assert af.title == "lalala" + assert af.tracktitle == "lalala" @pytest.mark.usefixtures("seeded_cache") @@ -399,4 +399,4 @@ def test_ignore_values(config: Config, source_dir: Path) -> None: rule = MetadataRule.parse("tracktitle:rack", ["replace:lalala"], ["tracktitle:^Track 1$"]) execute_metadata_rule(config, rule, confirm_yes=False) af = AudioTags.from_file(source_dir / "Test Release 1" / "01.m4a") - assert af.title == "Track 1" + assert af.tracktitle == "Track 1" diff --git a/rose/tracks_test.py b/rose/tracks_test.py index 90ef418..772c009 100644 --- a/rose/tracks_test.py +++ b/rose/tracks_test.py @@ -15,7 +15,7 @@ def test_run_action_on_track(config: Config, source_dir: Path) -> None: assert af.id is not None run_actions_on_track(config, af.id, [action]) af = AudioTags.from_file(source_dir / "Test Release 2" / "01.m4a") - assert af.title == "Bop" + assert af.tracktitle == "Bop" @pytest.mark.usefixtures("seeded_cache") diff --git a/rose_vfs/virtualfs_test.py b/rose_vfs/virtualfs_test.py index 6e2eec0..d214f11 100644 --- a/rose_vfs/virtualfs_test.py +++ b/rose_vfs/virtualfs_test.py @@ -130,8 +130,8 @@ def test_virtual_filesystem_write_files( with start_virtual_fs(config): # Write! af = AudioTags.from_file(path) - assert af.title == "Track 1" - af.title = "Hahahaha!!" + assert af.tracktitle == "Track 1" + af.tracktitle = "Hahahaha!!" af.flush() # Read! File should have been renamed post-cache update. exists() for the old file will # resolve because of the "legacy file resolution" grace period, but the old file should no @@ -140,7 +140,7 @@ def test_virtual_filesystem_write_files( path = path.with_name("01. Hahahaha!!.m4a") assert path.is_file() af = AudioTags.from_file(path) - assert af.title == "Hahahaha!!" + assert af.tracktitle == "Hahahaha!!" @pytest.mark.usefixtures("seeded_cache") diff --git a/scripts/update_testdata_files.py b/scripts/update_testdata_files.py index 9390927..ba2fc69 100755 --- a/scripts/update_testdata_files.py +++ b/scripts/update_testdata_files.py @@ -1,5 +1,6 @@ #!/usr/bin/env python +import os from typing import Any import mutagen @@ -26,6 +27,8 @@ def write_tag_with_description(f: Any, name: str, value: str | None) -> None: f.tags.add(x) +os.chdir(os.environ["ROSE_ROOT"] + "/testdata/Tagger") + f = mutagen.File("track1.flac") # type: ignore f.tags["originaldate"] = "1990" f.tags["secondarygenre"] = "Minimal;Ambient" @@ -34,7 +37,7 @@ def write_tag_with_description(f: Any, name: str, value: str | None) -> None: f.save() f = mutagen.File("track2.m4a") # type: ignore -f.tags["----:net.sunsetglow.rose:ORIGINALYEAR"] = b"1990" +f.tags["----:net.sunsetglow.rose:ORIGINALDATE"] = b"1990" f.tags["----:net.sunsetglow.rose:SECONDARYGENRE"] = b"Minimal;Ambient" f.tags["----:net.sunsetglow.rose:DESCRIPTOR"] = b"Lush;Warm" f.tags["----:net.sunsetglow.rose:EDITION"] = b"Japan" diff --git a/testdata/Tagger/track2.m4a b/testdata/Tagger/track2.m4a index 928e820..a2d9f47 100644 Binary files a/testdata/Tagger/track2.m4a and b/testdata/Tagger/track2.m4a differ