db: Give Media knowledge about their Tracks & Properties
I expand on the media_view to include additional playlist properties, and configure the default sort order to sort by track number. I then set up the medium_tracks_view to make it easy to select tracks that belong to a specific medium. Signed-off-by: Anna Schumaker <Anna@NoWheyCreamery.com>
This commit is contained in:
parent
8e55de26d1
commit
36ca0b9818
|
@ -223,13 +223,15 @@ CREATE TABLE media (
|
||||||
);
|
);
|
||||||
|
|
||||||
CREATE VIEW media_view AS
|
CREATE VIEW media_view AS
|
||||||
SELECT mediumid, propertyid, albumid, number, name, type, active
|
SELECT mediumid, propertyid, albumid, number, name, type,
|
||||||
|
active, loop, shuffle, sort_order, current_trackid
|
||||||
FROM media
|
FROM media
|
||||||
JOIN playlist_properties USING (propertyid);
|
JOIN playlist_properties USING (propertyid);
|
||||||
|
|
||||||
CREATE TRIGGER media_insert_trigger AFTER INSERT ON media
|
CREATE TRIGGER media_insert_trigger AFTER INSERT ON media
|
||||||
BEGIN
|
BEGIN
|
||||||
INSERT INTO playlist_properties (active) VALUES (False);
|
INSERT INTO playlist_properties (active, sort_order)
|
||||||
|
VALUES (False, "mediumno, number");
|
||||||
UPDATE media SET propertyid = last_insert_rowid()
|
UPDATE media SET propertyid = last_insert_rowid()
|
||||||
WHERE mediumid = NEW.mediumid;
|
WHERE mediumid = NEW.mediumid;
|
||||||
END;
|
END;
|
||||||
|
@ -536,6 +538,13 @@ CREATE VIEW album_tracks_view AS
|
||||||
JOIN libraries USING (libraryid)
|
JOIN libraries USING (libraryid)
|
||||||
WHERE libraries.deleting = False;
|
WHERE libraries.deleting = False;
|
||||||
|
|
||||||
|
CREATE VIEW medium_tracks_view AS
|
||||||
|
SELECT tracks.trackid, media.mediumid
|
||||||
|
FROM tracks
|
||||||
|
JOIN media USING (mediumid)
|
||||||
|
JOIN libraries USING (libraryid)
|
||||||
|
WHERE libraries.deleting = False;
|
||||||
|
|
||||||
|
|
||||||
/****************************************************
|
/****************************************************
|
||||||
* *
|
* *
|
||||||
|
|
|
@ -4,6 +4,7 @@ import sqlite3
|
||||||
from gi.repository import GObject
|
from gi.repository import GObject
|
||||||
from .. import format
|
from .. import format
|
||||||
from . import playlist
|
from . import playlist
|
||||||
|
from . import tracks
|
||||||
|
|
||||||
|
|
||||||
class Medium(playlist.Playlist):
|
class Medium(playlist.Playlist):
|
||||||
|
@ -36,15 +37,28 @@ class Medium(playlist.Playlist):
|
||||||
class Table(playlist.Table):
|
class Table(playlist.Table):
|
||||||
"""Our Media Table."""
|
"""Our Media Table."""
|
||||||
|
|
||||||
|
def __init__(self, sql: GObject.TYPE_PYOBJECT, **kwargs):
|
||||||
|
"""Initialize the Media Table."""
|
||||||
|
super().__init__(sql=sql, autodelete=True,
|
||||||
|
system_tracks=False, **kwargs)
|
||||||
|
|
||||||
def do_construct(self, **kwargs) -> Medium:
|
def do_construct(self, **kwargs) -> Medium:
|
||||||
"""Construct a new medium."""
|
"""Construct a new medium."""
|
||||||
return Medium(**kwargs)
|
return Medium(**kwargs)
|
||||||
|
|
||||||
|
def do_add_track(self, medium: Medium, track: tracks.Track) -> bool:
|
||||||
|
"""Verify adding a Track to the Medium playlist."""
|
||||||
|
return track.get_medium() == medium
|
||||||
|
|
||||||
def do_get_sort_key(self, medium: Medium) -> tuple[int, int, tuple, str]:
|
def do_get_sort_key(self, medium: Medium) -> tuple[int, int, tuple, str]:
|
||||||
"""Get the sort key for a medium."""
|
"""Get the sort key for a medium."""
|
||||||
return (medium.albumid, medium.number,
|
return (medium.albumid, medium.number,
|
||||||
format.sort_key(medium.name), medium.type)
|
format.sort_key(medium.name), medium.type)
|
||||||
|
|
||||||
|
def do_remove_track(self, medium: Medium, track: tracks.Track) -> bool:
|
||||||
|
"""Verify removing a Track from the Medium playlist."""
|
||||||
|
return True
|
||||||
|
|
||||||
def do_sql_delete(self, medium: Medium) -> sqlite3.Cursor:
|
def do_sql_delete(self, medium: Medium) -> sqlite3.Cursor:
|
||||||
"""Delete a medium."""
|
"""Delete a medium."""
|
||||||
return self.sql("DELETE FROM media WHERE mediumid=?",
|
return self.sql("DELETE FROM media WHERE mediumid=?",
|
||||||
|
@ -75,6 +89,11 @@ class Table(playlist.Table):
|
||||||
WHERE albumid=? AND number=? AND type=?""",
|
WHERE albumid=? AND number=? AND type=?""",
|
||||||
album.albumid, number, type)
|
album.albumid, number, type)
|
||||||
|
|
||||||
|
def do_sql_select_trackids(self, medium: Medium) -> sqlite3.Cursor:
|
||||||
|
"""Load a Medium's Tracks from the database."""
|
||||||
|
return self.sql("""SELECT trackid FROM medium_tracks_view
|
||||||
|
WHERE mediumid=?""", medium.mediumid)
|
||||||
|
|
||||||
def do_sql_update(self, medium: Medium,
|
def do_sql_update(self, medium: Medium,
|
||||||
column: str, newval) -> sqlite3.Cursor:
|
column: str, newval) -> sqlite3.Cursor:
|
||||||
"""Update a medium."""
|
"""Update a medium."""
|
||||||
|
|
|
@ -1,5 +1,6 @@
|
||||||
# Copyright 2022 (c) Anna Schumaker.
|
# Copyright 2022 (c) Anna Schumaker.
|
||||||
"""Tests our medium Gio.ListModel."""
|
"""Tests our medium Gio.ListModel."""
|
||||||
|
import pathlib
|
||||||
import unittest.mock
|
import unittest.mock
|
||||||
import emmental.db
|
import emmental.db
|
||||||
import tests.util
|
import tests.util
|
||||||
|
@ -54,10 +55,25 @@ class TestMediumsTable(tests.util.TestCase):
|
||||||
self.album = self.sql.albums.create("Test Album", "Test Artist", "123")
|
self.album = self.sql.albums.create("Test Album", "Test Artist", "123")
|
||||||
self.table = self.sql.media
|
self.table = self.sql.media
|
||||||
|
|
||||||
|
self.library = self.sql.libraries.create(pathlib.Path("/a/b"))
|
||||||
|
self.year = self.sql.years.create(2023)
|
||||||
|
|
||||||
def test_init(self):
|
def test_init(self):
|
||||||
"""Test that the medium model is configured corretly."""
|
"""Test that the medium model is configured corretly."""
|
||||||
self.assertIsInstance(self.table, emmental.db.playlist.Table)
|
self.assertIsInstance(self.table, emmental.db.playlist.Table)
|
||||||
self.assertEqual(len(self.table), 0)
|
self.assertEqual(len(self.table), 0)
|
||||||
|
self.assertTrue(self.table.autodelete)
|
||||||
|
self.assertFalse(self.table.system_tracks)
|
||||||
|
|
||||||
|
def test_add_track(self):
|
||||||
|
"""Test adding a Track to a Medium playlist."""
|
||||||
|
medium = self.table.create(self.album, "", number=1)
|
||||||
|
track = self.sql.tracks.create(self.library, pathlib.Path("1.ogg"),
|
||||||
|
medium, self.year)
|
||||||
|
self.assertTrue(self.table.add_track(medium, track))
|
||||||
|
|
||||||
|
medium2 = self.table.create(self.album, "", number=2)
|
||||||
|
self.assertFalse(self.table.add_track(medium2, track))
|
||||||
|
|
||||||
def test_construct(self):
|
def test_construct(self):
|
||||||
"""Test constructing a medium playlist."""
|
"""Test constructing a medium playlist."""
|
||||||
|
@ -72,6 +88,7 @@ class TestMediumsTable(tests.util.TestCase):
|
||||||
self.assertEqual(medium.name, "Medium 2")
|
self.assertEqual(medium.name, "Medium 2")
|
||||||
self.assertEqual(medium.number, 2)
|
self.assertEqual(medium.number, 2)
|
||||||
self.assertEqual(medium.type, "CD")
|
self.assertEqual(medium.type, "CD")
|
||||||
|
self.assertFalse(medium.tracks_movable)
|
||||||
|
|
||||||
def test_create(self):
|
def test_create(self):
|
||||||
"""Test creating a medium playlist."""
|
"""Test creating a medium playlist."""
|
||||||
|
@ -81,6 +98,7 @@ class TestMediumsTable(tests.util.TestCase):
|
||||||
self.assertEqual(medium1.name, "")
|
self.assertEqual(medium1.name, "")
|
||||||
self.assertEqual(medium1.number, 1)
|
self.assertEqual(medium1.number, 1)
|
||||||
self.assertEqual(medium1.type, "")
|
self.assertEqual(medium1.type, "")
|
||||||
|
self.assertEqual(medium1.sort_order, "mediumno, number")
|
||||||
|
|
||||||
cur = self.sql("SELECT COUNT(name) FROM media")
|
cur = self.sql("SELECT COUNT(name) FROM media")
|
||||||
self.assertEqual(cur.fetchone()["COUNT(name)"], 1)
|
self.assertEqual(cur.fetchone()["COUNT(name)"], 1)
|
||||||
|
@ -117,6 +135,16 @@ class TestMediumsTable(tests.util.TestCase):
|
||||||
|
|
||||||
self.assertFalse(medium.delete())
|
self.assertFalse(medium.delete())
|
||||||
|
|
||||||
|
def test_get_trackids(self):
|
||||||
|
"""Test loading medium tracks from the database."""
|
||||||
|
medium = self.table.create(self.album, "", number=1)
|
||||||
|
track1 = self.sql.tracks.create(self.library, pathlib.Path("1.ogg"),
|
||||||
|
medium, self.year)
|
||||||
|
track2 = self.sql.tracks.create(self.library, pathlib.Path("2.ogg"),
|
||||||
|
medium, self.year)
|
||||||
|
self.assertSetEqual(self.table.get_trackids(medium),
|
||||||
|
{track1.trackid, track2.trackid})
|
||||||
|
|
||||||
def test_filter(self):
|
def test_filter(self):
|
||||||
"""Test filtering medium playlists."""
|
"""Test filtering medium playlists."""
|
||||||
self.table.create(self.album, "Medium 1", number=1)
|
self.table.create(self.album, "Medium 1", number=1)
|
||||||
|
@ -170,6 +198,12 @@ class TestMediumsTable(tests.util.TestCase):
|
||||||
self.assertIsNone(self.table.lookup(self.album, number=3,
|
self.assertIsNone(self.table.lookup(self.album, number=3,
|
||||||
type="Enhanced CD"))
|
type="Enhanced CD"))
|
||||||
|
|
||||||
|
def test_remove_track(self):
|
||||||
|
"""Test removing a Track from the Medium."""
|
||||||
|
medium = self.table.create(self.album, "Test Medium",
|
||||||
|
number=1, type="CD")
|
||||||
|
self.assertTrue(self.table.remove_track(medium, unittest.mock.Mock()))
|
||||||
|
|
||||||
def test_rename(self):
|
def test_rename(self):
|
||||||
"""Test renaming a medium playlist."""
|
"""Test renaming a medium playlist."""
|
||||||
medium1 = self.table.create(self.album, "Medium 1",
|
medium1 = self.table.create(self.album, "Medium 1",
|
||||||
|
@ -191,7 +225,16 @@ class TestMediumsTable(tests.util.TestCase):
|
||||||
medium = self.table.create(self.album, "Test Medium",
|
medium = self.table.create(self.album, "Test Medium",
|
||||||
number=1, type="CD")
|
number=1, type="CD")
|
||||||
medium.active = True
|
medium.active = True
|
||||||
|
medium.loop = "Track"
|
||||||
|
medium.shuffle = True
|
||||||
|
medium.sort_order = "trackid"
|
||||||
|
|
||||||
row = self.sql("""SELECT active FROM playlist_properties
|
row = self.sql("""SELECT active, loop, shuffle,
|
||||||
WHERE propertyid=?""", medium.propertyid).fetchone()
|
sort_order, current_trackid
|
||||||
self.assertEqual(row["active"], True)
|
FROM media_view WHERE mediumid=?""",
|
||||||
|
medium.mediumid).fetchone()
|
||||||
|
self.assertTrue(row["active"])
|
||||||
|
self.assertEqual(row["loop"], "Track")
|
||||||
|
self.assertTrue(row["shuffle"])
|
||||||
|
self.assertEqual(row["sort_order"], "trackid")
|
||||||
|
self.assertIsNone(row["current_trackid"])
|
||||||
|
|
Loading…
Reference in New Issue