diff --git a/emmental/db/emmental.sql b/emmental/db/emmental.sql index 7f3fe0c..aa044c2 100644 --- a/emmental/db/emmental.sql +++ b/emmental/db/emmental.sql @@ -223,13 +223,15 @@ CREATE TABLE media ( ); 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 JOIN playlist_properties USING (propertyid); CREATE TRIGGER media_insert_trigger AFTER INSERT ON media 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() WHERE mediumid = NEW.mediumid; END; @@ -536,6 +538,13 @@ CREATE VIEW album_tracks_view AS JOIN libraries USING (libraryid) 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; + /**************************************************** * * diff --git a/emmental/db/media.py b/emmental/db/media.py index 341f23e..6d163f3 100644 --- a/emmental/db/media.py +++ b/emmental/db/media.py @@ -4,6 +4,7 @@ import sqlite3 from gi.repository import GObject from .. import format from . import playlist +from . import tracks class Medium(playlist.Playlist): @@ -36,15 +37,28 @@ class Medium(playlist.Playlist): class Table(playlist.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: """Construct a new medium.""" 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]: """Get the sort key for a medium.""" return (medium.albumid, medium.number, 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: """Delete a medium.""" return self.sql("DELETE FROM media WHERE mediumid=?", @@ -75,6 +89,11 @@ class Table(playlist.Table): WHERE albumid=? AND number=? AND 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, column: str, newval) -> sqlite3.Cursor: """Update a medium.""" diff --git a/tests/db/test_media.py b/tests/db/test_media.py index 8d85483..784779b 100644 --- a/tests/db/test_media.py +++ b/tests/db/test_media.py @@ -1,5 +1,6 @@ # Copyright 2022 (c) Anna Schumaker. """Tests our medium Gio.ListModel.""" +import pathlib import unittest.mock import emmental.db import tests.util @@ -54,10 +55,25 @@ class TestMediumsTable(tests.util.TestCase): self.album = self.sql.albums.create("Test Album", "Test Artist", "123") 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): """Test that the medium model is configured corretly.""" self.assertIsInstance(self.table, emmental.db.playlist.Table) 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): """Test constructing a medium playlist.""" @@ -72,6 +88,7 @@ class TestMediumsTable(tests.util.TestCase): self.assertEqual(medium.name, "Medium 2") self.assertEqual(medium.number, 2) self.assertEqual(medium.type, "CD") + self.assertFalse(medium.tracks_movable) def test_create(self): """Test creating a medium playlist.""" @@ -81,6 +98,7 @@ class TestMediumsTable(tests.util.TestCase): self.assertEqual(medium1.name, "") self.assertEqual(medium1.number, 1) self.assertEqual(medium1.type, "") + self.assertEqual(medium1.sort_order, "mediumno, number") cur = self.sql("SELECT COUNT(name) FROM media") self.assertEqual(cur.fetchone()["COUNT(name)"], 1) @@ -117,6 +135,16 @@ class TestMediumsTable(tests.util.TestCase): 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): """Test filtering medium playlists.""" 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, 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): """Test renaming a medium playlist.""" 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", number=1, type="CD") medium.active = True + medium.loop = "Track" + medium.shuffle = True + medium.sort_order = "trackid" - row = self.sql("""SELECT active FROM playlist_properties - WHERE propertyid=?""", medium.propertyid).fetchone() - self.assertEqual(row["active"], True) + row = self.sql("""SELECT active, loop, shuffle, + sort_order, current_trackid + 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"])