Merge pull request #305 from nwg-piotr/players

Playerctl: add multiple players support
This commit is contained in:
Piotr Miller
2024-06-15 02:04:25 +02:00
committed by GitHub
6 changed files with 51 additions and 9 deletions

View File

@@ -194,6 +194,7 @@
"script": "Script", "script": "Script",
"script-tooltip": "Script to execute: should return \nan icon name or path and a label \nin 1 or 2 lines of text. See Wiki \nfor details.", "script-tooltip": "Script to execute: should return \nan icon name or path and a label \nin 1 or 2 lines of text. See Wiki \nfor details.",
"scroll": "Scroll", "scroll": "Scroll",
"scroll-to-switch": "scroll to switch",
"select": "Select", "select": "Select",
"set-0-to-disable": "Set 0 to disable", "set-0-to-disable": "Set 0 to disable",
"settings": "Settings", "settings": "Settings",

View File

@@ -194,6 +194,7 @@
"script": "スクリプト", "script": "スクリプト",
"script-tooltip": "実行するスクリプト:アイコン名またはパスとラベルを\n1または2行のテキストで返す必要があります。詳細はWikiを参照してください。", "script-tooltip": "実行するスクリプト:アイコン名またはパスとラベルを\n1または2行のテキストで返す必要があります。詳細はWikiを参照してください。",
"scroll": "スクロール", "scroll": "スクロール",
"scroll-to-switch": "スクロールして切り替える",
"select": "選択", "select": "選択",
"set-0-to-disable": "0 に設定して無効化", "set-0-to-disable": "0 に設定して無効化",
"settings": "設定", "settings": "設定",

View File

@@ -194,6 +194,7 @@
"script": "Skrypt", "script": "Skrypt",
"script-tooltip": "Skrypt do wykonania: powinien zwracać nazwę\nlub ścieżkę ikony i tekst, w jednym lub dwóch wierszach.\nWięcej informacji w Wiki.", "script-tooltip": "Skrypt do wykonania: powinien zwracać nazwę\nlub ścieżkę ikony i tekst, w jednym lub dwóch wierszach.\nWięcej informacji w Wiki.",
"scroll": "Przewijanie", "scroll": "Przewijanie",
"scroll-to-switch": "przewiń aby przełączyć",
"select": "Wybierz", "select": "Wybierz",
"set-0-to-disable": "Ustaw 0 aby wyłączyć", "set-0-to-disable": "Ustaw 0 aby wyłączyć",
"settings": "Ustawienia", "settings": "Ustawienia",

View File

@@ -6,5 +6,6 @@
"humidity": "Umiditate", "humidity": "Umiditate",
"pressure": "Presiune", "pressure": "Presiune",
"visibility": "Vizibilitate", "visibility": "Vizibilitate",
"wind": "Vânt" "wind": "Vânt",
"scroll-to-switch": "derulați pentru a comuta"
} }

View File

@@ -390,7 +390,7 @@ def instantiate_content(panel, container, content_list, icons_path=""):
if item == "playerctl": if item == "playerctl":
if item in panel: if item in panel:
playerctl = Playerctl(panel[item], icons_path) playerctl = Playerctl(panel[item], voc, icons_path)
container.pack_start(playerctl, False, False, panel["items-padding"]) container.pack_start(playerctl, False, False, panel["items-padding"])
else: else:
print("'{}' not defined in this panel instance".format(item)) print("'{}' not defined in this panel instance".format(item))

View File

@@ -5,9 +5,10 @@ import threading
from urllib.parse import unquote, urlparse from urllib.parse import unquote, urlparse
import gi import gi
gi.require_version('Playerctl', '2.0') gi.require_version('Playerctl', '2.0')
from gi.repository import GLib, Gtk from gi.repository import GLib, Gtk, Gdk
from gi.repository import Playerctl as Ctl from gi.repository import Playerctl as Ctl
import requests import requests
@@ -17,7 +18,7 @@ from nwg_panel.tools import check_key, eprint, local_dir, update_image
class Playerctl(Gtk.EventBox): class Playerctl(Gtk.EventBox):
PlayerOps = Enum('PlayerOps', ['PLAY_PAUSE', 'NEXT', 'PREVIOUS']) PlayerOps = Enum('PlayerOps', ['PLAY_PAUSE', 'NEXT', 'PREVIOUS'])
def __init__(self, settings, icons_path=""): def __init__(self, settings, voc, icons_path=""):
self.settings = settings self.settings = settings
self.icons_path = icons_path self.icons_path = icons_path
Gtk.EventBox.__init__(self) Gtk.EventBox.__init__(self)
@@ -33,12 +34,19 @@ class Playerctl(Gtk.EventBox):
check_key(settings, "angle", 0.0) check_key(settings, "angle", 0.0)
check_key(settings, "button-css-name", "") check_key(settings, "button-css-name", "")
self.voc = voc
self.old_cover_url = "" self.old_cover_url = ""
self.old_media_info = "" self.old_media_info = ""
self.player = None self.player = None
self.player_handler_ids = [] self.player_handler_ids = []
self.num_players = 0
self.player_idx = 0
self.add_events(Gdk.EventMask.SCROLL_MASK)
self.connect('scroll-event', self.on_scroll)
self.build_box() self.build_box()
self.subscribe() self.subscribe()
@@ -60,9 +68,16 @@ class Playerctl(Gtk.EventBox):
for name in reversed(self.manager.props.player_names): for name in reversed(self.manager.props.player_names):
self.manage_player_by_name(self.manager, name) self.manage_player_by_name(self.manager, name)
self.num_players = len(self.manager.props.players)
if self.num_players > 1:
self.num_players_lbl.set_text(f" {self.player_idx + 1}/{self.num_players} ")
self.num_players_lbl.set_tooltip_text(
f"Player {self.player_idx + 1}/{self.num_players}, {self.voc["scroll-to-switch"]}")
else:
self.num_players_lbl.set_text("")
if len(self.manager.props.players) > 0: if len(self.manager.props.players) > 0:
# Populate the top player only self.init_player(self.manager.props.players[self.player_idx])
self.init_player(self.manager.props.players[0])
@staticmethod @staticmethod
def manage_player_by_name(manager, name): def manage_player_by_name(manager, name):
@@ -70,11 +85,13 @@ class Playerctl(Gtk.EventBox):
manager.manage_player(player) manager.manage_player(player)
def on_name_appeared(self, manager, name): def on_name_appeared(self, manager, name):
self.subscribe()
self.deinit_player() self.deinit_player()
self.manage_player_by_name(manager, name) self.manage_player_by_name(manager, name)
self.init_player(manager.props.players[0]) self.init_player(manager.props.players[self.player_idx])
def on_player_vanished(self, manager, player): def on_player_vanished(self, manager, player):
self.subscribe()
# Non-active player vanished, do nothing # Non-active player vanished, do nothing
if self.player and player.props.player_name != self.player.props.player_name: if self.player and player.props.player_name != self.player.props.player_name:
return return
@@ -82,7 +99,7 @@ class Playerctl(Gtk.EventBox):
# Active player vanished, populate another one if exists # Active player vanished, populate another one if exists
self.deinit_player() self.deinit_player()
if len(manager.props.players) > 0: if len(manager.props.players) > 0:
self.init_player(manager.props.players[0]) self.init_player(manager.props.players[self.player_idx])
def init_player(self, player): def init_player(self, player):
self.player = player self.player = player
@@ -169,6 +186,20 @@ class Playerctl(Gtk.EventBox):
if not path: if not path:
update_image(self.cover_img, "music", self.settings["cover-size"], self.icons_path) update_image(self.cover_img, "music", self.settings["cover-size"], self.icons_path)
def on_scroll(self, widget, event):
if event.direction == Gdk.ScrollDirection.UP:
if self.player_idx < self.num_players - 1:
self.player_idx += 1
else:
self.player_idx = 0
if event.direction == Gdk.ScrollDirection.DOWN:
if self.player_idx > 0:
self.player_idx -= 1
else:
self.player_idx = self.num_players - 1
print(f"Switched to player {self.player_idx}")
self.subscribe()
def build_box(self): def build_box(self):
self.box = Gtk.Box(orientation=Gtk.Orientation.HORIZONTAL, spacing=0) self.box = Gtk.Box(orientation=Gtk.Orientation.HORIZONTAL, spacing=0)
if self.settings["angle"] != 0.0: if self.settings["angle"] != 0.0:
@@ -207,6 +238,11 @@ class Playerctl(Gtk.EventBox):
btn.connect("clicked", self.launch, self.PlayerOps.NEXT) btn.connect("clicked", self.launch, self.PlayerOps.NEXT)
button_box.pack_start(btn, False, False, 1) button_box.pack_start(btn, False, False, 1)
self.num_players_lbl = Gtk.Label.new("")
if self.settings["label-css-name"]:
self.num_players_lbl.set_property("name", self.settings["label-css-name"])
self.num_players_lbl.set_angle(self.settings["angle"])
self.label = AutoScrollLabel(self.settings["scroll"], self.label = AutoScrollLabel(self.settings["scroll"],
self.settings["chars"], self.settings["chars"],
self.settings["interval"]) self.settings["interval"])
@@ -221,10 +257,12 @@ class Playerctl(Gtk.EventBox):
self.box.pack_start(button_box, False, False, 2) self.box.pack_start(button_box, False, False, 2)
if self.settings["show-cover"]: if self.settings["show-cover"]:
self.box.pack_start(self.cover_img, False, False, 0) self.box.pack_start(self.cover_img, False, False, 0)
self.box.pack_start(self.label, False, False, 10) self.box.pack_start(self.num_players_lbl, False, False, 0)
self.box.pack_start(self.label, False, False, 5)
else: else:
if self.settings["show-cover"]: if self.settings["show-cover"]:
self.box.pack_start(self.cover_img, False, False, 2) self.box.pack_start(self.cover_img, False, False, 2)
self.box.pack_start(self.num_players_lbl, False, False, 0)
self.box.pack_start(self.label, False, False, 2) self.box.pack_start(self.label, False, False, 2)
self.box.pack_start(button_box, False, False, 10) self.box.pack_start(button_box, False, False, 10)