From 75868b32d07aafe46b69649d2da0dc2c833f112d Mon Sep 17 00:00:00 2001 From: Warry Date: Thu, 4 Dec 2025 12:03:31 +0100 Subject: refactor: Restructure GUI components into separate modules for improved maintainability --- tidal_dl_ng/gui_covers.py | 161 ---------------------------------------------- 1 file changed, 161 deletions(-) delete mode 100644 tidal_dl_ng/gui_covers.py (limited to 'tidal_dl_ng/gui_covers.py') diff --git a/tidal_dl_ng/gui_covers.py b/tidal_dl_ng/gui_covers.py deleted file mode 100644 index 858ab11..0000000 --- a/tidal_dl_ng/gui_covers.py +++ /dev/null @@ -1,161 +0,0 @@ -"""Cover management for GUI - Handles cover loading, caching and display.""" - -from contextlib import suppress - -from PySide6 import QtGui - -from tidal_dl_ng.cache import CoverPixmapCache -from tidal_dl_ng.download import Download -from tidal_dl_ng.helper.path import resource_path -from tidal_dl_ng.logger import logger_gui -from tidal_dl_ng.worker import Worker - - -class CoverManager: - """Manages cover art loading, caching and display operations.""" - - def __init__(self, parent_window, threadpool, info_tab_widget): - """Initialize the cover manager. - - Args: - parent_window: Main window instance - threadpool: QThreadPool for async operations - info_tab_widget: InfoTabWidget instance for display - """ - self.parent = parent_window - self.threadpool = threadpool - self.info_tab = info_tab_widget - self.cache = CoverPixmapCache() - self.cover_url_current = "" - - def load_cover(self, media, use_cache_check: bool = True): - """Load and display cover for media item. - - Args: - media: Media object (Track, Album, etc.) - use_cache_check: If True, check cache before loading - """ - if use_cache_check: - # Try cache first for instant display - cover_url = self._get_cover_url(media) - if cover_url: - if cover_url == self.cover_url_current: - return # Already displayed - - cached_pixmap = self.cache.get(cover_url) - if cached_pixmap: - self._display_cover(cached_pixmap, cover_url) - return - - # Load asynchronously - worker = Worker(self._load_cover_async, media) - self.threadpool.start(worker) - - def _load_cover_async(self, media): - """Load cover in background thread.""" - # Emit spinner on tab widget instead of InfoTabWidget (which is QObject, not QWidget) - tab_widget = self.info_tab.tab_widget if hasattr(self.info_tab, "tab_widget") else None - if tab_widget: - self.parent.s_spinner_start.emit(tab_widget) - - try: - cover_url = self._get_cover_url(media) - - if cover_url and self.cover_url_current != cover_url: - # Check cache again (thread-safe) - cached_pixmap = self.cache.get(cover_url) - if cached_pixmap: - self._display_cover(cached_pixmap, cover_url) - else: - # Download and cache - data_cover = Download.cover_data(cover_url) - pixmap = QtGui.QPixmap() - pixmap.loadFromData(data_cover) - self.cache.set(cover_url, pixmap) - self._display_cover(pixmap, cover_url) - elif not cover_url: - self._display_default_cover() - except Exception as e: - logger_gui.warning(f"Failed to load cover: {e}") - self._display_default_cover() - finally: - self.parent.s_spinner_stop.emit() - - def _get_cover_url(self, media) -> str | None: - """Extract cover URL from media object.""" - with suppress(Exception): - if hasattr(media, "album") and media.album: - return media.album.image() - if hasattr(media, "image") and callable(getattr(media, "image", None)): - return media.image() - return None - - def _display_cover(self, pixmap: QtGui.QPixmap, url: str): - """Display a pixmap on the info tab.""" - self.info_tab.set_cover_pixmap(pixmap) - self.info_tab.cover_url_current = url - self.cover_url_current = url - - def _display_default_cover(self): - """Display default cover image.""" - path_image = resource_path("tidal_dl_ng/ui/default_album_image.png") - pixmap = QtGui.QPixmap(path_image) - self.info_tab.set_cover_pixmap(pixmap) - self.info_tab.cover_url_current = "" - self.cover_url_current = "" - - def preload_covers_for_playlist(self, items: list) -> None: - """Preload cover pixmaps for a list of tracks in background. - - Args: - items: List of Track/Video objects to preload covers for. - """ - - def worker() -> None: - # Extract unique cover URLs - cover_urls = set() - for item in items[:50]: # Limit to first 50 - with suppress(Exception): - url = self._get_cover_url(item) - if url: - cover_urls.add(url) - - # Preload each unique cover - for cover_url in cover_urls: - if self.cache.get(cover_url): - continue # Already cached - - with suppress(Exception): - data_cover = Download.cover_data(cover_url) - pixmap = QtGui.QPixmap() - pixmap.loadFromData(data_cover) - self.cache.set(cover_url, pixmap) - logger_gui.debug(f"Preloaded cover: {cover_url[:50]}...") - - worker_obj = Worker(worker) - self.threadpool.start(worker_obj) - - def _queue_cover_fetch(self, media): - """Queue a cover fetch operation for a media item.""" - with suppress(Exception): - # previously try/except/pass - self.threadpool.start(Worker(self.load_cover, media)) - - def _fetch_cover_pixmap(self, media, use_cache_check: bool): - """Fetch cover pixmap for media, with optional cache check.""" - with suppress(Exception): - # previously try/except/continue inside loop - pixmap = self.cache.get(self._get_cover_url(media)) - if pixmap: - return pixmap - - # If not in cache, download cover - cover_url = self._get_cover_url(media) - if cover_url: - data_cover = Download.cover_data(cover_url) - pixmap = QtGui.QPixmap() - pixmap.loadFromData(data_cover) - self.cache.set(cover_url, pixmap) - return pixmap - - return None -- cgit v1.3.1