Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion pyproject.toml
Original file line number Diff line number Diff line change
Expand Up @@ -14,7 +14,7 @@ classifiers = [
]
dynamic = ["version"]
dependencies = [
"mopidy >= 4.0.0a8",
"mopidy >= 4.0.0a13",
"pykka >= 4.1",
"uritools >= 4.0.3",
]
Expand Down
3 changes: 2 additions & 1 deletion src/mopidy_local/commands.py
Original file line number Diff line number Diff line change
Expand Up @@ -252,7 +252,8 @@ def _scan_metadata( # noqa: PLR0913
media_dir,
)
mtime = file_mtimes.get(absolute_path)
track = tags.convert_tags_to_track(result.tags).replace(
track = tags.convert_tags_to_track(
result.tags,
uri=local_uri,
length=result.duration,
last_modified=mtime,
Expand Down
30 changes: 15 additions & 15 deletions src/mopidy_local/library.py
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,7 @@

import uritools
from mopidy import backend, models
from mopidy.models import Ref, RefType, SearchResult
from mopidy.models import ModelType, Ref, SearchResult
from mopidy.types import Uri

from . import Extension, schema
Expand Down Expand Up @@ -52,11 +52,11 @@ def load(self):
def lookup(self, uri):
try:
if uri.startswith("local:album"):
return list(schema.lookup(self._connect(), RefType.ALBUM, uri))
return list(schema.lookup(self._connect(), ModelType.ALBUM, uri))
if uri.startswith("local:artist"):
return list(schema.lookup(self._connect(), RefType.ARTIST, uri))
return list(schema.lookup(self._connect(), ModelType.ARTIST, uri))
if uri.startswith("local:track"):
return list(schema.lookup(self._connect(), RefType.TRACK, uri))
return list(schema.lookup(self._connect(), ModelType.TRACK, uri))
msg = "Invalid lookup URI"
raise ValueError(msg) # noqa: TRY301
except Exception as e:
Expand Down Expand Up @@ -127,27 +127,27 @@ def _connect(self):
return self._connection

def _browse_album(self, uri, order=("disc_no", "track_no", "name")):
return schema.browse(self._connect(), RefType.TRACK, order, album=uri)
return schema.browse(self._connect(), ModelType.TRACK, order, album=uri)

def _browse_artist(self, uri, order=("type", "name COLLATE NOCASE")):
with self._connect() as c:
albums = schema.browse(c, RefType.ALBUM, order, albumartist=uri)
albums = schema.browse(c, ModelType.ALBUM, order, albumartist=uri)
refs = schema.browse(c, order=order, artist=uri)
album_uris, tracks = {ref.uri for ref in albums}, []
for ref in refs:
if ref.type == RefType.ALBUM and ref.uri not in album_uris:
if ref.type == ModelType.ALBUM and ref.uri not in album_uris:
albums.append(
Ref.directory(
uri=uritools.uricompose(
"local",
None,
"directory",
dict(type=RefType.TRACK, album=ref.uri, artist=uri), # noqa: C408
dict(type=ModelType.TRACK, album=ref.uri, artist=uri), # noqa: C408
),
name=ref.name,
),
)
elif ref.type == RefType.TRACK:
elif ref.type == ModelType.TRACK:
tracks.append(ref)
else:
logger.debug("Skipped SQLite browse result %s", ref.uri)
Expand All @@ -168,29 +168,29 @@ def _browse_directory(self, uri, order=("type", "name COLLATE NOCASE")):

# Fix #38: keep sort order of album tracks; this also applies
# to composers and performers
if type_ == RefType.TRACK and "album" in query:
if type_ == ModelType.TRACK and "album" in query:
order = ("disc_no", "track_no", "name")
if type_ == RefType.ARTIST and self._config["use_artist_sortname"]:
if type_ == ModelType.ARTIST and self._config["use_artist_sortname"]:
order = ("coalesce(sortname, name) COLLATE NOCASE",)
roles = role or ("artist", "albumartist") # TODO: re-think 'roles'...

refs = []
for ref in schema.browse(self._connect(), type_, order, role=roles, **query):
if ref.type == RefType.TRACK or (not query and not role):
if ref.type == ModelType.TRACK or (not query and not role):
refs.append(ref)
elif ref.type == RefType.ALBUM:
elif ref.type == ModelType.ALBUM:
refs.append(
Ref.directory(
uri=uritools.uricompose(
"local",
None,
"directory",
dict(query, type=RefType.TRACK, album=ref.uri),
dict(query, type=ModelType.TRACK, album=ref.uri),
),
name=ref.name,
),
)
elif ref.type == RefType.ARTIST:
elif ref.type == ModelType.ARTIST:
refs.append(
Ref.directory(
uri=uritools.uricompose(
Expand Down
28 changes: 14 additions & 14 deletions src/mopidy_local/schema.py
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,7 @@
import re
import sqlite3

from mopidy.models import Album, Artist, Image, Ref, RefType, Track
from mopidy.models import Album, Artist, Image, ModelType, Ref, Track

_IMAGE_SIZE_RE = re.compile(r".*-(\d+)x(\d+)\.(?:png|gif|jpeg)$")

Expand All @@ -22,28 +22,28 @@
_BROWSE_QUERIES = {
None: f"""
SELECT CASE WHEN album.uri IS NULL THEN
'{RefType.TRACK}' ELSE '{RefType.ALBUM}' END AS type,
'{ModelType.TRACK}' ELSE '{ModelType.ALBUM}' END AS type,
coalesce(album.uri, track.uri) AS uri,
coalesce(album.name, track.name) AS name
FROM track LEFT OUTER JOIN album ON track.album = album.uri
WHERE %s
GROUP BY coalesce(album.uri, track.uri)
ORDER BY %s
""", # noqa: S608
RefType.ALBUM: f"""
SELECT '{RefType.ALBUM}' AS type, uri AS uri, name AS name
ModelType.ALBUM: f"""
SELECT '{ModelType.ALBUM}' AS type, uri AS uri, name AS name
FROM album
WHERE %s
ORDER BY %s
""", # noqa: S608
RefType.ARTIST: f"""
SELECT '{RefType.ARTIST}' AS type, uri AS uri, name AS name
ModelType.ARTIST: f"""
SELECT '{ModelType.ARTIST}' AS type, uri AS uri, name AS name
FROM artist
WHERE %s
ORDER BY %s
""", # noqa: S608
RefType.TRACK: f"""
SELECT '{RefType.TRACK}' AS type, uri AS uri, name AS name
ModelType.TRACK: f"""
SELECT '{ModelType.TRACK}' AS type, uri AS uri, name AS name
FROM track
WHERE %s
ORDER BY %s
Expand All @@ -61,7 +61,7 @@
"performer": "track.performers = ?",
"max-age": "track.last_modified >= (strftime('%s', 'now') - ?) * 1000",
},
RefType.ARTIST: {
ModelType.ARTIST: {
"role": {
"albumartist": """EXISTS (
SELECT * FROM album WHERE album.artists = artist.uri
Expand All @@ -77,7 +77,7 @@
)""",
},
},
RefType.ALBUM: {
ModelType.ALBUM: {
"albumartist": "artists = ?",
"artist": """? IN (
SELECT artists FROM track WHERE album = album.uri
Expand All @@ -101,7 +101,7 @@
AND last_modified >= (strftime('%s', 'now') - ?) * 1000
)""",
},
RefType.TRACK: {
ModelType.TRACK: {
"album": "album = ?",
"albumartist": """? IN (
SELECT artists FROM album WHERE uri = track.album
Expand All @@ -116,13 +116,13 @@
}

_LOOKUP_QUERIES = {
RefType.ALBUM: """
ModelType.ALBUM: """
SELECT * FROM tracks WHERE album_uri = ?
""",
RefType.ARTIST: """
ModelType.ARTIST: """
SELECT * FROM tracks WHERE ? IN (artist_uri, albumartist_uri)
""",
RefType.TRACK: """
ModelType.TRACK: """
SELECT * FROM tracks WHERE uri = ?
""",
}
Expand Down
8 changes: 4 additions & 4 deletions src/mopidy_local/translator.py
Original file line number Diff line number Diff line change
Expand Up @@ -27,19 +27,19 @@ def local_uri_to_path(local_uri: str, media_dir: Path) -> Path:
return media_dir / file_path


def path_to_file_uri(path: str | bytes | Path) -> str:
def path_to_file_uri(path: str | bytes | Path) -> Uri:
"""Convert absolute path to file URI."""
ppath = Path(os.fsdecode(path))
if not ppath.is_absolute():
msg = "Path must be absolute"
raise ValueError(msg)
return ppath.as_uri()
return Uri(ppath.as_uri())


def path_to_local_track_uri(path: str | bytes | Path, media_dir: Path) -> str:
def path_to_local_track_uri(path: str | bytes | Path, media_dir: Path) -> Uri:
"""Convert path to local track URI."""
ppath = Path(os.fsdecode(path))
if ppath.is_absolute():
ppath = ppath.relative_to(media_dir)
quoted_path = urllib.parse.quote(bytes(ppath))
return f"local:track:{quoted_path}"
return Uri(f"local:track:{quoted_path}")
2 changes: 1 addition & 1 deletion tests/test_playback.py
Original file line number Diff line number Diff line change
Expand Up @@ -678,7 +678,7 @@ def test_tracklist_position_at_end_of_playlist(self):

@mock.patch.object(core.PlaybackController, "_on_tracklist_change")
def test_on_tracklist_change_gets_called(self, change_mock):
self.tracklist.add([Track()]).get()
self.tracklist.add([Track(uri="a")]).get()
change_mock.assert_called_once_with()

@populate_tracklist
Expand Down
42 changes: 21 additions & 21 deletions tests/test_schema.py
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@
import unittest
from uuid import UUID

from mopidy.models import Album, Artist, Ref, RefType, Track
from mopidy.models import Album, Artist, ModelType, Ref, Track

from mopidy_local import schema

Expand Down Expand Up @@ -133,26 +133,26 @@ def test_dates(self):
def test_lookup_track(self):
with self.connection as c:
for track in self.tracks:
result = schema.lookup(c, RefType.TRACK, track.uri)
result = schema.lookup(c, ModelType.TRACK, track.uri)
assert [track] == list(result)

def test_lookup_album(self):
with self.connection as c:
result = schema.lookup(c, RefType.ALBUM, self.albums[0].uri)
result = schema.lookup(c, ModelType.ALBUM, self.albums[0].uri)
assert [self.tracks[2]] == list(result)

result = schema.lookup(c, RefType.ALBUM, self.albums[1].uri)
result = schema.lookup(c, ModelType.ALBUM, self.albums[1].uri)
assert [self.tracks[3]] == list(result)

result = schema.lookup(c, RefType.ALBUM, self.albums[2].uri)
result = schema.lookup(c, ModelType.ALBUM, self.albums[2].uri)
assert [self.tracks[4]] == list(result)

def test_lookup_artist(self):
with self.connection as c:
result = schema.lookup(c, RefType.ARTIST, self.artists[0].uri)
result = schema.lookup(c, ModelType.ARTIST, self.artists[0].uri)
assert [self.tracks[1], self.tracks[3]] == list(result)

result = schema.lookup(c, RefType.ARTIST, self.artists[1].uri)
result = schema.lookup(c, ModelType.ARTIST, self.artists[1].uri)
assert [self.tracks[4]] == list(result)

@unittest.SkipTest # TODO: check indexed search
Expand Down Expand Up @@ -208,30 +208,30 @@ def ref(artist):
return Ref.artist(name=artist.name, uri=artist.uri)

with self.connection as c:
assert list(map(ref, self.artists)) == schema.browse(c, RefType.ARTIST)
assert list(map(ref, self.artists)) == schema.browse(c, ModelType.ARTIST)
assert list(map(ref, self.artists)) == schema.browse(
c,
RefType.ARTIST,
ModelType.ARTIST,
role=["artist", "albumartist"],
)
assert list(map(ref, self.artists[0:1])) == schema.browse(
c,
RefType.ARTIST,
ModelType.ARTIST,
role="artist",
)
assert list(map(ref, self.artists[0:1])) == schema.browse(
c,
RefType.ARTIST,
ModelType.ARTIST,
role="composer",
)
assert list(map(ref, self.artists[0:1])) == schema.browse(
c,
RefType.ARTIST,
ModelType.ARTIST,
role="performer",
)
assert list(map(ref, self.artists)) == schema.browse(
c,
RefType.ARTIST,
ModelType.ARTIST,
role="albumartist",
)

Expand All @@ -240,15 +240,15 @@ def ref(album):
return Ref.album(name=album.name, uri=album.uri)

with self.connection as c:
assert list(map(ref, self.albums)) == schema.browse(c, RefType.ALBUM)
assert list(map(ref, self.albums)) == schema.browse(c, ModelType.ALBUM)
assert list(map(ref, [])) == schema.browse(
c,
RefType.ALBUM,
ModelType.ALBUM,
artist=self.artists[0].uri,
)
assert list(map(ref, self.albums[1:2])) == schema.browse(
c,
RefType.ALBUM,
ModelType.ALBUM,
albumartist=self.artists[0].uri,
)

Expand All @@ -257,25 +257,25 @@ def ref(track):
return Ref.track(name=track.name, uri=track.uri)

with self.connection as c:
assert list(map(ref, self.tracks)) == schema.browse(c, RefType.TRACK)
assert list(map(ref, self.tracks)) == schema.browse(c, ModelType.TRACK)
assert list(map(ref, self.tracks[1:2])) == schema.browse(
c,
RefType.TRACK,
ModelType.TRACK,
artist=self.artists[0].uri,
)
assert list(map(ref, self.tracks[2:3])) == schema.browse(
c,
RefType.TRACK,
ModelType.TRACK,
album=self.albums[0].uri,
)
assert list(map(ref, self.tracks[3:4])) == schema.browse(
c,
RefType.TRACK,
ModelType.TRACK,
albumartist=self.artists[0].uri,
)
assert list(map(ref, self.tracks[4:5])) == schema.browse(
c,
RefType.TRACK,
ModelType.TRACK,
composer=self.artists[0].uri,
performer=self.artists[0].uri,
)
Expand Down
14 changes: 10 additions & 4 deletions tests/test_tracklist.py
Original file line number Diff line number Diff line change
Expand Up @@ -135,7 +135,13 @@ def test_filter_by_uri_returns_multiple_matches(self):
assert track == tl_tracks[1].track

def test_filter_by_uri_returns_nothing_if_no_match(self):
self.controller.playlist = Playlist(tracks=[Track(uri="z"), Track(uri="y")])
self.controller.playlist = Playlist(
uri="pl",
tracks=[
Track(uri="z"),
Track(uri="y"),
],
)
assert self.controller.filter({"uri": ["a"]}).get() == []

def test_filter_by_multiple_criteria_returns_elements_matching_all(self):
Expand All @@ -154,9 +160,9 @@ def test_filter_by_multiple_criteria_returns_elements_matching_all(self):
assert t3 == result3[0].track

def test_filter_by_criteria_that_is_not_present_in_all_elements(self):
track1 = Track()
track1 = Track(uri="a")
track2 = Track(uri="b")
track3 = Track()
track3 = Track(uri="c")

self.controller.add([track1, track2, track3])
result = self.controller.filter({"uri": ["b"]}).get()
Expand Down Expand Up @@ -363,5 +369,5 @@ def test_version_does_not_change_when_adding_nothing(self):

def test_version_increases_when_adding_something(self):
version = self.controller.get_version().get()
self.controller.add([Track()])
self.controller.add([Track(uri="a")])
assert version < self.controller.get_version().get()