emmental/playlist/model.py
Anna Schumaker e646b12f65 playlist: Create a SortOptionsModel
Containing all the valid sort options that could be set

Signed-off-by: Anna Schumaker <Anna@NoWheyCreamery.com>
2021-11-26 17:26:09 -05:00

216 lines
7.4 KiB
Python

# Copyright 2021 (c) Anna Schumaker.
import audio
import lib
from gi.repository import GObject
from gi.repository import Gio
from gi.repository import Gtk
from lib import bus
from . import controls
from . import runtime
class PlaylistModel(GObject.GObject, Gio.ListModel):
def __init__(self):
GObject.GObject.__init__(self)
self.playlist = None
self.tracks = [ ]
def do_get_item_type(self): return GObject.TYPE_PYOBJECT
def do_get_n_items(self): return len(self.tracks)
def do_get_item(self, n):
return self.tracks[n] if n < len(self.tracks) else None
def get_playlist(self): return self.playlist
def set_playlist(self, playlist):
if self.playlist:
self.playlist.disconnect_by_func(self.refreshed)
self.playlist.disconnect_by_func(self.track_added)
self.playlist.disconnect_by_func(self.track_removed)
self.playlist = playlist
self.refreshed(playlist)
self.playlist.connect("refreshed", self.refreshed)
self.playlist.connect("track-added", self.track_added)
self.playlist.connect("track-removed", self.track_removed)
def track_added(self, plist, track):
index = plist.get_track_index(track)
self.tracks.insert(index, track)
self.emit("items-changed", index, 0, 1)
def track_removed(self, plist, track, adjusted_current):
index = self.tracks.index(track)
del self.tracks[index]
self.emit("items-changed", index, 1, 0)
def refreshed(self, plist):
rm = len(self.tracks)
self.tracks = plist.get_tracks()
self.emit("items-changed", 0, rm, len(self.tracks))
class Filter(lib.filter.Regex):
def do_match(self, track):
fields = [ f"disc={track.disc.number}",
f"track={track.number}",
f"title={track.title}",
f"artist={track.artist.name}",
f"album={track.album.name}",
f"subtitle={track.disc.subtitle}",
f"year={track.year.year}" ]
return self.search(' & '.join(fields))
PlaylistFilter = Filter()
class FilterPlaylistModel(Gtk.FilterListModel):
def __init__(self):
Gtk.FilterListModel.__init__(self)
self.set_model(PlaylistModel())
self.set_filter(PlaylistFilter)
def get_playlist(self): return self.get_model().get_playlist()
def set_playlist(self, plist):
self.set_incremental(plist.get_n_tracks() > 1000)
self.get_model().set_playlist(plist)
def get_runtime(self):
n = self.get_n_items()
return sum([ int(self.get_item(i).length) for i in range(n) ])
class PlaylistSelection(Gtk.MultiSelection):
def __init__(self):
Gtk.MultiSelection.__init__(self)
self.set_model(FilterPlaylistModel())
def get_filter_model(self): return self.get_model()
def get_playlist(self): return self.get_model().get_playlist()
def set_playlist(self, plist): return self.get_model().set_playlist(plist)
class SortPlaylistModel(Gtk.StringList):
def __init__(self):
Gtk.StringList.__init__(self)
self.playlist = None
self.connect("items-changed", self.order_changed)
def get_index(self, string):
fields = [ self.get_string(i).split()[0] for i in range(self.get_n_items()) ]
return fields.index(string)
def get_direction(self, string):
return self.get_string(self.get_index(string)).split()[1]
def set_playlist(self, plist):
self.handler_block_by_func(self.order_changed)
self.playlist = plist
order = [ f for f in plist.sort if f.split()[0] not in ( "discs.number", "tracks.trackid") ]
self.splice(0, self.get_n_items(), order)
self.handler_unblock_by_func(self.order_changed)
def append(self, field):
super().append(f"{field} ASC")
def remove(self, field):
super().remove(self.get_index(field))
def move_up(self, field):
if (index := self.get_index(field)) > 0:
self.splice(index - 1, 2, [ self.get_string(index),
self.get_string(index - 1) ])
def move_down(self, field):
if (index := self.get_index(field)) < (self.get_n_items() - 1):
self.splice(index, 2, [ self.get_string(index + 1),
self.get_string(index) ])
def reverse(self, field):
index = self.get_index(field)
dir = 'DESC' if self.get_direction(field) == 'ASC' else 'ASC'
self.splice(index, 1, [ f"{field} {dir}" ])
def order_changed(self, model, pos, rm, add):
order = [ self.get_string(i) for i in range(self.get_n_items()) ]
if i := self.get_index("tracks.number"):
order.insert(i, f"discs.number {self.get_direction('tracks.number')}")
self.playlist.sort = order
class SortOptionsModel(Gtk.StringList):
def __init__(self):
Gtk.StringList.__init__(self)
self.append("tracks.number ASC")
self.append("tracks.title ASC"),
self.append("tracks.length ASC"),
self.append("artists.sort ASC"),
self.append("albums.sort ASC"),
self.append("discs.subtitle ASC"),
self.append("albums.release ASC"),
self.append("tracks.playcount ASC"),
self.append("tracks.lastplayed ASC")
class TagModel(GObject.GObject, Gio.ListModel):
def __init__(self, tag=None):
GObject.GObject.__init__(self)
self.Controls = controls.Controls()
self.bus = bus.Bus(1)
self.items = [ ]
self.__set_tag__(tag)
audio.Player.connect("track-changed", self.on_tracks_changed)
def __set_tag__(self, tag):
self.tag = tag
if self.tag != None:
self.items = self.tag.tracks.copy()
self.tag.TrackAdded.register(self.track_added)
self.tag.TrackRemoved.register(self.track_removed)
self.Controls.set_tag(tag)
return len(self.items)
def __unset_tag__(self):
n = len(self.items)
if self.tag:
self.tag.TrackAdded.unregister(self.track_added)
self.tag.TrackRemoved.unregister(self.track_removed)
self.items.clear()
return n
def do_get_item_type(self):
return GObject.TYPE_PYOBJECT
def do_get_n_items(self):
return len(self.items)
def do_get_item(self, n):
if n < len(self.items):
return self.items[n]
def items_changed(self, pos, removed, added):
super().items_changed(pos, removed, added)
runtime.set_runtime(self.tag.runtime)
runtime.set_visible_count(len(self.items))
def switch_tag(self, tag):
removed = self.__unset_tag__()
added = self.__set_tag__(tag)
self.items_changed(0, removed, added)
def do_track_added(self, tag, track, pos):
self.items.insert(pos, track)
self.items_changed(pos, 0, 1)
def track_added(self, tag, track, pos):
self.bus.board(self.do_track_added, tag, track, pos)
def do_track_removed(self, tag, track, pos):
self.items.remove(track)
self.items_changed(pos, 1, 0)
def track_removed(self, tag, track, pos):
self.bus.board(self.do_track_removed, tag, track, pos)
def on_tracks_changed(self, player, prev, new):
if prev in self.items:
self.items_changed(self.items.index(prev), 1, 1)
if new in self.items:
self.items_changed(self.items.index(new), 1, 1)