# Copyright 2021 (c) Anna Schumaker. from . import artwork from . import controls from . import nowplaying from . import seeker from lib import publisher from lib import settings from gi.repository import GObject from gi.repository import Gst, GLib import tagdb class Player(GObject.GObject): def __init__(self): GObject.GObject.__init__(self) self.video = Gst.ElementFactory.make("fakesink") self.playbin = Gst.ElementFactory.make("playbin") self.playbin.set_property("video-sink", self.video) self.bus = self.playbin.get_bus() self.bus.add_signal_watch() self.bus.connect("message::eos", self.next) self.bus.connect("message::state-changed", self.on_state_changed) self.bus.connect("message::tag", self.on_tag) self.Controls = controls.Controls() self.Controls.connect("previous", self.previous) self.Controls.connect("play", self.play) self.Controls.connect("pause", self.pause) self.Controls.connect("next", self.next) self.Controls.connect("volume-changed", self.volume_changed) self.NowPlaying = nowplaying.NowPlaying() self.Artwork = artwork.Artwork() self.Seeker = seeker.Seeker() self.Seeker.connect(self.seeked) self.Controls.sizegroup.add_widget(self.Seeker.scale) GLib.timeout_add(250, self.update_progress) self.track = tagdb.Tracks[settings.get_int("audio.trackid")] self.load_set_state(self.track, Gst.State.PAUSED) if self.track: self.track.add_to_playlist("Previous") self.volume_changed() def duration(self): (res, dur) = self.playbin.query_duration(Gst.Format.TIME) return dur if res == True else 0 def get_state(self): (ret, state, pending) = self.playbin.get_state(Gst.CLOCK_TIME_NONE) if ret == Gst.StateChangeReturn.SUCCESS: return state return ret def load_track(self, track): prev = self.track self.track = track if track is not None: settings.set("audio.trackid", track.trackid) uri = track.filepath().absolute().as_uri() self.playbin.set_property("uri", uri) self.emit("track-changed", prev, self.track) def load_set_state(self, track, state): self.playbin.set_state(Gst.State.READY) self.load_track(track) if track is not None: self.playbin.set_state(state) def next(self, *args): duration = self.duration() if duration > 0 and (self.runtime() / duration) > (2 / 3): self.track.played() (track, cont) = tagdb.Stack.next() state = Gst.State.PLAYING if cont else Gst.State.PAUSED self.load_set_state(track, state) def on_state_changed(self, bus, message): (old, new, pending) = message.parse_state_changed() self.Controls.set_state(new) self.emit("state-changed", old, new, pending) def on_tag(self, bus, message): taglist = message.parse_tag() (res, title) = taglist.get_string("title") if res == True: self.NowPlaying.set_title(title) (res, artist) = taglist.get_string("artist") if res == True: self.NowPlaying.set_artist(artist) (res, sample) = taglist.get_sample("image") if res == True: self.Artwork.set_from_sample(sample) else: self.Artwork.reset() def pause(self, *args): self.playbin.set_state(Gst.State.PAUSED) def play(self, *args): self.playbin.set_state(Gst.State.PLAYING) def playpause(self, *args): if self.get_state() == Gst.State.PLAYING: self.pause() else: self.play() def play_track(self, track): if track == self.track: return False self.load_set_state(track, Gst.State.PLAYING) return True def position(self): (res, pos) = self.playbin.query_position(Gst.Format.TIME) return pos if res == True else 0 def previous(self, *args): self.play_track(tagdb.Stack.previous()) def runtime(self): if self.playbin.clock == None: return 0 return self.playbin.clock.get_time() - self.playbin.base_time def seeked(self, scale, scroll, value): self.playbin.seek_simple(Gst.Format.TIME, Gst.SeekFlags.FLUSH, value * Gst.SECOND) def update_progress(self): self.Seeker.configure(self.position() / Gst.SECOND, self.duration() / Gst.SECOND) return GLib.SOURCE_CONTINUE def volume_changed(self, *args): self.playbin.set_property("volume", self.Controls.menu.volume.get_value()) @GObject.Signal(arg_types=(Gst.State, Gst.State, Gst.State)) def state_changed(self, old, new, pending): pass @GObject.Signal(arg_types=(tagdb.track.Track, tagdb.track.Track)) def track_changed(self, prev, new): pass