Skip to content

Commit

Permalink
add current artist/genre/label/collage/playlist to the path templates
Browse files Browse the repository at this point in the history
  • Loading branch information
azuline committed Apr 26, 2024
1 parent 6a4b3fd commit 519a647
Show file tree
Hide file tree
Showing 4 changed files with 100 additions and 16 deletions.
10 changes: 10 additions & 0 deletions docs/TEMPLATES.md
Original file line number Diff line number Diff line change
Expand Up @@ -99,6 +99,11 @@ releaseartists.composer: list[Artist]
releaseartists.conductor: list[Artist]
releaseartists.djmixer: list[Artist]
position: str # If in a collage context, the zero-padded position of the release in the collage.
context.genre: str # The current genre being viewed in the Virtual Filesystem.
context.label: str # The current label being viewed in the Virtual Filesystem.
context.artist: str # The current artist being viewed in the Virtual Filesystem.
context.collage: str # The current collage being viewed in the Virtual Filesystem.
context.playlist: str # The current playlist being viewed in the Virtual Filesystem.
```

And provides the template variables for tracks:
Expand Down Expand Up @@ -141,6 +146,11 @@ releaseartists.composer: list[Artist]
releaseartists.conductor: list[Artist]
releaseartists.djmixer: list[Artist]
position: str # If in a playlist context, the zero-padded position of the track in the playlist.
context.genre: str # The current genre being viewed in the Virtual Filesystem.
context.label: str # The current label being viewed in the Virtual Filesystem.
context.artist: str # The current artist being viewed in the Virtual Filesystem.
context.collage: str # The current collage being viewed in the Virtual Filesystem.
context.playlist: str # The current playlist being viewed in the Virtual Filesystem.
```

Rosé also provides the following custom filters:
Expand Down
31 changes: 23 additions & 8 deletions rose/templates.py
Original file line number Diff line number Diff line change
Expand Up @@ -251,21 +251,36 @@ def parse(self) -> None:
raise InvalidPathTemplateError(f"Failed to compile template: {e}", key=key) from e


@dataclasses.dataclass
class PathContext:
genre: str | None
artist: str | None
label: str | None
collage: str | None
playlist: str | None


def eval_release_template(
template: PathTemplate,
release: CachedRelease,
context: PathContext | None = None,
position: str | None = None,
) -> str:
return _collapse_spacing(template.compiled.render(**_calc_release_variables(release, position)))
return _collapse_spacing(
template.compiled.render(context=context, **_calc_release_variables(release, position))
)


def eval_track_template(
template: PathTemplate,
track: CachedTrack,
context: PathContext | None = None,
position: str | None = None,
) -> str:
return (
_collapse_spacing(template.compiled.render(**_calc_track_variables(track, position)))
_collapse_spacing(
template.compiled.render(context=context, **_calc_track_variables(track, position))
)
+ track.source_path.suffix
)

Expand Down Expand Up @@ -480,11 +495,11 @@ def _preview_release_template(c: Config, label: str, template: PathTemplate) ->
kimlip, youngforever, debussy = _get_preview_releases(c)
click.secho(f"{label}:", dim=True, underline=True)
click.secho(" Sample 1: ", dim=True, nl=False)
click.secho(eval_release_template(template, kimlip, "1"))
click.secho(eval_release_template(template, kimlip, position="1"))
click.secho(" Sample 2: ", dim=True, nl=False)
click.secho(eval_release_template(template, youngforever, "2"))
click.secho(eval_release_template(template, youngforever, position="2"))
click.secho(" Sample 3: ", dim=True, nl=False)
click.secho(eval_release_template(template, debussy, "3"))
click.secho(eval_release_template(template, debussy, position="3"))


def _preview_track_template(c: Config, label: str, template: PathTemplate) -> None:
Expand All @@ -509,7 +524,7 @@ def _preview_track_template(c: Config, label: str, template: PathTemplate) -> No
metahash="0",
release=kimlip,
)
click.secho(eval_track_template(template, track, "1"))
click.secho(eval_track_template(template, track, position="1"))

click.secho(" Sample 2: ", dim=True, nl=False)
track = CachedTrack(
Expand All @@ -527,7 +542,7 @@ def _preview_track_template(c: Config, label: str, template: PathTemplate) -> No
metahash="0",
release=youngforever,
)
click.secho(eval_track_template(template, track, "2"))
click.secho(eval_track_template(template, track, position="2"))

click.secho(" Sample 3: ", dim=True, nl=False)
track = CachedTrack(
Expand All @@ -549,4 +564,4 @@ def _preview_track_template(c: Config, label: str, template: PathTemplate) -> No
metahash="0",
release=debussy,
)
click.secho(eval_track_template(template, track, "3"))
click.secho(eval_track_template(template, track, position="3"))
11 changes: 7 additions & 4 deletions rose/templates_test.py
Original file line number Diff line number Diff line change
Expand Up @@ -73,23 +73,26 @@ def test_default_templates() -> None:
== "A1, A2 & A3 (feat. BB) (prod. PP) - 2023. Title - Single"
)
assert (
eval_release_template(templates.collages.release, release, "4")
eval_release_template(templates.collages.release, release, position="4")
== "4. A1, A2 & A3 (feat. BB) (prod. PP) - 2023. Title - Single"
)

release = deepcopy(EMPTY_CACHED_RELEASE)
release.releasetitle = "Title"
assert eval_release_template(templates.source.release, release) == "Unknown Artists - Title"
assert (
eval_release_template(templates.collages.release, release, "4")
eval_release_template(templates.collages.release, release, position="4")
== "4. Unknown Artists - Title"
)

track = deepcopy(EMPTY_CACHED_TRACK)
track.tracknumber = "2"
track.tracktitle = "Trick"
assert eval_track_template(templates.source.track, track) == "02. Trick.m4a"
assert eval_track_template(templates.playlists, track, "4") == "4. Unknown Artists - Trick.m4a"
assert (
eval_track_template(templates.playlists, track, position="4")
== "4. Unknown Artists - Trick.m4a"
)

track = deepcopy(EMPTY_CACHED_TRACK)
track.release.disctotal = 2
Expand All @@ -105,7 +108,7 @@ def test_default_templates() -> None:
== "04-02. Trick (feat. Hi, High & Hye).m4a"
)
assert (
eval_track_template(templates.playlists, track, "4")
eval_track_template(templates.playlists, track, position="4")
== "4. Main (feat. Hi, High & Hye) - Trick.m4a"
)

Expand Down
64 changes: 60 additions & 4 deletions rose_vfs/virtualfs.py
Original file line number Diff line number Diff line change
Expand Up @@ -104,6 +104,7 @@
update_cache_for_releases,
)
from rose.cache import list_releases_delete_this
from rose.templates import PathContext

logger = logging.getLogger(__name__)

Expand Down Expand Up @@ -226,6 +227,16 @@ def label_parent(self) -> VirtualPath:
"""Parent path of a label: Used as an input to the Sanitizer."""
return VirtualPath(view=self.view)

@property
def collage_parent(self) -> VirtualPath:
"""Parent path of a collage: Used as an input to the Sanitizer."""
return VirtualPath(view=self.view)

@property
def playlist_parent(self) -> VirtualPath:
"""Parent path of a playlist: Used as an input to the Sanitizer."""
return VirtualPath(view=self.view)

@classmethod
def parse(cls, path: Path) -> VirtualPath:
parts = str(path.resolve()).split("/")[1:] # First part is always empty string.
Expand Down Expand Up @@ -355,9 +366,10 @@ class VirtualNameGenerator:
paths, new paths will take precedence.
"""

def __init__(self, config: Config):
def __init__(self, config: Config, sanitizer: Sanitizer):
# fmt: off
self._config = config
self._sanitizer = sanitizer
# These are the stateful maps that we use to remember path mappings. They are maps from the
# (parent_path, virtual path) -> entity ID.
#
Expand Down Expand Up @@ -423,7 +435,29 @@ def list_release_paths(
f"VNAMES: Reused cached virtual dirname {vname} for release {logtext} in {time.time()-time_start} seconds"
)
except KeyError:
vname = eval_release_template(template, release, position)
context = PathContext(
genre=self._sanitizer.unsanitize(
release_parent.genre,
release_parent.genre_parent,
)
if release_parent.genre
else None,
label=self._sanitizer.unsanitize(
release_parent.label,
release_parent.label_parent,
)
if release_parent.label
else None,
artist=self._sanitizer.unsanitize(
release_parent.artist,
release_parent.artist_parent,
)
if release_parent.artist
else None,
collage=release_parent.collage,
playlist=None,
)
vname = eval_release_template(template, release, context, position)
vname = sanitize_dirname(self._config, vname, False)
self._release_template_eval_cache[cachekey] = vname
logger.debug(
Expand Down Expand Up @@ -501,7 +535,29 @@ def list_track_paths(
try:
vname = self._track_template_eval_cache[cachekey]
except KeyError:
vname = eval_track_template(template, track, position)
context = PathContext(
genre=self._sanitizer.unsanitize(
track_parent.genre,
track_parent.genre_parent,
)
if track_parent.genre
else None,
label=self._sanitizer.unsanitize(
track_parent.label,
track_parent.label_parent,
)
if track_parent.label
else None,
artist=self._sanitizer.unsanitize(
track_parent.artist,
track_parent.artist_parent,
)
if track_parent.artist
else None,
collage=track_parent.collage,
playlist=track_parent.playlist,
)
vname = eval_track_template(template, track, context, position)
vname = sanitize_filename(self._config, vname, False)
logger.debug(
f"VNAMES: Generated virtual filename {vname} for track {logtext} in {time.time() - time_start} seconds"
Expand Down Expand Up @@ -696,8 +752,8 @@ class RoseLogicalCore:
def __init__(self, config: Config, fhandler: FileHandleManager):
self.config = config
self.fhandler = fhandler
self.vnames = VirtualNameGenerator(config)
self.sanitizer = Sanitizer(config, self)
self.vnames = VirtualNameGenerator(config, self.sanitizer)
self.can_show = CanShower(config)
# This map stores the state for "file creation" operations. We currently have two file
# creation operations:
Expand Down

0 comments on commit 519a647

Please sign in to comment.