186 lines
6.0 KiB
Python
186 lines
6.0 KiB
Python
import threading
|
|
import time
|
|
|
|
import gi
|
|
import vlc
|
|
|
|
from croaker import path
|
|
from croaker.playlist import Playlist, load_playlist
|
|
|
|
gi.require_version("Gtk", "4.0")
|
|
gi.require_version("Gdk", "4.0")
|
|
from gi.repository import Gdk, GLib, GObject, Gtk, Pango # noqa E402
|
|
|
|
|
|
class PlayerWindow(Gtk.ApplicationWindow):
|
|
def __init__(self, *args, **kwargs):
|
|
super().__init__(*args, **kwargs)
|
|
|
|
self._max_width = 300
|
|
self._max_height = 330
|
|
self._artwork_width = self._max_width
|
|
self._artwork_height = 248
|
|
|
|
css_provider = Gtk.CssProvider()
|
|
css_provider.load_from_path(str(path.assets() / "style.css"))
|
|
Gtk.StyleContext.add_provider_for_display(
|
|
Gdk.Display.get_default(), css_provider, Gtk.STYLE_PROVIDER_PRIORITY_APPLICATION
|
|
)
|
|
self.set_title("Croaker Radio")
|
|
self._root = Gtk.Fixed()
|
|
self._root.set_size_request(self._max_width, self._max_height)
|
|
self.set_child(self._root)
|
|
|
|
self._artwork = Gtk.Fixed()
|
|
self._track = None
|
|
self._artist = None
|
|
self._album = None
|
|
|
|
self._draw_window()
|
|
|
|
def _draw_window(self):
|
|
margin_size = 8
|
|
label_width = self._max_width - (2 * margin_size)
|
|
label_height = 16
|
|
label_spacing = 8
|
|
|
|
self._artwork.set_size_request(self._artwork_width, self._artwork_height)
|
|
self._root.put(self._artwork, 0, 0)
|
|
self.draw_artwork()
|
|
|
|
def label(text: str):
|
|
l = Gtk.Label()
|
|
l.set_ellipsize(Pango.EllipsizeMode.END)
|
|
l.add_css_class("label")
|
|
l.set_text(text)
|
|
l.set_size_request(label_width, label_height)
|
|
l.set_justify(Gtk.Justification.LEFT)
|
|
l.set_hexpand(True)
|
|
l.set_xalign(0)
|
|
return l
|
|
|
|
self._track = label("CROAKER RADIO")
|
|
self._track.add_css_class("now_playing")
|
|
self._root.put(self._track, margin_size, self._artwork_height + label_spacing)
|
|
|
|
self._artist = label("Artist")
|
|
self._root.put(self._artist, margin_size, self._artwork_height + (2 * label_spacing) + label_height)
|
|
|
|
self._album = label("Album")
|
|
self._root.put(self._album, margin_size, self._artwork_height + (3 * label_spacing) + (2 * label_height))
|
|
|
|
def now_playing(self, track: str, artist: str, album: str):
|
|
self._track.set_text(f"🎵 {track}")
|
|
self._artist.set_text(f"🐸 {artist}")
|
|
self._album.set_text(f"💿 {album}")
|
|
|
|
def draw_artwork(self):
|
|
image1 = Gtk.Image()
|
|
image1.set_from_file(str(path.assets() / "froghat.png"))
|
|
image1.set_size_request(self._artwork_width, self._artwork_height)
|
|
image1.add_css_class("artwork")
|
|
self._artwork.put(image1, 0, 0)
|
|
|
|
|
|
class GUI(Gtk.Application):
|
|
"""
|
|
A simple GTK application that instaniates a VLC player and listens for commands.
|
|
"""
|
|
|
|
def __init__(self):
|
|
super().__init__()
|
|
|
|
self._playlist: Playlist | None = None
|
|
|
|
self._vlc_instance = vlc.Instance("--loop")
|
|
self._media_list_player = vlc.MediaListPlayer()
|
|
self._player.audio_set_volume(30)
|
|
|
|
self._signal_handler = threading.Thread(target=self._wait_for_signals)
|
|
self._signal_handler.daemon = True
|
|
|
|
self.play_requested = threading.Event()
|
|
self.back_requested = threading.Event()
|
|
self.ffwd_requested = threading.Event()
|
|
self.stop_requested = threading.Event()
|
|
self.load_requested = threading.Event()
|
|
self.clear_requested = threading.Event()
|
|
self.shutdown_requested = threading.Event()
|
|
|
|
GLib.set_application_name("Croaker Radio")
|
|
|
|
@property
|
|
def _player(self):
|
|
return self._media_list_player.get_media_player()
|
|
|
|
def do_activate(self):
|
|
self._signal_handler.start()
|
|
self._window = PlayerWindow(application=self)
|
|
self._window.present()
|
|
|
|
def load(self, playlist_name: str):
|
|
self.clear()
|
|
self._playlist = load_playlist(playlist_name)
|
|
|
|
media = self._vlc_instance.media_list_new()
|
|
for track in self._playlist.tracks:
|
|
media.add_media(self._vlc_instance.media_new(track))
|
|
|
|
self._media_list_player.set_media_list(media)
|
|
self._media_list_player.play()
|
|
self._update_now_playing()
|
|
events = self._player.event_manager()
|
|
events.event_attach(vlc.EventType.MediaPlayerMediaChanged, self._update_now_playing)
|
|
|
|
def _update_now_playing(self, event=None):
|
|
track = "[NOTHING PLAYING]"
|
|
artist = "artist"
|
|
album = "album"
|
|
media = self._player.get_media()
|
|
if media:
|
|
media.parse()
|
|
track = media.get_meta(vlc.Meta.Title)
|
|
artist = media.get_meta(vlc.Meta.Artist)
|
|
album = media.get_meta(vlc.Meta.Album)
|
|
self._window.now_playing(track, artist, album)
|
|
|
|
def _wait_for_signals(self):
|
|
while not self.shutdown_requested.is_set():
|
|
if self.play_requested.is_set():
|
|
self.play_requested.clear()
|
|
GLib.idle_add(self._media_list_player.play)
|
|
|
|
if self.back_requested.is_set():
|
|
self.back_requested.clear()
|
|
GLib.idle_add(self._media_list_player.previous)
|
|
|
|
if self.ffwd_requested.is_set():
|
|
self.ffwd_requested.clear()
|
|
GLib.idle_add(self._media_list_player.next)
|
|
|
|
if self.stop_requested.is_set():
|
|
self.stop_requested.clear()
|
|
GLib.idle_add(self._media_list_player.stop)
|
|
|
|
if self.load_requested.is_set():
|
|
self.load_requested.clear()
|
|
GLib.idle_add(self._media_list_player.load)
|
|
|
|
if self.clear_requested.is_set():
|
|
self.clear_requested.clear()
|
|
GLib.idle_add(self.clear)
|
|
|
|
time.sleep(0.25)
|
|
GLib.idle_add(self.quit)
|
|
exit()
|
|
|
|
def clear(self):
|
|
if self._media_list_player:
|
|
self._media_list_player.stop()
|
|
self._playlist = None
|
|
|
|
def quit(self):
|
|
self.clear()
|
|
self._vlc_instance.release()
|
|
exit()
|