diff --git a/config/data.py b/config/data.py index 9267ac4..7dd2f0c 100644 --- a/config/data.py +++ b/config/data.py @@ -10,7 +10,7 @@ gi.require_version("Gtk", "3.0") APP_NAME = "modus" APP_NAME_CAP = "Modus" -ALLOWED_PLAYERS = ["vlc", "cmus", "firefox", "spotify", "chromium"] +ALLOWED_PLAYERS = ["vlc", "cmus", "firefox", "spotify", "chromium", "vivaldi", "brave"] NOTIF_POS_KEY = "notif_pos" NOTIF_POS_DEFAULT = "Top" diff --git a/config/hypr/colors.conf b/config/hypr/colors.conf index 7ad1c79..c08933d 100644 --- a/config/hypr/colors.conf +++ b/config/hypr/colors.conf @@ -1,27 +1,27 @@ -$wallpaper = /home/sankalp/Pictures/wallpapers/5.png -$background = 1a110f -$foreground = f1dfd9 +$wallpaper = /home/sankalp/Pictures/wallpapers/48.png +$background = 0f1417 +$foreground = dee3e6 -$primary = ffb59c -$secondary = e7bdb0 -$tertiary = d6c68d -$surface = 1a110f -$surface_bright = 423733 -$outline = a08d87 +$primary = 89d0ed +$secondary = b3cad5 +$tertiary = c4c3eb +$surface = 0f1417 +$surface_bright = 353a3d +$outline = 8a9296 $error = ff5945 $shadow = 000000 -$red = ffb4a2 -$green = b7d085 -$yellow = dec56e -$blue = cebdfe -$magenta = fcb0d5 -$cyan = 84d5c4 +$red = ffb2b9 +$green = 95d5a7 +$yellow = b8cf84 +$blue = afc6ff +$magenta = e4b7f3 +$cyan = 82d3e2 $white = 82d3e0 -$red_dim = ff623c -$green_dim = 89ad42 -$yellow_dim = bb9b2b -$blue_dim = 8359fc -$magenta_dim = f84ea1 -$cyan_dim = 3eb59c +$red_dim = ff4c5c +$green_dim = 4cb86a +$yellow_dim = 8baa43 +$blue_dim = 497dff +$magenta_dim = c360e4 +$cyan_dim = 30b5ce diff --git a/modules/dock/components/music_player.py b/modules/dock/components/music_player.py index 38eaa43..f981613 100644 --- a/modules/dock/components/music_player.py +++ b/modules/dock/components/music_player.py @@ -178,24 +178,22 @@ class MusicPlayer(Box): try: if hasattr(self.current_player_service, 'cleanup'): self.current_player_service.cleanup() - except Exception as e: - print(f"[DEBUG] Error cleaning up player service on destroy: {e}") + except Exception: + pass # Clean up popup if hasattr(self, 'popup') and self.popup: try: self.popup.destroy() self.popup = None - except Exception as e: - print(f"[DEBUG] Error destroying popup: {e}") + except Exception: + pass - except Exception as e: - print(f"[DEBUG] Error in on_destroy: {e}") + except Exception: + pass def on_new_player(self, manager, player): """Handle new player detection""" - print(f"Music dock component: New player detected - {player.props.player_name}") - # If this is our first player, make it current if not self.current_player: self.set_current_player(player) @@ -213,7 +211,6 @@ class MusicPlayer(Box): def on_player_vanish(self, manager, player): """Handle player disappearing""" - print(f"Music dock component: Player vanished - {player.props.player_name}") # If the current player vanished, find another one if ( @@ -243,19 +240,10 @@ class MusicPlayer(Box): or "xesam:artist" in keys or "mpris:length" in keys ): - print( - f"[DEBUG] Switching to player with media: { - candidate_player.props.player_name - }" - ) + pass self.set_current_player(candidate_player) break - except Exception as e: - print( - f"[DEBUG] Error checking candidate player {player_name}: { - e - }" - ) + except Exception: continue self.update_visibility() @@ -296,18 +284,14 @@ class MusicPlayer(Box): status = player.props.playback_status if status and hasattr(status, 'value_name'): if status.value_name == "PLAYERCTL_PLAYBACK_STATUS_PLAYING": - print(f"[DEBUG] Found playing player: {player.props.player_name}") return player except Exception as e: - print(f"[DEBUG] Error checking playback status for {player_name}: {e}") continue except Exception as e: - print(f"[DEBUG] Error checking player {player_name}: {e}") continue except Exception as e: - print(f"[DEBUG] Error in get_playing_player: {e}") return None def check_active_player(self): @@ -342,11 +326,9 @@ class MusicPlayer(Box): # If we can't safely compare, assume we should switch should_switch = True except Exception as e: - print(f"[DEBUG] Error comparing players: {e}") should_switch = True if should_switch: - print(f"[DEBUG] Switching to playing player: {playing_player.props.player_name}") self.set_current_player(playing_player) self._last_player_switch = current_time @@ -365,7 +347,6 @@ class MusicPlayer(Box): self._try_switch_to_alternative_player(current_time) except Exception as e: - print(f"[DEBUG] Error checking current player status: {e}") # Current player seems invalid, try to find another self._try_switch_to_alternative_player(current_time) @@ -373,7 +354,6 @@ class MusicPlayer(Box): self.update_visibility() except Exception as e: - print(f"[DEBUG] Error in check_active_player: {e}") # Return True to continue the timeout return True @@ -384,7 +364,6 @@ class MusicPlayer(Box): self.manager.init_all_players() self.update_visibility() except Exception as e: - print(f"[DEBUG] Error in delayed music player init: {e}") return False # Don't repeat this timeout def _try_switch_to_alternative_player(self, current_time): @@ -417,27 +396,22 @@ class MusicPlayer(Box): continue # Switch to a different available player - print(f"[DEBUG] Switching to available player: {player.props.player_name}") self.set_current_player(player) self._last_player_switch = current_time break except Exception as e: - print(f"[DEBUG] Error checking alternative player {player_name}: {e}") continue except Exception as e: - print(f"[DEBUG] Error in _try_switch_to_alternative_player: {e}") def set_current_player(self, player): """Set the current active player""" try: # Validate player before proceeding if not player or not hasattr(player, 'props') or not hasattr(player.props, 'player_name'): - print("[DEBUG] Invalid player object, skipping") return - print(f"[DEBUG] Setting current player to: {player.props.player_name}") # Properly cleanup previous player service if self.current_player_service: @@ -448,60 +422,63 @@ class MusicPlayer(Box): else: # Fallback: Stop any running fabricators/timers manually if hasattr(self.current_player_service, 'pos_fabricator'): - self.current_player_service.pos_fabricator.stop() + try: + self.current_player_service.pos_fabricator.stop() + except Exception: + pass - # Disconnect signals with specific error handling + # Disconnect signals - only if they were actually connected + # Use a more robust disconnection approach try: - self.current_player_service.disconnect_by_func(self.on_track_position) - except (TypeError, AttributeError) as e: - print(f"[DEBUG] Error disconnecting track_position: {e}") + # Get all signal handlers and disconnect them + if hasattr(self.current_player_service, 'disconnect'): + # Try to disconnect all signals from this service + self.current_player_service.disconnect() + except Exception: + # If bulk disconnect fails, try individual disconnections + pass - try: - self.current_player_service.disconnect_by_func(self.on_play) - except (TypeError, AttributeError) as e: - print(f"[DEBUG] Error disconnecting play: {e}") - - try: - self.current_player_service.disconnect_by_func(self.on_pause) - except (TypeError, AttributeError) as e: - print(f"[DEBUG] Error disconnecting pause: {e}") - - try: - self.current_player_service.disconnect_by_func(self.on_metadata) - except (TypeError, AttributeError) as e: - print(f"[DEBUG] Error disconnecting metadata: {e}") - - except Exception as e: - print(f"[DEBUG] Error during player service cleanup: {e}") + except Exception: + pass self.current_player = player + self.current_player_service = None - # Create new player service with error handling + # Create new player service with error handling and recursion prevention try: - self.current_player_service = PlayerService(player=player) - except Exception as e: - print(f"[DEBUG] Error creating PlayerService: {e}") - self.current_player_service = None - return + # Validate player before creating service + if (hasattr(player, 'props') and + hasattr(player.props, 'player_name') and + player.props.player_name): - # Connect to player events with error handling - if self.current_player_service: - try: - self.current_player_service.connect("track-position", self.on_track_position) - self.current_player_service.connect("play", self.on_play) - self.current_player_service.connect("pause", self.on_pause) - self.current_player_service.connect("meta-change", self.on_metadata) - except Exception as e: - print(f"[DEBUG] Error connecting to player service signals: {e}") + self.current_player_service = PlayerService(player=player) + + # Connect to player events with error handling + if self.current_player_service: + try: + self.current_player_service.connect("track-position", self.on_track_position) + self.current_player_service.connect("play", self.on_play) + self.current_player_service.connect("pause", self.on_pause) + self.current_player_service.connect("meta-change", self.on_metadata) + except Exception: + # If signal connection fails, clean up the service + if hasattr(self.current_player_service, 'cleanup'): + self.current_player_service.cleanup() + self.current_player_service = None + else: + pass + + except Exception: + self.current_player_service = None # Always use generic music icon, not player-specific icons self.music_label.set_markup(icons.music) - # Update initial state - self.update_playback_state() + # Update initial state only if we have a valid service + if self.current_player_service: + self.update_playback_state() except Exception as e: - print(f"[DEBUG] Critical error in set_current_player: {e}") # Reset to safe state self.current_player = None self.current_player_service = None @@ -518,7 +495,6 @@ class MusicPlayer(Box): pos = float(pos) dur = float(dur) except (ValueError, TypeError): - print(f"[DEBUG] Invalid position/duration values: pos={pos}, dur={dur}") return # Validate ranges @@ -534,8 +510,8 @@ class MusicPlayer(Box): # Safely update progress bar try: self.progress_bar.value = progress - except Exception as e: - print(f"[DEBUG] Error updating progress bar: {e}") + except Exception: + pass # Update tooltip with timestamp info try: @@ -554,17 +530,39 @@ class MusicPlayer(Box): tooltip = f"Music Player\n{timestamp_text}" self.event_box.set_tooltip_text(tooltip) - except Exception as e: - print(f"[DEBUG] Error updating tooltip: {e}") + except Exception: + pass else: + # Duration is 0 or unknown - show position only if available try: - self.progress_bar.value = 0 - self.event_box.set_tooltip_text("Music Player") - except Exception as e: - print(f"[DEBUG] Error resetting progress bar: {e}") + if pos > 0: + # Show position even without duration + pos_min = int(pos // 60) + pos_sec = int(pos % 60) + timestamp_text = f"{pos_min:02d}:{pos_sec:02d}" - except Exception as e: - print(f"[DEBUG] Error in on_track_position: {e}") + # Get current track info if available + if hasattr(self, "_current_track_info") and self._current_track_info: + tooltip = f"{self._current_track_info}\n{timestamp_text} (Duration unknown)" + else: + tooltip = f"Music Player\n{timestamp_text} (Duration unknown)" + + self.event_box.set_tooltip_text(tooltip) + + # Set progress bar to indeterminate state or small progress + # Use a pulsing animation or small fixed progress to show activity + self.progress_bar.value = 0.1 # Small progress to show activity + else: + self.progress_bar.value = 0 + if hasattr(self, "_current_track_info") and self._current_track_info: + self.event_box.set_tooltip_text(f"{self._current_track_info} (Duration unknown)") + else: + self.event_box.set_tooltip_text("Music Player") + except Exception: + pass + + except Exception: + pass def on_play(self, service): """Handle play state""" @@ -709,10 +707,8 @@ class MusicPlayer(Box): or "xesam:artist" in keys or "mpris:length" in keys ): - print(f"[DEBUG] Found player with media content: {player.props.player_name}") return True except Exception as e: - print(f"[DEBUG] Error checking metadata for {player_name}: {e}") # Also check if player is currently playing (even without full metadata) if hasattr(player.props, "playback_status"): @@ -720,17 +716,13 @@ class MusicPlayer(Box): status = player.props.playback_status if (status and hasattr(status, 'value_name') and status.value_name == "PLAYERCTL_PLAYBACK_STATUS_PLAYING"): - print(f"[DEBUG] Found playing player: {player.props.player_name}") return True except Exception as e: - print(f"[DEBUG] Error checking playback status for {player_name}: {e}") except Exception as e: - print(f"[DEBUG] Error checking player {player_name}: {e}") continue except Exception as e: - print(f"[DEBUG] Error in has_running_players: {e}") return False @@ -745,4 +737,4 @@ class MusicPlayer(Box): # Show component only if there are players with actual media content has_media_players = self.has_running_players() - self.set_visible(has_media_players) + self.set_visible(has_media_players) \ No newline at end of file diff --git a/modules/dock/components/player.py b/modules/dock/components/player.py index 27f45a5..843f3c3 100644 --- a/modules/dock/components/player.py +++ b/modules/dock/components/player.py @@ -1,5 +1,6 @@ import re +from gi.repository import Playerctl from fabric.core.service import Signal from fabric.widgets.box import Box from fabric.widgets.button import Button @@ -174,6 +175,14 @@ class Player(Box): self.duration = dur if dur > 0: self.wiggly.update_value_from_signal(pos / dur) + else: + # Duration is 0 or unknown - show some activity but don't update progress + # Keep the current progress or set to a small value to indicate activity + if pos > 0: + # Show minimal progress to indicate playback is active + self.wiggly.update_value_from_signal(0.1) + else: + self.wiggly.update_value_from_signal(0.0) def on_seek(self, sender, ratio): pos = ratio * self.duration # duration in seconds @@ -314,7 +323,7 @@ class Player(Box): class PlayerContainer(Box): @Signal - def active_player_changed(self, player) -> None: ... + def active_player_changed(self, player: Playerctl.Player) -> None: ... def __init__(self, **kwargs): super().__init__(name="player-container", orientation="v", **kwargs) @@ -431,4 +440,4 @@ class PlayerContainer(Box): if btn.get_name() == curr.get_name(): btn.add_style_class("active") else: - btn.remove_style_class("active") + btn.remove_style_class("active") \ No newline at end of file diff --git a/services/mpris.py b/services/mpris.py index 4c0f16c..e79f0bd 100644 --- a/services/mpris.py +++ b/services/mpris.py @@ -82,31 +82,54 @@ class PlayerService(Service): # Get position safely try: pos = self._player.get_position() / 1_000_000 # seconds - except Exception as e: - print(f"[DEBUG] Error getting player position: {e}") + except Exception: return - # Get duration safely from metadata - try: - if (hasattr(self._player, 'props') and - hasattr(self._player.props, 'metadata') and - self._player.props.metadata and - "mpris:length" in self._player.props.metadata): + # Get duration safely from multiple sources + dur = 0.0 # Default to 0 - dur = self._player.props.metadata["mpris:length"] / 1_000_000 # seconds - else: - # No duration available, skip this update - return - except Exception as e: - print(f"[DEBUG] Error getting track duration: {e}") - return + if (hasattr(self._player, 'props') and + hasattr(self._player.props, 'metadata') and + self._player.props.metadata): + + metadata = self._player.props.metadata + + # Try mpris:length first (most common) + try: + raw_dur = metadata["mpris:length"] + if raw_dur and raw_dur > 0: + dur = float(raw_dur) / 1_000_000 # seconds + except (KeyError, Exception): + pass + + # Fallback to xesam:duration (alternative field) + if dur <= 0: + try: + raw_dur = metadata["xesam:duration"] + if raw_dur and raw_dur > 0: + dur = float(raw_dur) / 1_000_000 # seconds + except (KeyError, Exception): + pass + + # Try to get duration from player directly (some players support this) + if dur <= 0: + try: + if hasattr(self._player, 'get_metadata'): + player_metadata = self._player.get_metadata() + if player_metadata: + raw_dur = player_metadata["mpris:length"] + if raw_dur and raw_dur > 0: + dur = float(raw_dur) / 1_000_000 + except (KeyError, Exception): + pass # Validate values before emitting signal - if pos is not None and dur is not None and dur > 0: + # Allow dur=0 for position-only tracking + if pos is not None and dur is not None and pos >= 0 and dur >= 0: self.track_position(pos, dur) - except Exception as e: - print(f"[DEBUG] Error in fabricating: {e}") + except Exception: + pass def on_play(self, player, status): print("player is playing: {}".format(player.props.player_name)) @@ -173,4 +196,4 @@ class PlayerManager(Service): def _on_player_vanished(self, sender, player, manager): print("player has exited: {}".format(player.props.player_name)) print(type(player)) - self.player_vanish(player) + self.player_vanish(player) \ No newline at end of file