Skip to content

Commit

Permalink
add top-level vfs list for artists/genres/labels
Browse files Browse the repository at this point in the history
  • Loading branch information
azuline committed Oct 10, 2023
1 parent cb56571 commit 16ecf09
Show file tree
Hide file tree
Showing 5 changed files with 73 additions and 15 deletions.
25 changes: 23 additions & 2 deletions rose/cache/read.py
Original file line number Diff line number Diff line change
Expand Up @@ -60,7 +60,28 @@ def list_albums(c: Config) -> Iterator[CachedRelease]:
release_type=row["release_type"],
release_year=row["release_year"],
new=bool(row["new"]),
genres=sorted(row["genres"].split(r" \\ ")),
labels=sorted(row["labels"].split(r" \\ ")),
genres=row["genres"].split(r" \\ "),
labels=row["labels"].split(r" \\ "),
artists=artists,
)


def list_artists(c: Config) -> Iterator[str]:
with connect(c) as conn:
cursor = conn.execute("SELECT DISTINCT artist FROM releases_artists")
for row in cursor:
yield row["artist"]


def list_genres(c: Config) -> Iterator[str]:
with connect(c) as conn:
cursor = conn.execute("SELECT DISTINCT genre FROM releases_genres")
for row in cursor:
yield row["genre"]


def list_labels(c: Config) -> Iterator[str]:
with connect(c) as conn:
cursor = conn.execute("SELECT DISTINCT label FROM releases_labels")
for row in cursor:
yield row["label"]
37 changes: 29 additions & 8 deletions rose/cache/read_test.py
Original file line number Diff line number Diff line change
Expand Up @@ -2,17 +2,17 @@

from rose.cache.database import connect
from rose.cache.dataclasses import CachedArtist, CachedRelease
from rose.cache.read import list_albums
from rose.cache.read import list_albums, list_artists, list_genres, list_labels
from rose.foundation.conf import Config


def seed_data(c: Config) -> None:
with connect(c) as conn:
conn.executescript(
"""\
INSERT INTO releases (id, source_path, title, release_type, release_year, new)
VALUES ('r1', '/tmp/r1', 'Release 1', 'album', 2023, true)
, ('r2', '/tmp/r2', 'Release 2', 'album', 2021, false);
INSERT INTO releases (id, source_path, virtual_dirname, title, release_type, release_year, new)
VALUES ('r1', '/tmp/r1', 'r1', 'Release 1', 'album', 2023, true)
, ('r2', '/tmp/r2', 'r2', 'Release 2', 'album', 2021, false);
INSERT INTO releases_genres (release_id, genre)
VALUES ('r1', 'Techno')
Expand All @@ -23,10 +23,11 @@ def seed_data(c: Config) -> None:
VALUES ('r1', 'Silk Music')
, ('r2', 'Native State');
INSERT INTO tracks (id, source_path, title, release_id, track_number, disc_number, duration_seconds)
VALUES ('t1', '/tmp/r1/01.m4a', 'Track 1', 'r1', '01', '01', 120)
, ('t2', '/tmp/r1/02.m4a', 'Track 2', 'r1', '02', '01', 240)
, ('t3', '/tmp/r2/01.m4a', 'Track 1', 'r2', '01', '01', 120);
INSERT INTO tracks
(id, source_path, virtual_filename, title, release_id, track_number, disc_number, duration_seconds)
VALUES ('t1', '/tmp/r1/01.m4a', '01.m4a', 'Track 1', 'r1', '01', '01', 120)
, ('t2', '/tmp/r1/02.m4a', '02.m4a', 'Track 2', 'r1', '02', '01', 240)
, ('t3', '/tmp/r2/01.m4a', '01.m4a', 'Track 1', 'r2', '01', '01', 120);
INSERT INTO releases_artists (release_id, artist, role)
VALUES ('r1', 'Techno Man', 'main')
Expand All @@ -52,6 +53,7 @@ def test_list_albums(config: Config) -> None:
CachedRelease(
id="r1",
source_path=Path("/tmp/r1"),
virtual_dirname="r1",
title="Release 1",
release_type="album",
release_year=2023,
Expand All @@ -66,6 +68,7 @@ def test_list_albums(config: Config) -> None:
CachedRelease(
id="r2",
source_path=Path("/tmp/r2"),
virtual_dirname="r2",
title="Release 2",
release_type="album",
release_year=2021,
Expand All @@ -78,3 +81,21 @@ def test_list_albums(config: Config) -> None:
],
),
]


def test_list_artists(config: Config) -> None:
seed_data(config)
artists = list(list_artists(config))
assert set(artists) == {"Techno Man", "Bass Man", "Violin Woman", "Conductor Woman"}


def test_list_genres(config: Config) -> None:
seed_data(config)
genres = list(list_genres(config))
assert set(genres) == {"Techno", "Deep House", "Classical"}


def test_list_labels(config: Config) -> None:
seed_data(config)
labels = list(list_labels(config))
assert set(labels) == {"Silk Music", "Native State"}
7 changes: 3 additions & 4 deletions rose/cache/update.py
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,7 @@
from rose.cache.dataclasses import CachedArtist, CachedRelease, CachedTrack
from rose.foundation.conf import Config
from rose.tagger import ArtistTags, AudioFile
from rose.virtualfs.sanitize import sanitize_filename

logger = logging.getLogger(__name__)

Expand Down Expand Up @@ -37,8 +38,6 @@

ID_REGEX = re.compile(r"\{id=([^\}]+)\}$")

ILLEGAL_FS_CHARS_REGEX = re.compile(r'[:\?<>\\*\|"\/]')


def update_cache_for_all_releases(c: Config) -> None:
"""
Expand Down Expand Up @@ -102,7 +101,7 @@ def update_cache_for_release(c: Config, release_dir: Path) -> Path:
virtual_dirname += " [" + ";".join(tags.genre) + "]"
if tags.label:
virtual_dirname += " {" + ";".join(tags.label) + "}"
virtual_dirname = ILLEGAL_FS_CHARS_REGEX.sub("_", virtual_dirname)
virtual_dirname = sanitize_filename(virtual_dirname)

release = CachedRelease(
id=release_id,
Expand Down Expand Up @@ -198,7 +197,7 @@ def update_cache_for_release(c: Config, release_dir: Path) -> Path:
virtual_filename += f" [{tags.duration_sec // 60}{tags.duration_sec % 60:02d}]"
if tags.artists != tags.album_artists:
virtual_filename += " (by " + _format_artists(tags.artists) + ")"
virtual_filename = ILLEGAL_FS_CHARS_REGEX.sub("_", virtual_filename)
virtual_filename = sanitize_filename(virtual_filename)

track = CachedTrack(
id=track_id,
Expand Down
12 changes: 11 additions & 1 deletion rose/virtualfs/__init__.py
Original file line number Diff line number Diff line change
Expand Up @@ -8,8 +8,9 @@

import fuse

from rose.cache.read import list_albums
from rose.cache.read import list_albums, list_artists, list_genres, list_labels
from rose.foundation.conf import Config
from rose.virtualfs.sanitize import sanitize_filename

logger = logging.getLogger(__name__)

Expand Down Expand Up @@ -85,16 +86,25 @@ def readdir(self, path: str, _: Any) -> Iterator[fuse.Direntry]:
if path.startswith("/artists"):
if path == "/artists":
yield from [fuse.Direntry("."), fuse.Direntry("..")]
for artist in list_artists(self.config):
yield fuse.Direntry(sanitize_filename(artist))
return
return

if path.startswith("/genres"):
if path == "/genres":
yield from [fuse.Direntry("."), fuse.Direntry("..")]
for genre in list_genres(self.config):
yield fuse.Direntry(sanitize_filename(genre))
return
return

if path.startswith("/labels"):
if path == "/labels":
yield from [fuse.Direntry("."), fuse.Direntry("..")]
for label in list_labels(self.config):
yield fuse.Direntry(sanitize_filename(label))
return
return


Expand Down
7 changes: 7 additions & 0 deletions rose/virtualfs/sanitize.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
import re

ILLEGAL_FS_CHARS_REGEX = re.compile(r'[:\?<>\\*\|"\/]')


def sanitize_filename(x: str) -> str:
return ILLEGAL_FS_CHARS_REGEX.sub("_", x)

0 comments on commit 16ecf09

Please sign in to comment.