refactor(src/window/controlcenter): centralize fallback artwork path and streamline UI updates
Replaced get_relative_path with PLAYER_FALLBACK_ART and simplified image handling via apply_player_art.
This commit is contained in:
2 files changed
+55
-113
No files matched your search
@@ -1,10 +1,7 @@
|
||||
import weakref
|
||||
|
||||
from fabric.utils import (
|
||||
GLib,
|
||||
bulk_connect,
|
||||
get_relative_path,
|
||||
os,
|
||||
)
|
||||
from fabric.widgets.box import Box
|
||||
from fabric.widgets.button import Button
|
||||
@@ -15,20 +12,13 @@ from fabric.widgets.scale import Scale
|
||||
from fabric.widgets.stack import Stack
|
||||
from fabric.widgets.wayland import WaylandWindow as Window
|
||||
|
||||
import shared.data as data
|
||||
from services.mpris import PlayerManager, PlayerService
|
||||
from utils.utils import svg_file
|
||||
|
||||
CACHE_DIR = f"{data.CACHE_DIR}/media"
|
||||
_shared_mpris_manager = None
|
||||
_artwork_cache = {}
|
||||
|
||||
|
||||
def get_shared_mpris_manager():
|
||||
global _shared_mpris_manager
|
||||
if _shared_mpris_manager is None:
|
||||
_shared_mpris_manager = PlayerManager()
|
||||
return _shared_mpris_manager
|
||||
from window.controlcenter.player import (
|
||||
apply_player_art,
|
||||
get_shared_mpris_manager,
|
||||
PLAYER_FALLBACK_ART,
|
||||
)
|
||||
|
||||
|
||||
class EmbeddedExpandedPlayer(Box):
|
||||
@@ -97,8 +87,8 @@ class PlayerBoxStack(Box):
|
||||
super().destroy()
|
||||
|
||||
def _create_no_media_box(self):
|
||||
fallback_cover_path = get_relative_path("../../assets/icons/music.svg")
|
||||
album_cover = Box(name="macos-album-image-no")
|
||||
fallback_cover_path = PLAYER_FALLBACK_ART
|
||||
album_cover = Box(style_classes="album-image-c")
|
||||
album_cover.set_style(f"background-image:url('{fallback_cover_path}')")
|
||||
|
||||
track_title = Label(
|
||||
@@ -284,7 +274,7 @@ class PlayerBox(Box):
|
||||
super().__init__(h_align="center", name="player-box", h_expand=True, **kwargs)
|
||||
self.player = player
|
||||
self.player_stack = player_stack
|
||||
self.fallback_cover_path = get_relative_path("../../assets/icons/music.svg")
|
||||
self.fallback_cover_path = PLAYER_FALLBACK_ART
|
||||
self.cover_path = self.fallback_cover_path
|
||||
self.exit = False
|
||||
self._user_seeking = False
|
||||
@@ -292,7 +282,7 @@ class PlayerBox(Box):
|
||||
self._property_bindings = []
|
||||
self._seekbar_signal_ids = []
|
||||
|
||||
self.album_cover = Box(name="macos-album-image")
|
||||
self.album_cover = Box(style_classes="album-image-c")
|
||||
self.album_cover.set_style(
|
||||
f"background-image:url('{self.fallback_cover_path}')"
|
||||
)
|
||||
@@ -505,11 +495,9 @@ class PlayerBox(Box):
|
||||
|
||||
self.seek_bar.connect("realize", self._on_seek_bar_realized)
|
||||
|
||||
initial_art = self.player.get_artwork()
|
||||
if initial_art:
|
||||
self.album_cover.set_style(f"background-image:url('{initial_art}')")
|
||||
else:
|
||||
self.set_image()
|
||||
result = apply_player_art(self.album_cover, self.player)
|
||||
if result:
|
||||
self.cover_path = result
|
||||
|
||||
def update_buttons(self, player_buttons, show_buttons):
|
||||
self.stack_buttons_box.children = []
|
||||
@@ -612,56 +600,18 @@ class PlayerBox(Box):
|
||||
self.player_stack.on_player_playback_changed(self, status)
|
||||
|
||||
def _on_artwork_change(self, service, local_path, *_):
|
||||
if not self.exit and local_path:
|
||||
GLib.idle_add(
|
||||
lambda: (
|
||||
self.album_cover.set_style(f"background-image:url('{local_path}')")
|
||||
if os.path.isfile(local_path)
|
||||
else None
|
||||
)
|
||||
)
|
||||
if self.exit:
|
||||
return
|
||||
result = apply_player_art(self.album_cover, self.player, service, local_path)
|
||||
if result:
|
||||
self.cover_path = result
|
||||
|
||||
def set_image(self, service=None, path=None, *_):
|
||||
if self.exit or self.player is None:
|
||||
return
|
||||
if path:
|
||||
self.cover_path = path
|
||||
self.album_cover.set_style(f"background-image:url('{self.cover_path}')")
|
||||
return
|
||||
url = self.player.arturl
|
||||
if url:
|
||||
new_cover_path = (
|
||||
(
|
||||
CACHE_DIR
|
||||
+ "/"
|
||||
+ GLib.compute_checksum_for_string(GLib.ChecksumType.SHA1, url, -1)
|
||||
)
|
||||
if "file://" != url[0:7]
|
||||
else url[7:]
|
||||
)
|
||||
if new_cover_path != self.cover_path:
|
||||
self.cover_path = new_cover_path
|
||||
if os.path.exists(self.cover_path):
|
||||
self.album_cover.set_style(
|
||||
f"background-image:url('{self.cover_path}')"
|
||||
)
|
||||
return
|
||||
from fabric.utils import Gio
|
||||
|
||||
Gio.File.new_for_uri(uri=url).copy_async(
|
||||
Gio.File.new_for_path(self.cover_path),
|
||||
Gio.FileCopyFlags.OVERWRITE,
|
||||
GLib.PRIORITY_DEFAULT,
|
||||
None,
|
||||
None,
|
||||
lambda src, res, *_: (
|
||||
self.album_cover.set_style(
|
||||
f"background-image:url('{self.cover_path}')"
|
||||
)
|
||||
if not self.exit and os.path.isfile(self.cover_path)
|
||||
else None
|
||||
),
|
||||
)
|
||||
result = apply_player_art(self.album_cover, self.player, service, path)
|
||||
if result:
|
||||
self.cover_path = result
|
||||
|
||||
def _on_track_position(self, service, pos: float, dur: float):
|
||||
if self.exit or self._user_seeking:
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
from fabric.utils import Gio, GLib, bulk_connect, get_relative_path, logger, os
|
||||
from fabric.utils import bulk_connect, get_relative_path, logger, os
|
||||
from fabric.widgets.box import Box
|
||||
from fabric.widgets.button import Button
|
||||
from fabric.widgets.centerbox import CenterBox
|
||||
@@ -12,7 +12,7 @@ from services.mpris import PlayerManager, PlayerService
|
||||
from utils.utils import svg_file
|
||||
|
||||
CACHE_DIR = f"{data.CACHE_DIR}/media"
|
||||
MEDIA_CACHE = CACHE_DIR
|
||||
PLAYER_FALLBACK_ART = get_relative_path("../../assets/icons/music.svg")
|
||||
if not os.path.exists(CACHE_DIR):
|
||||
os.makedirs(CACHE_DIR)
|
||||
|
||||
@@ -36,6 +36,31 @@ def cleanup_shared_mpris_manager():
|
||||
_shared_mpris_manager = None
|
||||
|
||||
|
||||
def apply_player_art(album_cover_widget, player, service=None, path=None):
|
||||
"""
|
||||
Single source of truth for applying album art to any player widget.
|
||||
|
||||
Call patterns:
|
||||
- On init / metadata change: apply_player_art(widget, player)
|
||||
- From artwork-change signal: apply_player_art(widget, player, service_obj, local_path)
|
||||
|
||||
Returns the applied path, or None if no art is available yet (backend will
|
||||
emit artwork-change when the async download completes).
|
||||
"""
|
||||
# artwork-change signal emits (service_obj, local_path_str)
|
||||
if path and isinstance(path, str) and os.path.exists(path):
|
||||
album_cover_widget.set_style(f"background-image:url('{path}')")
|
||||
return path
|
||||
# Check if backend already has it cached from a previous download
|
||||
if player:
|
||||
cached = player.get_artwork()
|
||||
if cached and os.path.exists(cached):
|
||||
album_cover_widget.set_style(f"background-image:url('{cached}')")
|
||||
return cached
|
||||
# Nothing yet — backend will emit artwork-change when download finishes
|
||||
return None
|
||||
|
||||
|
||||
class PlayerBoxStack(Box):
|
||||
def __init__(
|
||||
self, mpris_manager: PlayerManager = None, control_center=None, **kwargs
|
||||
@@ -275,7 +300,7 @@ class PlayerBox(Box):
|
||||
self.player = player
|
||||
self.player_stack = player_stack
|
||||
self.control_center = control_center
|
||||
self.cover_path = get_relative_path("../../assets/icons/music.svg")
|
||||
self.cover_path = PLAYER_FALLBACK_ART
|
||||
self.exit = False
|
||||
self._signal_connections = []
|
||||
|
||||
@@ -394,15 +419,15 @@ class PlayerBox(Box):
|
||||
"play": self._on_playback_change,
|
||||
"pause": self._on_playback_change,
|
||||
"meta-change": self._on_metadata,
|
||||
"artwork-change": self.set_image,
|
||||
},
|
||||
)
|
||||
for handler_id in connections:
|
||||
self._signal_connections.append((self.player, handler_id))
|
||||
|
||||
initial_art = self.player.get_artwork()
|
||||
if initial_art:
|
||||
self.cover_path = initial_art
|
||||
self.album_cover.set_style(f"background-image:url('{self.cover_path}')")
|
||||
result = apply_player_art(self.album_cover, self.player)
|
||||
if result:
|
||||
self.cover_path = result
|
||||
|
||||
def _on_outer_box_clicked(self, *_):
|
||||
if self.control_center and hasattr(self.control_center, "open_expanded_player"):
|
||||
@@ -442,42 +467,9 @@ class PlayerBox(Box):
|
||||
def set_image(self, service=None, path=None, *_):
|
||||
if self.exit or self.player is None:
|
||||
return
|
||||
if path:
|
||||
self.cover_path = path
|
||||
self.album_cover.set_style(f"background-image:url('{self.cover_path}')")
|
||||
return
|
||||
url = self.player.arturl
|
||||
if url:
|
||||
new_cover_path = (
|
||||
(
|
||||
MEDIA_CACHE
|
||||
+ "/"
|
||||
+ GLib.compute_checksum_for_string(GLib.ChecksumType.SHA1, url, -1)
|
||||
)
|
||||
if "file://" != url[0:7]
|
||||
else url[7:]
|
||||
)
|
||||
if new_cover_path != self.cover_path:
|
||||
self.cover_path = new_cover_path
|
||||
if os.path.exists(self.cover_path):
|
||||
self.album_cover.set_style(
|
||||
f"background-image:url('{self.cover_path}')"
|
||||
)
|
||||
return
|
||||
Gio.File.new_for_uri(uri=url).copy_async(
|
||||
Gio.File.new_for_path(self.cover_path),
|
||||
Gio.FileCopyFlags.OVERWRITE,
|
||||
GLib.PRIORITY_DEFAULT,
|
||||
None,
|
||||
None,
|
||||
lambda src, res, *_: (
|
||||
self.album_cover.set_style(
|
||||
f"background-image:url('{self.cover_path}')"
|
||||
)
|
||||
if not self.exit and os.path.isfile(self.cover_path)
|
||||
else None
|
||||
),
|
||||
)
|
||||
result = apply_player_art(self.album_cover, self.player, service, path)
|
||||
if result:
|
||||
self.cover_path = result
|
||||
|
||||
def suspend(self):
|
||||
self.exit = True
|
||||
|
||||
Reference in new issue
Block a user