Skip to content

Commit

Permalink
work
Browse files Browse the repository at this point in the history
  • Loading branch information
azuline committed Apr 20, 2024
1 parent 8030486 commit f54aaa7
Show file tree
Hide file tree
Showing 18 changed files with 276 additions and 26 deletions.
12 changes: 8 additions & 4 deletions conftest.py
Original file line number Diff line number Diff line change
Expand Up @@ -112,10 +112,10 @@ def seeded_cache(config: Config) -> None:
conn.executescript(
f"""\
INSERT INTO releases
(id , source_path , cover_image_path , added_at , datafile_mtime, title , releasetype, releaseyear, disctotal, new , metahash)
VALUES ('r1', '{dirpaths[0]}', null , '0000-01-01T00:00:00+00:00', '999' , 'Release 1', 'album' , 2023 , 1 , false, '1')
, ('r2', '{dirpaths[1]}', '{imagepaths[0]}', '0000-01-01T00:00:00+00:00', '999' , 'Release 2', 'album' , 2021 , 1 , false, '2')
, ('r3', '{dirpaths[2]}', null , '0000-01-01T00:00:00+00:00', '999' , 'Release 3', 'album' , 2021 , 1 , true , '3');
(id , source_path , cover_image_path , added_at , datafile_mtime, title , releasetype, releaseyear, compositionyear, catalognumber, disctotal, new , metahash)
VALUES ('r1', '{dirpaths[0]}', null , '0000-01-01T00:00:00+00:00', '999' , 'Release 1', 'album' , 2023 , null , null , 1 , false, '1')
, ('r2', '{dirpaths[1]}', '{imagepaths[0]}', '0000-01-01T00:00:00+00:00', '999' , 'Release 2', 'album' , 2021 , null , 'DG-001' , 1 , false, '2')
, ('r3', '{dirpaths[2]}', null , '0000-01-01T00:00:00+00:00', '999' , 'Release 3', 'album' , 2021 , 1780 , 'DG-002' , 1 , true , '3');
INSERT INTO releases_genres
(release_id, genre , genre_sanitized, position)
Expand Down Expand Up @@ -184,6 +184,8 @@ def seeded_cache(config: Config) -> None:
, discnumber
, releasetitle
, releaseyear
, compositionyear
, catalognumber
, releasetype
, genre
, label
Expand All @@ -197,6 +199,8 @@ def seeded_cache(config: Config) -> None:
, process_string_for_fts(t.discnumber) AS discnumber
, process_string_for_fts(r.title) AS releasetitle
, process_string_for_fts(r.releaseyear) AS releaseyear
, process_string_for_fts(r.compositionyear) AS compositionyear
, process_string_for_fts(r.catalognumber) AS catalognumber
, process_string_for_fts(r.releasetype) AS releasetype
, process_string_for_fts(COALESCE(GROUP_CONCAT(rg.genre, ' '), '')) AS genre
, process_string_for_fts(COALESCE(GROUP_CONCAT(rl.label, ' '), '')) AS label
Expand Down
4 changes: 4 additions & 0 deletions docs/METADATA_TOOLS.md
Original file line number Diff line number Diff line change
Expand Up @@ -40,6 +40,7 @@ title = "Mix & Match"
new = false
releasetype = "ep"
releaseyear = 2017
compositionyear = -9999
genres = [
"Dance-Pop",
"Future Bass",
Expand All @@ -48,6 +49,7 @@ genres = [
labels = [
"BlockBerry Creative",
]
catalognumber = "WMED0709"
artists = [
{ name = "LOOΠΔ ODD EYE CIRCLE", role = "main" },
]
Expand Down Expand Up @@ -295,8 +297,10 @@ The rules engine supports matching and acting on the following tags:
- `releaseartist[djmixer]`
- `releasetype`
- `releaseyear`
- `compositionyear`
- `genre`
- `label`
- `catalognumber`

The `trackartist[*]`, `releaseartist[*]`, `genre`, and `label` tags are _multi-value_ tags, which
have a slightly different behavior from single-value tags for some of the actions. We'll explore
Expand Down
8 changes: 6 additions & 2 deletions docs/TEMPLATES.md
Original file line number Diff line number Diff line change
Expand Up @@ -77,12 +77,14 @@ Rosé provides the following template variables for releases:
```python
added_at: str # ISO8601 timestamp of when the release was added to the library.
releasetitle: str
releasetype: str # Type of the release (e.g. single, ep, etc). One of the enums as defined in TAGGING_CONVENTIONS.md.
releasetype: str # The type of the release (e.g. single, ep, etc). One of the enums as defined in TAGGING_CONVENTIONS.md.
releaseyear: int | None
compositionyear: int | None # The year that the release was composed. Mainly of interest in classical music.
new: bool # The "new"-ness of the release. See RELEASES.md for documentation on this feature.
disctotal: int # The number of discs in the release.
genres: list[str]
labels: list[str]
catalognumber: str | None
releaseartists: ArtistMapping # All release artists: an object with 6 properties, each corresponding to one role.
releaseartists.main: list[Artist] # The Artist object has a `name` property with the artist name.
releaseartists.guest: list[Artist]
Expand Down Expand Up @@ -113,11 +115,13 @@ trackartists.composer: list[Artist]
trackartists.conductor: list[Artist]
trackartists.djmixer: list[Artist]
releasetitle: str
releasetype: str # Type of the track's release (e.g. single, ep, etc).
releasetype: str # The type of the track's release (e.g. single, ep, etc).
releaseyear: int | None
compositionyear: int | None # The year that the release was composed. Mainly of interest in classical music.
new: bool # The "new"-ness of the track's release.
genres: list[str]
labels: list[str]
catalognumber: str | None
releaseartists: ArtistMapping # All release artists: an object with 6 properties, each corresponding to one role.
releaseartists.main: list[Artist] # The Artist object has a `name` property with the artist name.
releaseartists.guest: list[Artist]
Expand Down
34 changes: 26 additions & 8 deletions rose/audiotags.py
Original file line number Diff line number Diff line change
Expand Up @@ -87,13 +87,15 @@ class AudioTags:
release_id: str | None
title: str | None
releaseyear: int | None
compositionyear: int | None
tracknumber: str | None
tracktotal: int | None
discnumber: str | None
disctotal: int | None
release: str | None
genre: list[str]
label: list[str]
catalognumber: str | None
releasetype: str

releaseartists: ArtistMapping
Expand Down Expand Up @@ -144,13 +146,15 @@ def _get_paired_frame(x: str) -> str | None:
release_id=_get_tag(m.tags, ["TXXX:ROSERELEASEID"]),
title=_get_tag(m.tags, ["TIT2"]),
releaseyear=_parse_year(_get_tag(m.tags, ["TDRC", "TYER"])),
compositionyear=_parse_year(_get_tag(m.tags, ["TXXX:COMPOSITIONYEAR"])),
tracknumber=tracknumber,
tracktotal=tracktotal,
discnumber=discnumber,
disctotal=disctotal,
release=_get_tag(m.tags, ["TALB"]),
genre=_split_tag(_get_tag(m.tags, ["TCON"], split=True)),
label=_split_tag(_get_tag(m.tags, ["TPUB"], split=True)),
catalognumber=_get_tag(m.tags, ["TXXX:CATALOGNUMBER"]),
releasetype=_normalize_rtype(_get_tag(m.tags, ["TXXX:RELEASETYPE"], first=True)),
releaseartists=parse_artist_string(main=_get_tag(m.tags, ["TPE2"], split=True)),
trackartists=parse_artist_string(
Expand Down Expand Up @@ -178,13 +182,17 @@ def _get_paired_frame(x: str) -> str | None:
release_id=_get_tag(m.tags, ["----:net.sunsetglow.rose:RELEASEID"]),
title=_get_tag(m.tags, ["\xa9nam"]),
releaseyear=_parse_year(_get_tag(m.tags, ["\xa9day"])),
compositionyear=_parse_year(
_get_tag(m.tags, ["----:net.sunsetglow.rose:COMPOSITIONYEAR"])
),
tracknumber=str(tracknumber),
tracktotal=tracktotal,
discnumber=str(discnumber),
disctotal=disctotal,
release=_get_tag(m.tags, ["\xa9alb"]),
genre=_split_tag(_get_tag(m.tags, ["\xa9gen"], split=True)),
label=_split_tag(_get_tag(m.tags, ["----:com.apple.iTunes:LABEL"], split=True)),
catalognumber=_get_tag(m.tags, ["----:com.apple.iTunes:CATALOGNUMBER"]),
releasetype=_normalize_rtype(
_get_tag(m.tags, ["----:com.apple.iTunes:RELEASETYPE"], first=True)
),
Expand All @@ -206,15 +214,17 @@ def _get_paired_frame(x: str) -> str | None:
release_id=_get_tag(m.tags, ["rosereleaseid"]),
title=_get_tag(m.tags, ["title"]),
releaseyear=_parse_year(_get_tag(m.tags, ["date", "year"])),
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"]),
genre=_split_tag(_get_tag(m.tags, ["genre"], split=True)),
label=_split_tag(
_get_tag(m.tags, ["organization", "label", "recordlabel"], split=True)
_get_tag(m.tags, ["label", "organization", "recordlabel"], split=True)
),
catalognumber=_get_tag(m.tags, ["catalognumber"]),
releasetype=_normalize_rtype(_get_tag(m.tags, ["releasetype"], first=True)),
releaseartists=parse_artist_string(
main=_get_tag(m.tags, ["albumartist"], split=True)
Expand Down Expand Up @@ -272,11 +282,13 @@ def _write_tag_with_description(name: str, value: str | None) -> None:
_write_tag_with_description("TXXX:ROSERELEASEID", self.release_id)
_write_standard_tag("TIT2", self.title)
_write_standard_tag("TDRC", str(self.releaseyear).zfill(4))
_write_tag_with_description("TXXX:COMPOSITIONYEAR", self.compositionyear)
_write_standard_tag("TRCK", self.tracknumber)
_write_standard_tag("TPOS", self.discnumber)
_write_standard_tag("TALB", self.release)
_write_standard_tag("TCON", ";".join(self.genre))
_write_standard_tag("TPUB", ";".join(self.label))
_write_tag_with_description("TXXX:CATALOGNUMBER", self.catalognumber)
_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))
Expand All @@ -295,14 +307,18 @@ 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["\xa9day"] = str(self.releaseyear).zfill(4)
m.tags["\xa9alb"] = self.release or ""
m.tags["\xa9gen"] = ";".join(self.genre)
m.tags["\xa9nam"] = (self.title or "").encode()
m.tags["\xa9day"] = str(self.releaseyear).zfill(4).encode()
m.tags["----:net.sunsetglow.rose:COMPOSITIONYEAR"] = (
str(self.compositionyear).zfill(4).encode()
)
m.tags["\xa9alb"] = (self.release or "").encode()
m.tags["\xa9gen"] = ";".join(self.genre).encode()
m.tags["----:com.apple.iTunes:LABEL"] = ";".join(self.label).encode()
m.tags["----:com.apple.iTunes:CATALOGNUMBER"] = (self.catalognumber 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)
m.tags["aART"] = format_artist_string(self.releaseartists).encode()
m.tags["\xa9ART"] = format_artist_string(self.trackartists).encode()
# Wipe the alt. role artist tags, since we encode the full artist into the main tag.
with contextlib.suppress(KeyError):
del m.tags["----:com.apple.iTunes:REMIXER"]
Expand Down Expand Up @@ -351,11 +367,13 @@ def _write_tag_with_description(name: str, value: str | None) -> None:
m.tags["rosereleaseid"] = self.release_id or ""
m.tags["title"] = self.title or ""
m.tags["date"] = str(self.releaseyear).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["genre"] = ";".join(self.genre)
m.tags["organization"] = ";".join(self.label)
m.tags["label"] = ";".join(self.label)
m.tags["catalognumber"] = self.catalognumber or ""
m.tags["releasetype"] = self.releasetype
m.tags["albumartist"] = format_artist_string(self.releaseartists)
m.tags["artist"] = format_artist_string(self.trackartists)
Expand Down
34 changes: 33 additions & 1 deletion rose/cache.py
Original file line number Diff line number Diff line change
Expand Up @@ -209,6 +209,8 @@ class CachedRelease:
releasetitle: str
releasetype: str
releaseyear: int | None
compositionyear: int | None
catalognumber: str | None
new: bool
disctotal: int
genres: list[str]
Expand All @@ -227,6 +229,8 @@ def from_view(cls, c: Config, row: dict[str, Any], aliases: bool = True) -> Cach
releasetitle=row["releasetitle"],
releasetype=row["releasetype"],
releaseyear=row["releaseyear"],
compositionyear=row["compositionyear"],
catalognumber=row["catalognumber"],
disctotal=row["disctotal"],
new=bool(row["new"]),
genres=_split(row["genres"]) if row["genres"] else [],
Expand All @@ -248,6 +252,8 @@ def dump(self) -> dict[str, Any]:
"releasetitle": self.releasetitle,
"releasetype": self.releasetype,
"releaseyear": self.releaseyear,
"compositionyear": self.compositionyear,
"catalognumber": self.catalognumber,
"new": self.new,
"disctotal": self.disctotal,
"genres": self.genres,
Expand Down Expand Up @@ -318,6 +324,8 @@ def dump(self, with_release_info: bool = True) -> dict[str, Any]:
"releasetype": self.release.releasetype,
"disctotal": self.release.disctotal,
"releaseyear": self.release.releaseyear,
"compositionyear": self.release.compositionyear,
"catalognumber": self.release.catalognumber,
"new": self.release.new,
"genres": self.release.genres,
"labels": self.release.labels,
Expand Down Expand Up @@ -613,6 +621,8 @@ def _update_cache_for_releases_executor(
releasetitle="",
releasetype="",
releaseyear=None,
compositionyear=None,
catalognumber=None,
new=True,
disctotal=0,
genres=[],
Expand Down Expand Up @@ -782,6 +792,20 @@ def _update_cache_for_releases_executor(
release.releaseyear = tags.releaseyear
release_dirty = True

if tags.compositionyear != release.compositionyear:
logger.debug(
f"Release composition year change detected for {source_path}, updating"
)
release.compositionyear = tags.compositionyear
release_dirty = True

if tags.catalognumber != release.catalognumber:
logger.debug(
f"Release catalog number change detected for {source_path}, updating"
)
release.catalognumber = tags.catalognumber
release_dirty = True

if set(tags.genre) != set(release.genres):
logger.debug(f"Release genre change detected for {source_path}, updating")
release.genres = uniq(tags.genre)
Expand Down Expand Up @@ -950,6 +974,8 @@ def _update_cache_for_releases_executor(
release.releasetitle,
release.releasetype,
release.releaseyear,
release.compositionyear,
release.catalognumber,
release.disctotal,
release.new,
sha256_dataclass(release),
Expand Down Expand Up @@ -1031,10 +1057,12 @@ def _update_cache_for_releases_executor(
, title
, releasetype
, releaseyear
, compositionyear
, catalognumber
, disctotal
, new
, metahash
) VALUES {",".join(["(?,?,?,?,?,?,?,?,?,?,?)"] * len(upd_release_args))}
) VALUES {",".join(["(?,?,?,?,?,?,?,?,?,?,?,?,?)"] * len(upd_release_args))}
""",
_flatten(upd_release_args),
)
Expand Down Expand Up @@ -1149,6 +1177,8 @@ def _update_cache_for_releases_executor(
, disctotal
, releasetitle
, releaseyear
, compositionyear
, catalognumber
, releasetype
, genre
, label
Expand All @@ -1164,6 +1194,8 @@ def _update_cache_for_releases_executor(
, process_string_for_fts(r.disctotal) AS discnumber
, process_string_for_fts(r.title) AS releasetitle
, process_string_for_fts(r.releaseyear) AS releaseyear
, process_string_for_fts(r.compositionyear) AS compositionyear
, process_string_for_fts(r.catalognumber) AS catalognumber
, process_string_for_fts(r.releasetype) AS releasetype
, process_string_for_fts(COALESCE(GROUP_CONCAT(rg.genre, ' '), '')) AS genre
, process_string_for_fts(COALESCE(GROUP_CONCAT(rl.label, ' '), '')) AS label
Expand Down
8 changes: 7 additions & 1 deletion rose/cache.sql
Original file line number Diff line number Diff line change
Expand Up @@ -15,6 +15,8 @@ CREATE TABLE releases (
title TEXT NOT NULL,
releasetype TEXT NOT NULL,
releaseyear INTEGER,
compositionyear INTEGER,
catalognumber TEXT,
disctotal INTEGER NOT NULL,
-- A sha256() of the release object, which can be used as a performant cache
-- key.
Expand Down Expand Up @@ -156,8 +158,10 @@ CREATE VIRTUAL TABLE rules_engine_fts USING fts5 (
, discnumber
, disctotal
, releasetitle
, releaseyear
, releasetype
, releaseyear
, compositionyear
, catalognumber
, genre
, label
, releaseartist
Expand Down Expand Up @@ -201,6 +205,8 @@ CREATE VIEW releases_view AS
, r.title AS releasetitle
, r.releasetype
, r.releaseyear
, r.compositionyear
, r.catalognumber
, r.disctotal
, r.new
, r.metahash
Expand Down
Loading

0 comments on commit f54aaa7

Please sign in to comment.