2021-08-21 16:47:33 -04:00
|
|
|
# Copyright 2021 (c) Anna Schumaker.
|
|
|
|
#
|
|
|
|
# Table: playlists
|
2021-08-23 13:48:20 -04:00
|
|
|
# +------ ---+-----------+------+------+
|
|
|
|
# | playlistid | plstateid | name | sort |
|
|
|
|
# +-------- -+-----------+------+------+
|
|
|
|
from gi.repository import GObject
|
2021-10-10 13:49:19 -04:00
|
|
|
from . import playlist
|
|
|
|
from . import sql
|
2021-10-14 14:18:36 -04:00
|
|
|
from . import state
|
2021-10-17 16:43:09 -04:00
|
|
|
from . import track
|
2021-08-21 16:47:33 -04:00
|
|
|
|
2021-10-15 10:14:58 -04:00
|
|
|
|
|
|
|
class Collection(playlist.Playlist):
|
|
|
|
def __init__(self, row):
|
|
|
|
playlist.Playlist.__init__(self, row, "media-playback-start")
|
|
|
|
self._name = row["name"]
|
|
|
|
|
2021-10-14 17:29:00 -04:00
|
|
|
def get_n_tracks(self):
|
|
|
|
cur = sql.execute("SELECT COUNT(*) FROM tracks "
|
|
|
|
"JOIN libraries USING(libraryid) WHERE enabled=1")
|
|
|
|
return cur.fetchone()[0]
|
|
|
|
|
2021-10-17 16:43:09 -04:00
|
|
|
def get_track(self, n):
|
|
|
|
order = ', '.join(self.plist_state.sort)
|
|
|
|
row = sql.execute(f"SELECT * FROM tracks "
|
|
|
|
f"INNER JOIN artists USING(artistid) "
|
|
|
|
f"INNER JOIN albums USING(albumid) "
|
|
|
|
f"INNER JOIN discs USING(discid) "
|
|
|
|
f"INNER JOIN libraries USING(libraryid) "
|
|
|
|
f"WHERE libraries.enabled=1 "
|
|
|
|
f"ORDER BY {order} LIMIT 1 OFFSET ?",
|
|
|
|
[ n ]).fetchone()
|
|
|
|
return track.Table.factory(row)
|
|
|
|
|
2021-10-26 17:06:16 -04:00
|
|
|
def get_tracks(self):
|
|
|
|
order = ', '.join(self.plist_state.sort)
|
|
|
|
rows = sql.execute(f"SELECT * FROM tracks "
|
|
|
|
f"INNER JOIN artists USING(artistid) "
|
|
|
|
f"INNER JOIN albums USING(albumid) "
|
|
|
|
f"INNER JOIN discs USING(discid) "
|
|
|
|
f"INNER JOIN libraries USING(libraryid) "
|
|
|
|
f"WHERE libraries.enabled=1 "
|
|
|
|
f"ORDER BY {order}").fetchall()
|
|
|
|
return [ track.Table.factory(row) for row in rows ]
|
|
|
|
|
2021-10-17 21:48:17 -04:00
|
|
|
def get_track_index(self, track):
|
|
|
|
order = ', '.join(self.plist_state.sort)
|
|
|
|
cur = sql.execute(f"SELECT * FROM (SELECT trackid,ROW_NUMBER() "
|
|
|
|
f"OVER (ORDER BY {order}) "
|
|
|
|
f"FROM tracks "
|
|
|
|
f"INNER JOIN artists USING(artistid) "
|
|
|
|
f"INNER JOIN albums USING(albumid) "
|
|
|
|
f"INNER JOIN discs USING(discid) "
|
|
|
|
f"INNER JOIN libraries USING(libraryid) "
|
|
|
|
f"WHERE libraries.enabled=1) "
|
|
|
|
f"WHERE trackid=?", [ track.rowid ])
|
|
|
|
return cur.fetchone()[1] - 1
|
|
|
|
|
2021-10-15 10:14:58 -04:00
|
|
|
@GObject.Property
|
|
|
|
def name(self): return self._name
|
|
|
|
|
|
|
|
|
|
|
|
class UserPlaylist(playlist.MappedPlaylist):
|
|
|
|
def __init__(self, row, icon_name, map_table):
|
|
|
|
playlist.MappedPlaylist.__init__(self, row, icon_name, map_table)
|
2021-10-10 13:49:19 -04:00
|
|
|
self._name = row["name"]
|
2021-08-21 16:47:33 -04:00
|
|
|
|
2021-10-16 18:33:00 -04:00
|
|
|
def delete(self):
|
|
|
|
self.clear()
|
|
|
|
Table.delete(self)
|
2021-11-05 14:03:13 -04:00
|
|
|
sql.commit()
|
2021-10-16 17:37:23 -04:00
|
|
|
|
2021-08-23 13:48:20 -04:00
|
|
|
@GObject.Property
|
2021-10-10 13:49:19 -04:00
|
|
|
def name(self): return self._name
|
2021-08-23 13:48:20 -04:00
|
|
|
|
2021-08-21 16:47:33 -04:00
|
|
|
|
2021-10-15 16:06:02 -04:00
|
|
|
class Previous(UserPlaylist):
|
|
|
|
def __init__(self, row):
|
2021-11-17 12:03:28 -05:00
|
|
|
UserPlaylist.__init__(self, row, "media-skip-backward", "temp_playlist_map")
|
2021-10-15 16:06:02 -04:00
|
|
|
|
|
|
|
def add_track(self, track):
|
2021-11-13 17:33:13 -05:00
|
|
|
if self.get_track_index(track):
|
|
|
|
self.remove_track(track)
|
|
|
|
super().add_track(track)
|
|
|
|
self.current = 0
|
|
|
|
return True
|
|
|
|
|
|
|
|
def next_track(self):
|
|
|
|
self.current = max(-1, self.current - 1)
|
|
|
|
return self.get_current_track()
|
|
|
|
|
|
|
|
def previous_track(self):
|
|
|
|
return super().next_track()
|
2021-10-15 16:06:02 -04:00
|
|
|
|
|
|
|
|
2021-11-17 12:01:23 -05:00
|
|
|
class QueuedTracks(UserPlaylist):
|
|
|
|
def __init__(self, row):
|
2021-11-17 12:03:28 -05:00
|
|
|
UserPlaylist.__init__(self, row, "media-skip-forward", "playlist_map")
|
2021-11-17 12:01:23 -05:00
|
|
|
|
|
|
|
def next_track(self):
|
|
|
|
if track := super().next_track():
|
|
|
|
self.remove_track(track)
|
|
|
|
return track
|
|
|
|
|
|
|
|
|
2021-10-10 13:49:19 -04:00
|
|
|
class UserTable(playlist.Model):
|
2021-08-21 16:47:33 -04:00
|
|
|
def __init__(self):
|
2021-10-10 13:49:19 -04:00
|
|
|
playlist.Model.__init__(self, "playlists", "sort")
|
2021-08-21 16:47:33 -04:00
|
|
|
|
|
|
|
def do_create(self):
|
2021-10-10 13:49:19 -04:00
|
|
|
sql.execute("CREATE TABLE IF NOT EXISTS playlists "
|
|
|
|
"(playlistid INTEGER PRIMARY KEY, "
|
|
|
|
" plstateid INTEGER NOT NULL, "
|
|
|
|
" name TEXT UNIQUE, "
|
|
|
|
" sort TEXT, "
|
|
|
|
" FOREIGN KEY (plstateid) REFERENCES playlist_states(plstateid))")
|
2021-10-17 22:04:22 -04:00
|
|
|
sql.execute(f"CREATE TABLE IF NOT EXISTS playlist_map "
|
|
|
|
"(playlistid INTEGER, "
|
|
|
|
" trackid INTEGER, "
|
|
|
|
" FOREIGN KEY(playlistid) REFERENCES playlists(playlistid), "
|
|
|
|
" FOREIGN KEY(trackid) REFERENCES tracks(trackid), "
|
|
|
|
" UNIQUE(playlistid, trackid))")
|
|
|
|
sql.execute(f"CREATE TEMPORARY TABLE IF NOT EXISTS temp_playlist_map "
|
|
|
|
"(playlistid INTEGER, "
|
|
|
|
" trackid INTEGER, "
|
|
|
|
" FOREIGN KEY(playlistid) REFERENCES playlists(playlistid), "
|
|
|
|
" FOREIGN KEY(trackid) REFERENCES tracks(trackid), "
|
|
|
|
" UNIQUE(playlistid, trackid))")
|
2021-10-10 13:49:19 -04:00
|
|
|
|
|
|
|
self.find("Collection", loop=True)
|
|
|
|
self.find("Favorites")
|
|
|
|
self.find("New Tracks")
|
2021-10-17 16:44:21 -04:00
|
|
|
self.find("Previous", sort=["temp_playlist_map.rowid DESC"])
|
|
|
|
self.find("Queued Tracks", sort=["playlist_map.rowid ASC"])
|
2021-10-10 13:49:19 -04:00
|
|
|
|
2021-10-17 22:04:22 -04:00
|
|
|
def do_drop(self):
|
|
|
|
sql.execute("DROP TABLE playlists")
|
|
|
|
sql.execute("DROP TABLE playlist_map")
|
|
|
|
sql.execute("DROP TABLE temp_playlist_map")
|
|
|
|
|
2021-10-10 13:49:19 -04:00
|
|
|
def do_factory(self, row):
|
2021-12-28 17:19:09 -05:00
|
|
|
match row["name"]:
|
|
|
|
case "Collection":
|
|
|
|
return Collection(row)
|
|
|
|
case "Favorites":
|
|
|
|
return UserPlaylist(row, "emmental-favorites", "playlist_map")
|
|
|
|
case "New Tracks":
|
|
|
|
return UserPlaylist(row, "starred", "temp_playlist_map")
|
|
|
|
case "Previous":
|
|
|
|
return Previous(row)
|
|
|
|
case "Queued Tracks":
|
|
|
|
return QueuedTracks(row)
|
|
|
|
case _:
|
|
|
|
return UserPlaylist(row, "audio-x-generic", "playlist_map")
|
2021-10-10 13:49:19 -04:00
|
|
|
|
|
|
|
def do_insert(self, plstate, name):
|
|
|
|
return sql.execute("INSERT INTO playlists (plstateid, name, sort) "
|
|
|
|
"VALUES (?, ?, ?)", [ plstate.rowid, name, name.casefold() ])
|
2021-08-21 16:47:33 -04:00
|
|
|
|
|
|
|
def do_lookup(self, name):
|
2021-10-10 13:49:19 -04:00
|
|
|
return sql.execute("SELECT * FROM playlists WHERE name=?", [ name ])
|
2021-08-21 16:47:33 -04:00
|
|
|
|
2021-10-14 14:18:36 -04:00
|
|
|
def find(self, name, loop=False, sort=state.DefaultSort):
|
2021-10-10 13:49:19 -04:00
|
|
|
if (res := self.lookup(name)) == None:
|
2021-10-14 14:18:36 -04:00
|
|
|
res = self.insert(name, loop=loop, sort=sort)
|
2021-10-10 13:49:19 -04:00
|
|
|
return res
|
2021-08-23 13:48:20 -04:00
|
|
|
|
2021-08-21 16:47:33 -04:00
|
|
|
|
2021-10-10 13:49:19 -04:00
|
|
|
Table = UserTable()
|