Skip to content

Commit

Permalink
Support musicbrainz fields in search and distinct. (Fixes mopidy#42)
Browse files Browse the repository at this point in the history
  • Loading branch information
kingosticks committed Apr 20, 2020
1 parent 9b38637 commit 5246222
Show file tree
Hide file tree
Showing 5 changed files with 169 additions and 13 deletions.
6 changes: 6 additions & 0 deletions CHANGELOG.rst
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,12 @@ Changelog
*********


v3.2.0 (UNRELEASED)
===================

- Support searching by MusicBrainz ID and disc number fields. (#42, PR: #43)


v3.1.1 (2020-01-31)
===================

Expand Down
6 changes: 5 additions & 1 deletion mopidy_local/library.py
Original file line number Diff line number Diff line change
Expand Up @@ -102,7 +102,11 @@ def get_distinct(self, field, query=None):
q = []
for key, values in query.items() if query else []:
q.extend((key, value) for value in values)
return set(schema.list_distinct(self._connect(), field, q))
try:
return set(schema.list_distinct(self._connect(), field, q))
except LookupError as e:
logger.error("Error getting distinct %s: %s", field, e)
return set()

def _connect(self):
if not self._connection:
Expand Down
11 changes: 8 additions & 3 deletions mopidy_local/schema.py
Original file line number Diff line number Diff line change
Expand Up @@ -145,6 +145,7 @@
"genre": "genre = ?",
"performer": "performer_uri = ?",
"max-age": "last_modified >= (strftime('%s', 'now') - ?) * 1000",
"performer": "performer_uri = ?",
}

_SEARCH_FIELDS = {
Expand All @@ -157,11 +158,15 @@
"albumartist",
"genre",
"track_no",
"disc_no",
"date",
"comment",
"musicbrainz_trackid",
"musicbrainz_albumid",
"musicbrainz_artistid",
}

schema_version = 6
schema_version = 7

logger = logging.getLogger(__name__)

Expand Down Expand Up @@ -218,7 +223,7 @@ def list_distinct(c, field, query=tuple()):
elif key in _SEARCH_FIELDS:
terms.append("%s = ?" % key)
else:
raise LookupError("Invalid search field: %s" % key)
raise LookupError("Invalid query field: %s" % key)
params.append(value)
if terms:
sql += " AND " + " AND ".join(terms)
Expand Down Expand Up @@ -273,7 +278,7 @@ def search_tracks(c, query, limit, offset, exact, filters=tuple()):
clauses.append("(%s)" % " AND ".join(f))
params.extend(p)
else:
logger.debug("Skipped SQLite search filter %r", kwargs)
logger.error("Skipped SQLite search filter %r", kwargs)
if clauses:
sql += " AND (%s)" % " OR ".join(clauses)
sql += " LIMIT ? OFFSET ?"
Expand Down
122 changes: 122 additions & 0 deletions mopidy_local/sql/upgrade-v6.sql
Original file line number Diff line number Diff line change
@@ -0,0 +1,122 @@
-- Mopidy-Local-SQLite schema upgrade v6 -> v7

BEGIN EXCLUSIVE TRANSACTION;

CREATE INDEX track_disc_no_index ON track (disc_no);
CREATE INDEX album_musicbrainz_id_index ON album (musicbrainz_id);
CREATE INDEX artist_musicbrainz_id_index ON artist (musicbrainz_id);
CREATE INDEX track_musicbrainz_id_index ON track (musicbrainz_id);

DROP VIEW search;

CREATE VIEW search AS
SELECT docid AS docid,
uri AS uri,
name AS track_name,
album_name AS album,
artist_name AS artist,
composer_name AS composer,
performer_name AS performer,
albumartist_name AS albumartist,
genre AS genre,
track_no AS track_no,
coalesce(date, album_date) AS date,
comment AS comment,
disc_no AS disc_no,
musicbrainz_id AS musicbrainz_trackid,
album_musicbrainz_id AS musicbrainz_albumid,
artist_musicbrainz_id AS musicbrainz_artistid

FROM tracks;

DROP TABLE fts;

CREATE VIRTUAL TABLE fts USING fts3 (
uri,
track_name,
album,
artist,
composer,
performer,
albumartist,
genre,
track_no,
date,
comment,
disc_no,
musicbrainz_trackid,
musicbrainz_albumid,
musicbrainz_artistid
);

DROP TRIGGER track_after_insert;
DROP TRIGGER track_after_update;

CREATE TRIGGER track_after_insert AFTER INSERT ON track
BEGIN
INSERT INTO fts (
docid,
uri,
track_name,
album,
artist,
composer,
performer,
albumartist,
genre,
track_no,
date,
comment,
disc_no,
musicbrainz_trackid,
musicbrainz_albumid,
musicbrainz_artistid
) SELECT * FROM search WHERE docid = new.rowid;
END;

CREATE TRIGGER track_after_update AFTER UPDATE ON track
BEGIN
INSERT INTO fts (
docid,
uri,
track_name,
album,
artist,
composer,
performer,
albumartist,
genre,
track_no,
date,
comment,
disc_no,
musicbrainz_trackid,
musicbrainz_albumid,
musicbrainz_artistid
) SELECT * FROM search WHERE docid = new.rowid;
END;

-- update date

INSERT INTO fts (
docid,
uri,
track_name,
album,
artist,
composer,
performer,
albumartist,
genre,
track_no,
date,
comment,
disc_no,
musicbrainz_trackid,
musicbrainz_albumid,
musicbrainz_artistid
) SELECT * FROM search;

PRAGMA user_version = 7; -- update schema version

END TRANSACTION;
37 changes: 28 additions & 9 deletions tests/test_schema.py
Original file line number Diff line number Diff line change
Expand Up @@ -10,11 +10,11 @@

class SchemaTest(unittest.TestCase):
artists = [
Artist(uri="local:artist:0", name="artist #0"),
Artist(uri="local:artist:0", name="artist #0", musicbrainz_id="1234a-987c"),
Artist(uri="local:artist:1", name="artist #1"),
]
albums = [
Album(uri="local:album:0", name="album #0"),
Album(uri="local:album:0", name="album #0", musicbrainz_id="1234a-3421d"),
Album(uri="local:album:1", name="album #1", artists=[artists[0]]),
Album(uri="local:album:2", name="album #2", artists=[artists[1]]),
]
Expand All @@ -29,6 +29,7 @@ class SchemaTest(unittest.TestCase):
album=albums[2],
composers=[artists[0]],
performers=[artists[0]],
musicbrainz_id="1234a-567b",
),
]

Expand All @@ -49,32 +50,50 @@ def test_create(self):
assert len(self.tracks) == len(tracks)

def test_list_distinct(self):
self.assertCountEqual(
self.assertEqual(
[track.name for track in self.tracks],
schema.list_distinct(self.connection, "track_name"),
)
self.assertEqual([], schema.list_distinct(self.connection, "track_no"))
self.assertEqual([], schema.list_distinct(self.connection, "disc_no"))
self.assertEqual(
[album.name for album in self.albums],
schema.list_distinct(self.connection, "album"),
)
self.assertCountEqual(
self.assertEqual(
[artist.name for artist in self.artists[0:2]],
schema.list_distinct(self.connection, "albumartist"),
)
self.assertCountEqual(
self.assertEqual(
[artist.name for artist in self.artists[0:1]],
schema.list_distinct(self.connection, "artist"),
)
self.assertCountEqual(
self.assertEqual(
[artist.name for artist in self.artists[0:1]],
schema.list_distinct(self.connection, "composer"),
)
self.assertCountEqual(
self.assertEqual(
[artist.name for artist in self.artists[0:1]],
schema.list_distinct(self.connection, "performer"),
)
self.assertCountEqual(
self.assertEqual(
[self.tracks[0].date], schema.list_distinct(self.connection, "date")
)
self.assertCountEqual(
self.assertEqual(
[self.tracks[0].genre], schema.list_distinct(self.connection, "genre")
)
self.assertEqual(
[self.tracks[4].musicbrainz_id],
schema.list_distinct(self.connection, "musicbrainz_trackid"),
)
self.assertEqual(
[self.artists[0].musicbrainz_id],
schema.list_distinct(self.connection, "musicbrainz_artistid"),
)
self.assertEqual(
[self.albums[0].musicbrainz_id],
schema.list_distinct(self.connection, "musicbrainz_albumid"),
)

def test_lookup_track(self):
with self.connection as c:
Expand Down

0 comments on commit 5246222

Please sign in to comment.