Skip to content

Commit

Permalink
stuff
Browse files Browse the repository at this point in the history
  • Loading branch information
azuline committed May 6, 2024
1 parent c1e00f1 commit 3645a07
Show file tree
Hide file tree
Showing 7 changed files with 69 additions and 23 deletions.
2 changes: 2 additions & 0 deletions conftest.py
Original file line number Diff line number Diff line change
Expand Up @@ -227,6 +227,7 @@ def _seed_cache(config: Config, mkfiles: bool) -> None:
, label
, releaseartist
, trackartist
, new
)
SELECT
t.rowid
Expand All @@ -246,6 +247,7 @@ def _seed_cache(config: Config, mkfiles: bool) -> None:
, process_string_for_fts(COALESCE(GROUP_CONCAT(rl.label, ' '), '')) AS label
, process_string_for_fts(COALESCE(GROUP_CONCAT(ra.artist, ' '), '')) AS releaseartist
, process_string_for_fts(COALESCE(GROUP_CONCAT(ta.artist, ' '), '')) AS trackartist
, process_string_for_fts(CASE WHEN r.new THEN 'true' ELSE 'false' END) AS new
FROM tracks t
JOIN releases r ON r.id = t.release_id
LEFT JOIN releases_genres rg ON rg.release_id = r.id
Expand Down
3 changes: 3 additions & 0 deletions docs/METADATA_TOOLS.md
Original file line number Diff line number Diff line change
Expand Up @@ -327,12 +327,15 @@ The rules engine supports matching and acting on the following tags:
- `label`
- `catalognumber`
- `edition`
- `new`

The `trackartist[*]`, `releaseartist[*]`, `genre` (& parents), `secondarygenre` (& parents),
`descriptor`, 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 this difference in the [Actions](#actions)
section.

The `new` tag will always be the string `true` or `false`.

For convenience, the rules parser also allows you to specify _tag aliases_ in
place of the above tags, which expand to multiple tags when matching. The
supported aliases are:
Expand Down
2 changes: 2 additions & 0 deletions rose/cache.py
Original file line number Diff line number Diff line change
Expand Up @@ -1243,6 +1243,7 @@ def _update_cache_for_releases_executor(
, label
, releaseartist
, trackartist
, new
)
SELECT
t.rowid
Expand All @@ -1264,6 +1265,7 @@ def _update_cache_for_releases_executor(
, process_string_for_fts(COALESCE(GROUP_CONCAT(rl.label, ' '), '')) AS label
, process_string_for_fts(COALESCE(GROUP_CONCAT(ra.artist, ' '), '')) AS releaseartist
, process_string_for_fts(COALESCE(GROUP_CONCAT(ta.artist, ' '), '')) AS trackartist
, process_string_for_fts(CASE WHEN r.new THEN 'true' ELSE 'false' END) AS new
FROM tracks t
JOIN releases r ON r.id = t.release_id
LEFT JOIN releases_genres rg ON rg.release_id = r.id
Expand Down
1 change: 1 addition & 0 deletions rose/cache.sql
Original file line number Diff line number Diff line change
Expand Up @@ -183,6 +183,7 @@ CREATE VIRTUAL TABLE rules_engine_fts USING fts5 (
, label
, releaseartist
, trackartist
, new
-- Use standard unicode tokenizer; do not remove diacritics; treat everything we know as token.
-- Except for the ¬, which is our "separator." We use that separator to produce single-character
-- tokens.
Expand Down
7 changes: 6 additions & 1 deletion rose/rule_parser.py
Original file line number Diff line number Diff line change
Expand Up @@ -7,11 +7,11 @@

from __future__ import annotations

from collections.abc import Sequence
import io
import logging
import re
import shlex
from collections.abc import Sequence
from dataclasses import dataclass
from typing import Literal

Expand Down Expand Up @@ -75,6 +75,7 @@ def __str__(self) -> str:
"secondarygenre",
"descriptor",
"label",
"new",
]

ExpandableTag = Tag | Literal["artist", "trackartist", "releaseartist"]
Expand Down Expand Up @@ -130,6 +131,7 @@ def __str__(self) -> str:
"secondarygenre": ["secondarygenre"],
"descriptor": ["descriptor"],
"label": ["label"],
"new": ["new"],
"artist": [
"trackartist[main]",
"trackartist[guest]",
Expand Down Expand Up @@ -177,6 +179,7 @@ def __str__(self) -> str:
"secondarygenre",
"descriptor",
"label",
"new",
]

SINGLE_VALUE_TAGS: list[Tag] = [
Expand All @@ -192,6 +195,7 @@ def __str__(self) -> str:
"compositiondate",
"edition",
"catalognumber",
"new",
]

RELEASE_TAGS: list[Tag] = [
Expand All @@ -215,6 +219,7 @@ def __str__(self) -> str:
"descriptor",
"label",
"disctotal",
"new",
]


Expand Down
6 changes: 3 additions & 3 deletions rose/rule_parser_test.py
Original file line number Diff line number Diff line change
Expand Up @@ -77,7 +77,7 @@ def test_err(rule: str, err: str) -> None:
tracknumber^Track$
^
Invalid tag: must be one of {tracktitle, trackartist, trackartist[main], trackartist[guest], trackartist[remixer], trackartist[producer], trackartist[composer], trackartist[conductor], trackartist[djmixer], tracknumber, tracktotal, discnumber, disctotal, releasetitle, releaseartist, releaseartist[main], releaseartist[guest], releaseartist[remixer], releaseartist[producer], releaseartist[composer], releaseartist[conductor], releaseartist[djmixer], releasetype, releasedate, originaldate, compositiondate, edition, catalognumber, genre, secondarygenre, descriptor, label, artist}. The next character after a tag must be ':' or ','.
Invalid tag: must be one of {tracktitle, trackartist, trackartist[main], trackartist[guest], trackartist[remixer], trackartist[producer], trackartist[composer], trackartist[conductor], trackartist[djmixer], tracknumber, tracktotal, discnumber, disctotal, releasetitle, releaseartist, releaseartist[main], releaseartist[guest], releaseartist[remixer], releaseartist[producer], releaseartist[composer], releaseartist[conductor], releaseartist[djmixer], releasetype, releasedate, originaldate, compositiondate, edition, catalognumber, genre, secondarygenre, descriptor, label, new, artist}. The next character after a tag must be ':' or ','.
""",
)

Expand Down Expand Up @@ -250,7 +250,7 @@ def test_err(rule: str, err: str, matcher: MetadataMatcher | None = None) -> Non
haha/delete
^
Invalid tag: must be one of {tracktitle, trackartist, trackartist[main], trackartist[guest], trackartist[remixer], trackartist[producer], trackartist[composer], trackartist[conductor], trackartist[djmixer], tracknumber, discnumber, releasetitle, releaseartist, releaseartist[main], releaseartist[guest], releaseartist[remixer], releaseartist[producer], releaseartist[composer], releaseartist[conductor], releaseartist[djmixer], releasetype, releasedate, originaldate, compositiondate, edition, catalognumber, genre, secondarygenre, descriptor, label, artist}. The next character after a tag must be ':' or ','.
Invalid tag: must be one of {tracktitle, trackartist, trackartist[main], trackartist[guest], trackartist[remixer], trackartist[producer], trackartist[composer], trackartist[conductor], trackartist[djmixer], tracknumber, discnumber, releasetitle, releaseartist, releaseartist[main], releaseartist[guest], releaseartist[remixer], releaseartist[producer], releaseartist[composer], releaseartist[conductor], releaseartist[djmixer], releasetype, releasedate, originaldate, compositiondate, edition, catalognumber, genre, secondarygenre, descriptor, label, new, artist}. The next character after a tag must be ':' or ','.
""",
)

Expand All @@ -261,7 +261,7 @@ def test_err(rule: str, err: str, matcher: MetadataMatcher | None = None) -> Non
tracktitler/delete
^
Invalid tag: must be one of {tracktitle, trackartist, trackartist[main], trackartist[guest], trackartist[remixer], trackartist[producer], trackartist[composer], trackartist[conductor], trackartist[djmixer], tracknumber, discnumber, releasetitle, releaseartist, releaseartist[main], releaseartist[guest], releaseartist[remixer], releaseartist[producer], releaseartist[composer], releaseartist[conductor], releaseartist[djmixer], releasetype, releasedate, originaldate, compositiondate, edition, catalognumber, genre, secondarygenre, descriptor, label, artist}. The next character after a tag must be ':' or ','.
Invalid tag: must be one of {tracktitle, trackartist, trackartist[main], trackartist[guest], trackartist[remixer], trackartist[producer], trackartist[composer], trackartist[conductor], trackartist[djmixer], tracknumber, discnumber, releasetitle, releaseartist, releaseartist[main], releaseartist[guest], releaseartist[remixer], releaseartist[producer], releaseartist[composer], releaseartist[conductor], releaseartist[djmixer], releasetype, releasedate, originaldate, compositiondate, edition, catalognumber, genre, secondarygenre, descriptor, label, new, artist}. The next character after a tag must be ':' or ','.
""",
)

Expand Down
71 changes: 52 additions & 19 deletions rose_vfs/virtualfs.py
Original file line number Diff line number Diff line change
Expand Up @@ -93,6 +93,7 @@
list_playlists,
make_release_logtext,
make_track_logtext,
release_within_collage,
remove_release_from_collage,
remove_track_from_playlist,
rename_collage,
Expand All @@ -105,10 +106,8 @@
track_within_release,
update_cache_for_releases,
)
from rose.cache import (
list_releases_delete_this,
release_within_collage,
)
from rose.cache import list_releases, list_tracks
from rose.releases import find_releases_matching_rule
from rose.rule_parser import MatcherPattern, MetadataMatcher
from rose.tracks import find_tracks_matching_rule

Expand Down Expand Up @@ -1089,17 +1088,33 @@ def readdir(self, p: VirtualPath) -> Iterator[tuple[str, dict[str, Any]]]:
return

if p.release == ALL_TRACKS:
matcher = None
if p.artist:
matcher = MetadataMatcher(tags=["artist"], pattern=MatcherPattern(f"^{p.artist}$"))
matcher = MetadataMatcher(
tags=["artist"],
pattern=MatcherPattern(f"^{p.artist}$"),
)
if p.genre:
matcher = MetadataMatcher(tags=["genre"], pattern=MatcherPattern(f"^{p.genre}$"))
matcher = MetadataMatcher(
tags=["genre"],
pattern=MatcherPattern(f"^{p.genre}$"),
)
if p.descriptor:
matcher = MetadataMatcher(
tags=["descriptor"], pattern=MatcherPattern(f"^{p.descriptor}$")
tags=["descriptor"],
pattern=MatcherPattern(f"^{p.descriptor}$"),
)
if p.label:
matcher = MetadataMatcher(tags=["label"], pattern=MatcherPattern(f"^{p.label}$"))
tracks = find_tracks_matching_rule(self.config, matcher)
matcher = MetadataMatcher(
tags=["label"],
pattern=MatcherPattern(f"^{p.label}$"),
)

tracks = (
find_tracks_matching_rule(self.config, matcher)
if matcher
else list_tracks(self.config)
)
for trk, vname in self.vnames.list_track_paths(p, tracks):
yield vname, self.stat("file", trk.source_path)
return
Expand All @@ -1124,19 +1139,37 @@ def readdir(self, p: VirtualPath) -> Iterator[tuple[str, dict[str, Any]]]:
or p.label
or p.view in ["Releases", "New", "Added On", "Released On"]
):
# fmt: off
releases = list_releases_delete_this(
self.config,
artist_filter=self.sanitizer.unsanitize(p.artist, p.artist_parent) if p.artist else None,
genre_filter=self.sanitizer.unsanitize(p.genre, p.genre_parent) if p.genre else None,
descriptor_filter=self.sanitizer.unsanitize(p.descriptor, p.descriptor_parent) if p.descriptor else None,
label_filter=self.sanitizer.unsanitize(p.label, p.label_parent) if p.label else None,
new=True if p.view == "New" else None,
matcher = None
if p.artist:
matcher = MetadataMatcher(
tags=["releaseartist"],
pattern=MatcherPattern(f"^{p.artist}$"),
)
if p.genre:
matcher = MetadataMatcher(
tags=["genre"],
pattern=MatcherPattern(f"^{p.genre}$"),
)
if p.descriptor:
matcher = MetadataMatcher(
tags=["descriptor"],
pattern=MatcherPattern(f"^{p.descriptor}$"),
)
if p.label:
matcher = MetadataMatcher(
tags=["label"],
pattern=MatcherPattern(f"^{p.label}$"),
)

releases = (
find_releases_matching_rule(self.config, matcher)
if matcher
else list_releases(self.config)
)
# fmt: on
# TODO: new=True if p.view == "New" else None,
yield ALL_TRACKS, self.stat("dir")
for rls, vname in self.vnames.list_release_paths(p, releases):
yield vname, self.stat("dir", rls.source_path)
yield ALL_TRACKS, self.stat("dir")
return

if p.view == "Artists":
Expand Down

0 comments on commit 3645a07

Please sign in to comment.