Skip to content

Commit

Permalink
add option to hide labels/genres/artists that solely belong to new re…
Browse files Browse the repository at this point in the history
…leases
  • Loading branch information
azuline committed May 2, 2024
1 parent 9a649a5 commit d2f30a0
Show file tree
Hide file tree
Showing 13 changed files with 236 additions and 55 deletions.
7 changes: 5 additions & 2 deletions conftest.py
Original file line number Diff line number Diff line change
Expand Up @@ -83,6 +83,9 @@ def config(isolated_dir: Path) -> Config:
fuse_genres_blacklist=None,
fuse_descriptors_blacklist=None,
fuse_labels_blacklist=None,
hide_genres_with_only_new_releases=False,
hide_descriptors_with_only_new_releases=False,
hide_labels_with_only_new_releases=False,
cover_art_stems=["cover", "folder", "art", "front"],
valid_art_exts=["jpg", "jpeg", "png"],
max_filename_bytes=180,
Expand Down Expand Up @@ -117,8 +120,8 @@ def seeded_cache(config: Config) -> None:
INSERT INTO releases
(id , source_path , cover_image_path , added_at , datafile_mtime, title , releasetype, releasedate , originaldate, compositiondate, catalognumber, edition , disctotal, new , metahash)
VALUES ('r1', '{dirpaths[0]}', null , '0000-01-01T00:00:00+00:00', '999' , 'Release 1', 'album' , '2023' , null , null , null , null , 1 , false, '1')
, ('r2', '{dirpaths[1]}', '{imagepaths[0]}', '0000-01-01T00:00:00+00:00', '999' , 'Release 2', 'album' , '2021' , '2019' , null , 'DG-001' , 'Deluxe', 1 , false, '2')
, ('r3', '{dirpaths[2]}', null , '0000-01-01T00:00:00+00:00', '999' , 'Release 3', 'album' , '2021-04-20', null , '1780' , 'DG-002' , null , 1 , true , '3');
, ('r2', '{dirpaths[1]}', '{imagepaths[0]}', '0000-01-01T00:00:00+00:00', '999' , 'Release 2', 'album' , '2021' , '2019' , null , 'DG-001' , 'Deluxe', 1 , true , '2')
, ('r3', '{dirpaths[2]}', null , '0000-01-01T00:00:00+00:00', '999' , 'Release 3', 'album' , '2021-04-20', null , '1780' , 'DG-002' , null , 1 , false, '3');
INSERT INTO releases_genres
(release_id, genre , position)
Expand Down
8 changes: 8 additions & 0 deletions docs/CONFIGURATION.md
Original file line number Diff line number Diff line change
Expand Up @@ -82,6 +82,14 @@ fuse_genres_blacklist = [ "xxx" ]
fuse_descriptors_blacklist = [ "xxx" ]
fuse_labels_blacklist = [ "xxx" ]

# Whether to hide the genres, descriptors, and labels from new releases from
# being returned in when listing genres/descriptors/labels. This is useful new
# releases are improperly tagged, as those tags tend to be very incorrect by
# default.
hide_genres_with_only_new_releases = true
hide_descriptors_with_only_new_releases = true
hide_labels_with_only_new_releases = true

# When Rosé scans a release directory, it looks for cover art that matches:
#
# 1. A supported file "stem" (the filename excluding the extension).
Expand Down
8 changes: 7 additions & 1 deletion rose/__init__.py
Original file line number Diff line number Diff line change
Expand Up @@ -15,6 +15,9 @@
STORED_DATA_FILE_REGEX,
CachedRelease,
CachedTrack,
DescriptorEntry,
GenreEntry,
LabelEntry,
artist_exists,
calculate_release_logtext,
calculate_track_logtext,
Expand Down Expand Up @@ -98,9 +101,13 @@
"CachedRelease",
"CachedTrack",
"Config",
"DescriptorEntry",
"GenreEntry",
"LabelEntry",
"MetadataAction",
"MetadataMatcher",
"MetadataRule",
"PathContext",
"PathTemplate",
"RoseError",
"RoseExpectedError",
Expand All @@ -125,7 +132,6 @@
"descriptor_exists",
"dump_all_collages",
"dump_all_playlists",
"PathContext",
"dump_all_releases",
"dump_all_tracks",
"dump_collage",
Expand Down
73 changes: 60 additions & 13 deletions rose/cache.py
Original file line number Diff line number Diff line change
Expand Up @@ -2273,15 +2273,27 @@ def artist_exists(c: Config, artist: str) -> bool:
return bool(cursor.fetchone()[0])


def list_genres(c: Config) -> list[str]:
@dataclass(frozen=True)
class GenreEntry:
genre: str
only_new_releases: bool


def list_genres(c: Config) -> list[GenreEntry]:
with connect(c) as conn:
cursor = conn.execute("SELECT DISTINCT genre FROM releases_genres")
rval = set()
query = """
SELECT rg.genre, MIN(r.id) AS has_non_new_release
FROM releases_genres rg
LEFT JOIN releases r ON r.id = rg.release_id AND NOT r.new
GROUP BY rg.genre
"""
cursor = conn.execute(query)
rval: dict[str, bool] = {}
for row in cursor:
genre = row["genre"]
rval.add(genre)
rval.update(TRANSIENT_PARENT_GENRES.get(genre, []))
return list(rval)
rval[row["genre"]] = row["has_non_new_release"] is None
for g in TRANSIENT_PARENT_GENRES.get(row["genre"], []):
rval[g] = rval.get(g, False) or row["has_non_new_release"] is None
return [GenreEntry(genre=k, only_new_releases=v) for k, v in rval.items()]


def genre_exists(c: Config, genre: str) -> bool:
Expand All @@ -2295,10 +2307,29 @@ def genre_exists(c: Config, genre: str) -> bool:
return bool(cursor.fetchone()[0])


def list_descriptors(c: Config) -> list[str]:
@dataclass(frozen=True)
class DescriptorEntry:
descriptor: str
only_new_releases: bool


def list_descriptors(c: Config) -> list[DescriptorEntry]:
with connect(c) as conn:
cursor = conn.execute("SELECT DISTINCT descriptor FROM releases_descriptors")
return [row["descriptor"] for row in cursor]
cursor = conn.execute(
"""
SELECT rg.descriptor, MIN(r.id) AS has_non_new_release
FROM releases_descriptors rg
LEFT JOIN releases r ON r.id = rg.release_id AND NOT r.new
GROUP BY rg.descriptor
"""
)
return [
DescriptorEntry(
descriptor=row["descriptor"],
only_new_releases=row["has_non_new_release"] is None,
)
for row in cursor
]


def descriptor_exists(c: Config, descriptor: str) -> bool:
Expand All @@ -2310,10 +2341,26 @@ def descriptor_exists(c: Config, descriptor: str) -> bool:
return bool(cursor.fetchone()[0])


def list_labels(c: Config) -> list[str]:
@dataclass(frozen=True)
class LabelEntry:
label: str
only_new_releases: bool


def list_labels(c: Config) -> list[LabelEntry]:
with connect(c) as conn:
cursor = conn.execute("SELECT DISTINCT label FROM releases_labels")
return [row["label"] for row in cursor]
cursor = conn.execute(
"""
SELECT rg.label, MIN(r.id) AS has_non_new_release
FROM releases_labels rg
LEFT JOIN releases r ON r.id = rg.release_id AND NOT r.new
GROUP BY rg.label
"""
)
return [
LabelEntry(label=row["label"], only_new_releases=row["has_non_new_release"] is None)
for row in cursor
]


def label_exists(c: Config, label: str) -> bool:
Expand Down
40 changes: 25 additions & 15 deletions rose/cache_test.py
Original file line number Diff line number Diff line change
Expand Up @@ -16,6 +16,9 @@
CachedPlaylist,
CachedRelease,
CachedTrack,
DescriptorEntry,
GenreEntry,
LabelEntry,
_unpack,
artist_exists,
collage_exists,
Expand Down Expand Up @@ -1151,7 +1154,7 @@ def test_list_releases(config: Config) -> None:
compositiondate=None,
catalognumber="DG-001",
disctotal=1,
new=False,
new=True,
genres=["Classical"],
parent_genres=[],
labels=["Native State"],
Expand Down Expand Up @@ -1180,7 +1183,7 @@ def test_list_releases(config: Config) -> None:
compositiondate=RoseDate(1780),
catalognumber="DG-002",
disctotal=1,
new=True,
new=False,
genres=[],
parent_genres=[],
labels=[],
Expand Down Expand Up @@ -1426,7 +1429,7 @@ def test_list_tracks(config: Config) -> None:
releasedate=RoseDate(2021),
compositiondate=None,
catalognumber="DG-001",
new=False,
new=True,
disctotal=1,
genres=["Classical"],
parent_genres=[],
Expand Down Expand Up @@ -1467,7 +1470,7 @@ def test_list_tracks(config: Config) -> None:
releasedate=RoseDate(2021, 4, 20),
compositiondate=RoseDate(1780),
catalognumber="DG-002",
new=True,
new=False,
disctotal=1,
genres=[],
parent_genres=[],
Expand Down Expand Up @@ -1580,26 +1583,33 @@ def test_list_artists(config: Config) -> None:
def test_list_genres(config: Config) -> None:
genres = list_genres(config)
assert set(genres) == {
"Techno",
"Deep House",
"Classical",
"Dance",
"Electronic",
"Electronic Dance Music",
"House",
GenreEntry("Techno", False),
GenreEntry("Deep House", False),
GenreEntry("Classical", True),
GenreEntry("Dance", False),
GenreEntry("Electronic", False),
GenreEntry("Electronic Dance Music", False),
GenreEntry("House", False),
}


@pytest.mark.usefixtures("seeded_cache")
def test_list_descriptors(config: Config) -> None:
descriptors = list_descriptors(config)
assert set(descriptors) == {"Warm", "Hot", "Wet"}
assert set(descriptors) == {
DescriptorEntry("Warm", False),
DescriptorEntry("Hot", False),
DescriptorEntry("Wet", True),
}


@pytest.mark.usefixtures("seeded_cache")
def test_list_labels(config: Config) -> None:
labels = list_labels(config)
assert set(labels) == {"Silk Music", "Native State"}
assert set(labels) == {
LabelEntry("Silk Music", False),
LabelEntry("Native State", True),
}


@pytest.mark.usefixtures("seeded_cache")
Expand Down Expand Up @@ -1665,7 +1675,7 @@ def test_get_collage(config: Config) -> None:
releasedate=RoseDate(2021),
compositiondate=None,
catalognumber="DG-001",
new=False,
new=True,
disctotal=1,
genres=["Classical"],
parent_genres=[],
Expand Down Expand Up @@ -1791,7 +1801,7 @@ def test_get_playlist(config: Config) -> None:
releasedate=RoseDate(2021),
compositiondate=None,
catalognumber="DG-001",
new=False,
new=True,
disctotal=1,
genres=["Classical"],
parent_genres=[],
Expand Down
4 changes: 2 additions & 2 deletions rose/collages_test.py
Original file line number Diff line number Diff line change
Expand Up @@ -180,7 +180,7 @@ def test_dump_collage(config: Config) -> None:
"releasedate": "2021",
"compositiondate": None,
"catalognumber": "DG-001",
"new": False,
"new": True,
"disctotal": 1,
"genres": ["Classical"],
"parent_genres": [],
Expand Down Expand Up @@ -270,7 +270,7 @@ def test_dump_collages(config: Config) -> None:
"releasedate": "2021",
"compositiondate": None,
"catalognumber": "DG-001",
"new": False,
"new": True,
"disctotal": 1,
"genres": ["Classical"],
"parent_genres": [],
Expand Down
47 changes: 47 additions & 0 deletions rose/config.py
Original file line number Diff line number Diff line change
Expand Up @@ -78,6 +78,10 @@ class Config:
fuse_descriptors_blacklist: list[str] | None
fuse_labels_blacklist: list[str] | None

hide_genres_with_only_new_releases: bool
hide_descriptors_with_only_new_releases: bool
hide_labels_with_only_new_releases: bool

cover_art_stems: list[str]
valid_art_exts: list[str]

Expand Down Expand Up @@ -307,6 +311,46 @@ def parse(cls, config_path_override: Path | None = None) -> Config:
f"Cannot specify both fuse_labels_whitelist and fuse_labels_blacklist in configuration file ({cfgpath}): must specify only one or the other"
)

try:
hide_genres_with_only_new_releases = data["hide_genres_with_only_new_releases"]
del data["hide_genres_with_only_new_releases"]
if not isinstance(hide_genres_with_only_new_releases, bool):
raise ValueError(f"Must be a bool: got {type(hide_genres_with_only_new_releases)}")
except KeyError:
hide_genres_with_only_new_releases = False
except ValueError as e:
raise InvalidConfigValueError(
f"Invalid value for hide_genres_with_only_new_releases in configuration file ({cfgpath}): {e}"
) from e

try:
hide_descriptors_with_only_new_releases = data[
"hide_descriptors_with_only_new_releases"
]
del data["hide_descriptors_with_only_new_releases"]
if not isinstance(hide_descriptors_with_only_new_releases, bool):
raise ValueError(
f"Must be a bool: got {type(hide_descriptors_with_only_new_releases)}"
)
except KeyError:
hide_descriptors_with_only_new_releases = False
except ValueError as e:
raise InvalidConfigValueError(
f"Invalid value for hide_descriptors_with_only_new_releases in configuration file ({cfgpath}): {e}"
) from e

try:
hide_labels_with_only_new_releases = data["hide_labels_with_only_new_releases"]
del data["hide_labels_with_only_new_releases"]
if not isinstance(hide_labels_with_only_new_releases, bool):
raise ValueError(f"Must be a bool: got {type(hide_labels_with_only_new_releases)}")
except KeyError:
hide_labels_with_only_new_releases = False
except ValueError as e:
raise InvalidConfigValueError(
f"Invalid value for hide_labels_with_only_new_releases in configuration file ({cfgpath}): {e}"
) from e

try:
cover_art_stems = data["cover_art_stems"]
del data["cover_art_stems"]
Expand Down Expand Up @@ -515,6 +559,9 @@ def parse(cls, config_path_override: Path | None = None) -> Config:
fuse_genres_blacklist=fuse_genres_blacklist,
fuse_descriptors_blacklist=fuse_descriptors_blacklist,
fuse_labels_blacklist=fuse_labels_blacklist,
hide_genres_with_only_new_releases=hide_genres_with_only_new_releases,
hide_descriptors_with_only_new_releases=hide_descriptors_with_only_new_releases,
hide_labels_with_only_new_releases=hide_labels_with_only_new_releases,
cover_art_stems=cover_art_stems,
valid_art_exts=valid_art_exts,
max_filename_bytes=max_filename_bytes,
Expand Down
Loading

0 comments on commit d2f30a0

Please sign in to comment.