707 lines
27 KiB
Python
707 lines
27 KiB
Python
import os
|
|
import tempfile
|
|
import urllib.parse
|
|
import urllib.request
|
|
|
|
from fabric.widgets.box import Box
|
|
from fabric.widgets.button import Button
|
|
from fabric.widgets.centerbox import CenterBox
|
|
from fabric.widgets.circularprogressbar import CircularProgressBar
|
|
from fabric.widgets.label import Label
|
|
from fabric.widgets.overlay import Overlay
|
|
from fabric.widgets.stack import Stack
|
|
from gi.repository import Gdk, Gio, GLib, Gtk
|
|
|
|
import config.data as data
|
|
import modules.icons as icons
|
|
from modules.cavalcade import SpectrumRender
|
|
from services.mpris import MprisPlayer, MprisPlayerManager
|
|
from widgets.circle_image import CircleImage
|
|
|
|
vertical_mode = False
|
|
if data.PANEL_THEME == "Panel" and (data.BAR_POSITION in ["Left", "Right"] or data.PANEL_POSITION in ["Start", "End"]):
|
|
vertical_mode = True
|
|
|
|
def get_player_icon_markup_by_name(player_name):
|
|
if player_name:
|
|
pn = player_name.lower()
|
|
if pn == "firefox":
|
|
return icons.firefox
|
|
elif pn == "spotify":
|
|
return icons.spotify
|
|
elif pn in ("chromium", "brave"):
|
|
return icons.chromium
|
|
return icons.disc
|
|
|
|
def add_hover_cursor(widget):
|
|
widget.add_events(Gdk.EventMask.ENTER_NOTIFY_MASK | Gdk.EventMask.LEAVE_NOTIFY_MASK)
|
|
widget.connect("enter-notify-event", lambda w, event: w.get_window().set_cursor(
|
|
Gdk.Cursor.new_from_name(Gdk.Display.get_default(), "pointer")))
|
|
widget.connect("leave-notify-event", lambda w, event: w.get_window().set_cursor(None))
|
|
|
|
class PlayerBox(Box):
|
|
def __init__(self, mpris_player=None):
|
|
super().__init__(orientation="v", h_align="fill", spacing=0, h_expand=False, v_expand=not vertical_mode)
|
|
self.mpris_player = mpris_player
|
|
self._progress_timer_id = None
|
|
|
|
self.cover = CircleImage(
|
|
name="player-cover",
|
|
image_file=os.path.expanduser("~/.current.wall"),
|
|
size=162 if not vertical_mode else 96,
|
|
h_align="center",
|
|
v_align="center",
|
|
)
|
|
self.cover_placerholder = CircleImage(
|
|
name="player-cover",
|
|
size=198 if not vertical_mode else 132,
|
|
h_align="center",
|
|
v_align="center",
|
|
)
|
|
self.title = Label(name="player-title", h_expand=True, h_align="fill", ellipsization="end", max_chars_width=1, style_classes=["vertical"] if vertical_mode else [])
|
|
self.album = Label(name="player-album", h_expand=True, h_align="fill", ellipsization="end", max_chars_width=1)
|
|
self.artist = Label(name="player-artist", h_expand=True, h_align="fill", ellipsization="end", max_chars_width=1)
|
|
self.progressbar = CircularProgressBar(
|
|
name="player-progress",
|
|
size=198 if not vertical_mode else 132,
|
|
h_align="center",
|
|
v_align="center",
|
|
start_angle=180,
|
|
end_angle=360,
|
|
)
|
|
self.time = Label(name="player-time", label="--:-- / --:--")
|
|
self.overlay = Overlay(
|
|
child=self.cover_placerholder,
|
|
overlays=[self.progressbar, self.cover],
|
|
)
|
|
self.overlay_container = CenterBox(name="player-overlay", center_children=[self.overlay])
|
|
self.title.set_label("Nothing Playing")
|
|
self.album.set_label("Enjoy the silence")
|
|
self.artist.set_label("¯\\_(ツ)_/¯")
|
|
self.progressbar.set_value(0.0)
|
|
self.prev = Button(
|
|
name="player-btn",
|
|
child=Label(name="player-btn-label", markup=icons.prev),
|
|
h_expand=False,
|
|
v_expand=False,
|
|
h_align="center",
|
|
v_align="center",
|
|
)
|
|
self.backward = Button(
|
|
name="player-btn",
|
|
child=Label(name="player-btn-label", markup=icons.skip_back),
|
|
h_expand=False,
|
|
v_expand=False,
|
|
h_align="center",
|
|
v_align="center",
|
|
)
|
|
self.play_pause = Button(
|
|
name="player-btn",
|
|
child=Label(name="player-btn-label", markup=icons.play, style_classes=["play-pause"]),
|
|
style_classes=["play-pause"],
|
|
h_expand=False,
|
|
v_expand=False,
|
|
h_align="center",
|
|
v_align="center",
|
|
)
|
|
self.forward = Button(
|
|
name="player-btn",
|
|
child=Label(name="player-btn-label", markup=icons.skip_forward),
|
|
h_expand=False,
|
|
v_expand=False,
|
|
h_align="center",
|
|
v_align="center",
|
|
)
|
|
self.next = Button(
|
|
name="player-btn",
|
|
child=Label(name="player-btn-label", markup=icons.next),
|
|
h_expand=False,
|
|
v_expand=False,
|
|
h_align="center",
|
|
v_align="center",
|
|
)
|
|
add_hover_cursor(self.prev)
|
|
add_hover_cursor(self.backward)
|
|
add_hover_cursor(self.play_pause)
|
|
add_hover_cursor(self.forward)
|
|
add_hover_cursor(self.next)
|
|
self.btn_box = CenterBox(
|
|
name="player-btn-box",
|
|
orientation="h",
|
|
center_children=[
|
|
Box(
|
|
orientation="h",
|
|
spacing=8,
|
|
h_expand=True,
|
|
h_align="fill",
|
|
children=[
|
|
self.prev,
|
|
self.backward,
|
|
self.play_pause,
|
|
self.forward,
|
|
self.next,
|
|
]
|
|
)
|
|
]
|
|
)
|
|
|
|
self.p_children=[
|
|
self.overlay_container,
|
|
self.title,
|
|
self.album,
|
|
self.artist,
|
|
self.btn_box,
|
|
self.time,
|
|
] if not vertical_mode else [
|
|
self.overlay_container,
|
|
Box(
|
|
orientation="v",
|
|
spacing=4,
|
|
h_expand=True,
|
|
h_align="fill",
|
|
v_expand=False,
|
|
v_align="center",
|
|
children=[
|
|
self.title,
|
|
self.album,
|
|
self.btn_box,
|
|
self.artist,
|
|
self.time,
|
|
]
|
|
)
|
|
]
|
|
|
|
self.player_box = Box(
|
|
name="player-box",
|
|
orientation="v" if not vertical_mode else "h",
|
|
v_align="center",
|
|
spacing=4,
|
|
children=self.p_children,
|
|
)
|
|
self.add(self.player_box)
|
|
if mpris_player:
|
|
self._apply_mpris_properties()
|
|
self.prev.connect("clicked", self._on_prev_clicked)
|
|
self.play_pause.connect("clicked", self._on_play_pause_clicked)
|
|
self.backward.connect("clicked", self._on_backward_clicked)
|
|
self.forward.connect("clicked", self._on_forward_clicked)
|
|
self.next.connect("clicked", self._on_next_clicked)
|
|
self.mpris_player.connect("changed", self._on_mpris_changed)
|
|
else:
|
|
self.play_pause.get_child().set_markup(icons.stop)
|
|
self.play_pause.add_style_class("stop")
|
|
|
|
self.backward.add_style_class("disabled")
|
|
self.forward.add_style_class("disabled")
|
|
self.prev.add_style_class("disabled")
|
|
self.next.add_style_class("disabled")
|
|
self.progressbar.set_value(0.0)
|
|
self.time.set_text("--:-- / --:--")
|
|
|
|
def _apply_mpris_properties(self):
|
|
mp = self.mpris_player
|
|
self.title.set_visible(bool(mp.title and mp.title.strip()))
|
|
if mp.title and mp.title.strip():
|
|
self.title.set_text(mp.title)
|
|
self.album.set_visible(bool(mp.album and mp.album.strip()))
|
|
if mp.album and mp.album.strip():
|
|
self.album.set_text(mp.album)
|
|
self.artist.set_visible(bool(mp.artist and mp.artist.strip()))
|
|
if mp.artist and mp.artist.strip():
|
|
self.artist.set_text(mp.artist)
|
|
if mp.arturl:
|
|
parsed = urllib.parse.urlparse(mp.arturl)
|
|
if parsed.scheme == "file":
|
|
local_arturl = urllib.parse.unquote(parsed.path)
|
|
self._set_cover_image(local_arturl)
|
|
elif parsed.scheme in ("http", "https"):
|
|
GLib.Thread.new("download-artwork", self._download_and_set_artwork, mp.arturl)
|
|
else:
|
|
self._set_cover_image(mp.arturl)
|
|
else:
|
|
fallback = os.path.expanduser("~/.current.wall")
|
|
self._set_cover_image(fallback)
|
|
file_obj = Gio.File.new_for_path(fallback)
|
|
monitor = file_obj.monitor_file(Gio.FileMonitorFlags.NONE, None)
|
|
monitor.connect("changed", self.on_wallpaper_changed)
|
|
self._wallpaper_monitor = monitor
|
|
self.update_play_pause_icon()
|
|
|
|
self.progressbar.set_visible(True)
|
|
self.time.set_visible(True)
|
|
|
|
player_name = mp.player_name.lower() if hasattr(mp, "player_name") and mp.player_name else ""
|
|
can_seek = hasattr(mp, "can_seek") and mp.can_seek
|
|
|
|
if player_name == "firefox" or not can_seek:
|
|
# Firefox and non-seekable players don't support progress tracking
|
|
self.backward.add_style_class("disabled")
|
|
self.forward.add_style_class("disabled")
|
|
self.progressbar.set_value(0.0)
|
|
self.time.set_text("--:-- / --:--")
|
|
# Stop the timer since we can't track progress
|
|
if self._progress_timer_id:
|
|
GLib.source_remove(self._progress_timer_id)
|
|
self._progress_timer_id = None
|
|
else:
|
|
# Enable seeking controls
|
|
self.backward.remove_style_class("disabled")
|
|
self.forward.remove_style_class("disabled")
|
|
|
|
# Use adaptive timer based on playback status instead of fixed 1-second polling
|
|
self._start_adaptive_progress_timer()
|
|
|
|
if hasattr(mp, "can_go_previous") and mp.can_go_previous:
|
|
self.prev.remove_style_class("disabled")
|
|
else:
|
|
self.prev.add_style_class("disabled")
|
|
|
|
if hasattr(mp, "can_go_next") and mp.can_go_next:
|
|
self.next.remove_style_class("disabled")
|
|
else:
|
|
self.next.add_style_class("disabled")
|
|
|
|
def _start_adaptive_progress_timer(self):
|
|
"""Start progress timer with adaptive interval based on playback status"""
|
|
if self._progress_timer_id:
|
|
GLib.source_remove(self._progress_timer_id)
|
|
|
|
# Use longer intervals when paused to reduce CPU usage
|
|
if hasattr(self.mpris_player, 'playback_status') and self.mpris_player.playback_status == "playing":
|
|
interval = 1000 # 1 second when playing
|
|
else:
|
|
interval = 5000 # 5 seconds when paused/stopped
|
|
|
|
self._progress_timer_id = GLib.timeout_add(interval, self._update_progress)
|
|
self._update_progress() # Update immediately
|
|
|
|
def _set_cover_image(self, image_path):
|
|
if image_path and os.path.isfile(image_path):
|
|
self.cover.set_image_from_file(image_path)
|
|
else:
|
|
fallback = os.path.expanduser("~/.current.wall")
|
|
self.cover.set_image_from_file(fallback)
|
|
file_obj = Gio.File.new_for_path(fallback)
|
|
monitor = file_obj.monitor_file(Gio.FileMonitorFlags.NONE, None)
|
|
monitor.connect("changed", self.on_wallpaper_changed)
|
|
self._wallpaper_monitor = monitor
|
|
|
|
def _download_and_set_artwork(self, arturl):
|
|
"""
|
|
Download the artwork from the given URL asynchronously and update the cover image
|
|
using GLib.idle_add to ensure UI updates occur on the main thread.
|
|
"""
|
|
try:
|
|
parsed = urllib.parse.urlparse(arturl)
|
|
suffix = os.path.splitext(parsed.path)[1] or ".png"
|
|
with urllib.request.urlopen(arturl) as response:
|
|
data = response.read()
|
|
temp_file = tempfile.NamedTemporaryFile(delete=False, suffix=suffix)
|
|
temp_file.write(data)
|
|
temp_file.close()
|
|
local_arturl = temp_file.name
|
|
except Exception:
|
|
local_arturl = os.path.expanduser("~/.current.wall")
|
|
GLib.idle_add(self._set_cover_image, local_arturl)
|
|
return None
|
|
|
|
def update_play_pause_icon(self):
|
|
if self.mpris_player.playback_status == "playing":
|
|
self.play_pause.get_child().set_markup(icons.pause)
|
|
self.play_pause.add_style_class("playing")
|
|
else:
|
|
self.play_pause.get_child().set_markup(icons.play)
|
|
self.play_pause.remove_style_class("playing")
|
|
|
|
def on_wallpaper_changed(self, monitor, file, other_file, event):
|
|
self.cover.set_image_from_file(os.path.expanduser("~/.current.wall"))
|
|
|
|
def _on_prev_clicked(self, button):
|
|
if self.mpris_player:
|
|
self.mpris_player.previous()
|
|
|
|
def _on_play_pause_clicked(self, button):
|
|
if self.mpris_player:
|
|
self.mpris_player.play_pause()
|
|
self.update_play_pause_icon()
|
|
|
|
def _on_backward_clicked(self, button):
|
|
|
|
if self.mpris_player and self.mpris_player.can_seek and "disabled" not in self.backward.get_style_context().list_classes():
|
|
new_pos = max(0, self.mpris_player.position - 5000000)
|
|
self.mpris_player.position = new_pos
|
|
|
|
def _on_forward_clicked(self, button):
|
|
|
|
if self.mpris_player and self.mpris_player.can_seek and "disabled" not in self.forward.get_style_context().list_classes():
|
|
new_pos = self.mpris_player.position + 5000000
|
|
self.mpris_player.position = new_pos
|
|
|
|
def _on_next_clicked(self, button):
|
|
if self.mpris_player:
|
|
self.mpris_player.next()
|
|
|
|
def _update_progress(self):
|
|
|
|
if not self.mpris_player:
|
|
|
|
if self._progress_timer_id:
|
|
GLib.source_remove(self._progress_timer_id)
|
|
self._progress_timer_id = None
|
|
return False
|
|
|
|
try:
|
|
current = self.mpris_player.position
|
|
except Exception:
|
|
current = 0
|
|
try:
|
|
total = int(self.mpris_player.length or 0)
|
|
except Exception:
|
|
total = 0
|
|
|
|
if total <= 0:
|
|
progress = 0.0
|
|
self.time.set_text("--:-- / --:--")
|
|
|
|
else:
|
|
progress = (current / total)
|
|
self.time.set_text(f"{self._format_time(current)} / {self._format_time(total)}")
|
|
|
|
self.progressbar.set_value(progress)
|
|
return True
|
|
|
|
def _format_time(self, us):
|
|
seconds = int(us / 1000000)
|
|
minutes = seconds // 60
|
|
seconds = seconds % 60
|
|
return f"{minutes}:{seconds:02}"
|
|
|
|
def _update_metadata(self):
|
|
if not self.mpris_player:
|
|
return False
|
|
self._apply_mpris_properties()
|
|
return True
|
|
|
|
def _on_mpris_changed(self, *args):
|
|
|
|
if not hasattr(self, "_update_pending") or not self._update_pending:
|
|
self._update_pending = True
|
|
|
|
GLib.idle_add(self._apply_mpris_properties_debounced)
|
|
|
|
def _apply_mpris_properties_debounced(self):
|
|
"""Apply MPRIS properties with debouncing and restart adaptive timer"""
|
|
if self.mpris_player:
|
|
self._apply_mpris_properties()
|
|
else:
|
|
# Clean up timer when player is removed
|
|
if self._progress_timer_id:
|
|
GLib.source_remove(self._progress_timer_id)
|
|
self._progress_timer_id = None
|
|
self._update_pending = False
|
|
return False
|
|
|
|
class Player(Box):
|
|
def __init__(self):
|
|
super().__init__(name="player", orientation="v", h_align="fill", spacing=0, h_expand=False, v_expand=not vertical_mode)
|
|
self.player_stack = Stack(
|
|
name="player-stack",
|
|
transition_type="slide-left-right",
|
|
transition_duration=500,
|
|
v_align="center",
|
|
v_expand=not vertical_mode,
|
|
)
|
|
self.switcher = Gtk.StackSwitcher(
|
|
name="player-switcher" if not vertical_mode else "player-switcher-vertical",
|
|
spacing=8,
|
|
)
|
|
self.switcher.set_stack(self.player_stack)
|
|
self.switcher.set_halign(Gtk.Align.CENTER)
|
|
self.mpris_manager = MprisPlayerManager()
|
|
players = self.mpris_manager.players
|
|
if players:
|
|
for p in players:
|
|
mp = MprisPlayer(p)
|
|
pb = PlayerBox(mpris_player=mp)
|
|
self.player_stack.add_titled(pb, mp.player_name, mp.player_name)
|
|
else:
|
|
pb = PlayerBox(mpris_player=None)
|
|
self.player_stack.add_titled(pb, "nothing", "Nothing Playing")
|
|
self.mpris_manager.connect("player-appeared", self.on_player_appeared)
|
|
self.mpris_manager.connect("player-vanished", self.on_player_vanished)
|
|
self.switcher.set_visible(True)
|
|
self.add(self.player_stack)
|
|
self.add(self.switcher)
|
|
GLib.idle_add(self._replace_switcher_labels)
|
|
|
|
def on_player_appeared(self, manager, player):
|
|
children = self.player_stack.get_children()
|
|
if len(children) == 1 and not getattr(children[0], "mpris_player", None):
|
|
self.player_stack.remove(children[0])
|
|
mp = MprisPlayer(player)
|
|
pb = PlayerBox(mpris_player=mp)
|
|
self.player_stack.add_titled(pb, mp.player_name, mp.player_name)
|
|
|
|
self.switcher.set_visible(True)
|
|
GLib.idle_add(lambda: self._update_switcher_for_player(mp.player_name))
|
|
GLib.idle_add(self._replace_switcher_labels)
|
|
|
|
def on_player_vanished(self, manager, player_name):
|
|
for child in self.player_stack.get_children():
|
|
if hasattr(child, "mpris_player") and child.mpris_player and child.mpris_player.player_name == player_name:
|
|
self.player_stack.remove(child)
|
|
break
|
|
if not any(getattr(child, "mpris_player", None) for child in self.player_stack.get_children()):
|
|
pb = PlayerBox(mpris_player=None)
|
|
self.player_stack.add_titled(pb, "nothing", "Nothing Playing")
|
|
self.switcher.set_visible(True)
|
|
GLib.idle_add(self._replace_switcher_labels)
|
|
|
|
def _replace_switcher_labels(self):
|
|
buttons = self.switcher.get_children()
|
|
for btn in buttons:
|
|
if isinstance(btn, Gtk.ToggleButton):
|
|
default_label = None
|
|
for child in btn.get_children():
|
|
if isinstance(child, Gtk.Label):
|
|
default_label = child
|
|
break
|
|
if default_label:
|
|
label_player_name = getattr(default_label, "player_name", default_label.get_text().lower())
|
|
icon_markup = get_player_icon_markup_by_name(label_player_name)
|
|
btn.remove(default_label)
|
|
new_label = Label(name="player-label", markup=icon_markup)
|
|
new_label.player_name = label_player_name
|
|
btn.add(new_label)
|
|
new_label.show_all()
|
|
return False
|
|
|
|
def _update_switcher_for_player(self, player_name):
|
|
for btn in self.switcher.get_children():
|
|
if isinstance(btn, Gtk.ToggleButton):
|
|
default_label = None
|
|
for child in btn.get_children():
|
|
if isinstance(child, Gtk.Label):
|
|
default_label = child
|
|
break
|
|
if default_label:
|
|
label_player_name = getattr(default_label, "player_name", default_label.get_text().lower())
|
|
if label_player_name == player_name.lower():
|
|
icon_markup = get_player_icon_markup_by_name(player_name)
|
|
btn.remove(default_label)
|
|
new_label = Label(name="player-label", markup=icon_markup)
|
|
new_label.player_name = player_name.lower()
|
|
btn.add(new_label)
|
|
new_label.show_all()
|
|
return False
|
|
|
|
class PlayerSmall(CenterBox):
|
|
def __init__(self):
|
|
super().__init__(name="player-small", orientation="h", h_align="fill", v_align="center")
|
|
self._show_artist = False
|
|
self._display_options = ["cavalcade", "title", "artist"]
|
|
self._display_index = 0
|
|
self._current_display = "cavalcade"
|
|
|
|
self.mpris_icon = Button(
|
|
name="compact-mpris-icon",
|
|
h_align="center",
|
|
v_align="center",
|
|
child=Label(name="compact-mpris-icon-label", markup=icons.disc)
|
|
)
|
|
|
|
self.mpris_icon.add_events(Gdk.EventMask.BUTTON_PRESS_MASK)
|
|
self.mpris_icon.connect("button-press-event", self._on_icon_button_press)
|
|
|
|
child = self.mpris_icon.get_child()
|
|
child.add_events(Gdk.EventMask.BUTTON_PRESS_MASK)
|
|
child.connect("button-press-event", lambda widget, event: True)
|
|
|
|
add_hover_cursor(self.mpris_icon)
|
|
|
|
self.mpris_label = Label(
|
|
name="compact-mpris-label",
|
|
label="Nothing Playing",
|
|
ellipsization="end",
|
|
max_chars_width=26,
|
|
h_align="center",
|
|
)
|
|
self.mpris_button = Button(
|
|
name="compact-mpris-button",
|
|
h_align="center",
|
|
v_align="center",
|
|
child=Label(name="compact-mpris-button-label", markup=icons.play)
|
|
)
|
|
self.mpris_button.add_events(Gdk.EventMask.BUTTON_PRESS_MASK)
|
|
self.mpris_button.connect("button-press-event", self._on_play_pause_button_press)
|
|
|
|
add_hover_cursor(self.mpris_button)
|
|
|
|
self.cavalcade = SpectrumRender()
|
|
self.cavalcade_box = self.cavalcade.get_spectrum_box()
|
|
|
|
self.center_stack = Stack(
|
|
name="compact-mpris",
|
|
transition_type="crossfade",
|
|
transition_duration=100,
|
|
v_align="center",
|
|
v_expand=False,
|
|
children=[
|
|
self.cavalcade_box,
|
|
self.mpris_label,
|
|
]
|
|
)
|
|
self.center_stack.set_visible_child(self.cavalcade_box)
|
|
|
|
self.mpris_small = CenterBox(
|
|
name="compact-mpris",
|
|
orientation="h",
|
|
h_expand=True,
|
|
h_align="fill",
|
|
v_align="center",
|
|
v_expand=False,
|
|
start_children=self.mpris_icon,
|
|
center_children=self.center_stack,
|
|
end_children=self.mpris_button,
|
|
)
|
|
|
|
self.add(self.mpris_small)
|
|
|
|
self.mpris_manager = MprisPlayerManager()
|
|
self.mpris_player = None
|
|
|
|
self.current_index = 0
|
|
|
|
players = self.mpris_manager.players
|
|
if players:
|
|
mp = MprisPlayer(players[self.current_index])
|
|
self.mpris_player = mp
|
|
self._apply_mpris_properties()
|
|
self.mpris_player.connect("changed", self._on_mpris_changed)
|
|
else:
|
|
self._apply_mpris_properties()
|
|
|
|
self.mpris_manager.connect("player-appeared", self.on_player_appeared)
|
|
self.mpris_manager.connect("player-vanished", self.on_player_vanished)
|
|
self.mpris_button.connect("clicked", self._on_play_pause_clicked)
|
|
|
|
def _apply_mpris_properties(self):
|
|
if not self.mpris_player:
|
|
self.mpris_label.set_text("Nothing Playing")
|
|
self.mpris_button.get_child().set_markup(icons.stop)
|
|
self.mpris_icon.get_child().set_markup(icons.disc)
|
|
if self._current_display != "cavalcade":
|
|
self.center_stack.set_visible_child(self.mpris_label)
|
|
else:
|
|
self.center_stack.set_visible_child(self.cavalcade_box)
|
|
return
|
|
|
|
mp = self.mpris_player
|
|
|
|
player_name = mp.player_name.lower() if hasattr(mp, "player_name") and mp.player_name else ""
|
|
icon_markup = get_player_icon_markup_by_name(player_name)
|
|
self.mpris_icon.get_child().set_markup(icon_markup)
|
|
self.update_play_pause_icon()
|
|
|
|
if self._current_display == "title":
|
|
text = (mp.title if mp.title and mp.title.strip() else "Nothing Playing")
|
|
self.mpris_label.set_text(text)
|
|
self.center_stack.set_visible_child(self.mpris_label)
|
|
elif self._current_display == "artist":
|
|
text = (mp.artist if mp.artist else "Nothing Playing")
|
|
self.mpris_label.set_text(text)
|
|
self.center_stack.set_visible_child(self.mpris_label)
|
|
else:
|
|
self.center_stack.set_visible_child(self.cavalcade_box)
|
|
|
|
def _on_icon_button_press(self, widget, event):
|
|
from gi.repository import Gdk
|
|
if event.type == Gdk.EventType.BUTTON_PRESS:
|
|
players = self.mpris_manager.players
|
|
if not players:
|
|
return True
|
|
|
|
if event.button == 2:
|
|
self._display_index = (self._display_index + 1) % len(self._display_options)
|
|
self._current_display = self._display_options[self._display_index]
|
|
self._apply_mpris_properties()
|
|
return True
|
|
|
|
if event.button == 1:
|
|
self.current_index = (self.current_index + 1) % len(players)
|
|
elif event.button == 3:
|
|
self.current_index = (self.current_index - 1) % len(players)
|
|
if self.current_index < 0:
|
|
self.current_index = len(players) - 1
|
|
|
|
mp_new = MprisPlayer(players[self.current_index])
|
|
self.mpris_player = mp_new
|
|
|
|
self.mpris_player.connect("changed", self._on_mpris_changed)
|
|
self._apply_mpris_properties()
|
|
return True
|
|
return True
|
|
|
|
def _on_play_pause_button_press(self, widget, event):
|
|
if event.type == Gdk.EventType.BUTTON_PRESS:
|
|
if event.button == 1:
|
|
if self.mpris_player:
|
|
self.mpris_player.previous()
|
|
self.mpris_button.get_child().set_markup(icons.prev)
|
|
GLib.timeout_add(500, self._restore_play_pause_icon)
|
|
elif event.button == 3:
|
|
if self.mpris_player:
|
|
self.mpris_player.next()
|
|
self.mpris_button.get_child().set_markup(icons.next)
|
|
GLib.timeout_add(500, self._restore_play_pause_icon)
|
|
elif event.button == 2:
|
|
if self.mpris_player:
|
|
self.mpris_player.play_pause()
|
|
self.update_play_pause_icon()
|
|
return True
|
|
return True
|
|
|
|
def _restore_play_pause_icon(self):
|
|
self.update_play_pause_icon()
|
|
return False
|
|
|
|
def _on_icon_clicked(self, widget):
|
|
pass
|
|
|
|
def update_play_pause_icon(self):
|
|
if self.mpris_player and self.mpris_player.playback_status == "playing":
|
|
self.mpris_button.get_child().set_markup(icons.pause)
|
|
else:
|
|
self.mpris_button.get_child().set_markup(icons.play)
|
|
|
|
def _on_play_pause_clicked(self, button):
|
|
if self.mpris_player:
|
|
self.mpris_player.play_pause()
|
|
self.update_play_pause_icon()
|
|
|
|
def _on_mpris_changed(self, *args):
|
|
|
|
self._apply_mpris_properties()
|
|
|
|
def on_player_appeared(self, manager, player):
|
|
|
|
if not self.mpris_player:
|
|
mp = MprisPlayer(player)
|
|
self.mpris_player = mp
|
|
self._apply_mpris_properties()
|
|
self.mpris_player.connect("changed", self._on_mpris_changed)
|
|
|
|
def on_player_vanished(self, manager, player_name):
|
|
players = self.mpris_manager.players
|
|
if players and self.mpris_player and self.mpris_player.player_name == player_name:
|
|
if players:
|
|
self.current_index = self.current_index % len(players)
|
|
new_player = MprisPlayer(players[self.current_index])
|
|
self.mpris_player = new_player
|
|
self.mpris_player.connect("changed", self._on_mpris_changed)
|
|
else:
|
|
self.mpris_player = None
|
|
elif not players:
|
|
self.mpris_player = None
|
|
self._apply_mpris_properties()
|