diff --git a/src/__init__.py b/src/__init__.py index c498e0f..aae3b90 100644 --- a/src/__init__.py +++ b/src/__init__.py @@ -17,3 +17,16 @@ if os.path.exists(localedirdev): # Set GSettings schema dir (if not set already) if not os.environ.get('GSETTINGS_SCHEMA_DIR'): os.environ['GSETTINGS_SCHEMA_DIR'] = datadirdev + + +class Environment: + """Wrapper class to access environment settings.""" + + def get_srcdir(): + return srcdir + + def get_data(subdir): + return os.path.join(datadir, subdir) + + def get_locale(): + return localedir diff --git a/src/application.py b/src/application.py index c39b929..23f482e 100644 --- a/src/application.py +++ b/src/application.py @@ -14,12 +14,11 @@ class Application(Gtk.Application): ID = 'xyz.suruatoel.mcg' DOMAIN = 'mcg' - def __init__(self, version): + def __init__(self): super().__init__(application_id=Application.ID, flags=Gio.ApplicationFlags.FLAGS_NONE) self._window = None self._info_dialog = None - self._version = version self._verbosity = logging.WARNING self.set_accels_for_action('window.close', ['q']) self.set_accels_for_action('win.show-help-overlay', ['k']) @@ -53,7 +52,7 @@ class Application(Gtk.Application): self._info_dialog = Adw.AboutDialog() self._info_dialog.set_application_icon("xyz.suruatoel.mcg") self._info_dialog.set_application_name("CoverGrid") - self._info_dialog.set_version(self._version) + self._info_dialog.set_version("3.2.1") self._info_dialog.set_comments( """CoverGrid is a client for the Music Player Daemon, focusing on \ albums instead of single tracks.""") @@ -78,10 +77,10 @@ albums instead of single tracks.""") style_manager.set_color_scheme(Adw.ColorScheme.PREFER_DARK) def _load_css(self): - style_provider = Gtk.CssProvider() - style_provider.load_from_resource(self._get_resource_path('gtk.css')) + styleProvider = Gtk.CssProvider() + styleProvider.load_from_resource(self._get_resource_path('gtk.css')) Gtk.StyleContext.add_provider_for_display( - Gdk.Display.get_default(), style_provider, + Gdk.Display.get_default(), styleProvider, Gtk.STYLE_PROVIDER_PRIORITY_APPLICATION) def _setup_actions(self): diff --git a/src/client.py b/src/client.py index 17b7522..ac7235b 100644 --- a/src/client.py +++ b/src/client.py @@ -22,7 +22,7 @@ class MPDException(Exception): def _parse_error(self, error): if error: - parts = re.match(r"\[(\d+)@(\d+)\]\s\{(\w+)\}\s(.*)", error) + parts = re.match("\[(\d+)@(\d+)\]\s\{(\w+)\}\s(.*)", error) if parts: self._error_number = int(parts.group(1)) self._command_number = int(parts.group(2)) @@ -298,7 +298,7 @@ class Client(Base): resources = socket.getaddrinfo(host, port, socket.AF_UNSPEC, socket.SOCK_STREAM, socket.IPPROTO_TCP) for res in resources: - af, socktype, proto, _, sa = res + af, socktype, proto, canonname, sa = res try: sock = socket.socket(af, socktype, proto) sock.setsockopt(socket.SOL_SOCKET, socket.SO_KEEPALIVE, 1) @@ -542,6 +542,8 @@ class Client(Base): def _playpause(self): """Action: Perform the real play/pause command.""" + #status = self._parse_dict(self._call('status')) + #if 'state' in status: if self._state == 'play': self._call('pause') else: @@ -651,7 +653,7 @@ class Client(Base): return future def _add_action_future(self, future, method, *args): - """Add an action to the action list based on a future.""" + """Add an action to the action list based on a futre.""" self._logger.debug("add action future %r (%r)", method.__name__, args) action = (future, method, args) self._actions.put(action) @@ -752,6 +754,7 @@ class Client(Base): data = None size = 1 offset = 0 + index = 0 # Read data until size is reached while offset < size: @@ -772,7 +775,7 @@ class Client(Base): self._logger.debug("size: %d", size) # For some commands the second line is the mimetype if has_mimetype: - self._parse_dict([self._read_line()])['type'] + mimetype = self._parse_dict([self._read_line()])['type'] # Next line is the count of bytes read binary = int(self._parse_dict([self._read_line()])['binary']) self._logger.debug("binary: %d", binary) @@ -785,7 +788,7 @@ class Client(Base): # Read actual bytes self._read_bytes(data_view, binary) offset += binary - # Read line break to complete previous response + # Read line break to complete previous repsonse self._read_line() # Read command completion end = self._read_line() @@ -828,12 +831,12 @@ class Client(Base): self._buffer = buf def _parse_dict(self, response): - dictionary = {} + dict = {} if response: for line in response: key, value = self._split_line(line) - dictionary[key] = value - return dictionary + dict[key] = value + return dict def _parse_list(self, response, delimiters): entry = {} @@ -843,6 +846,11 @@ class Client(Base): if entry and key in delimiters: yield entry entry = {} + #if key in entry.keys(): + # if entry[key] is not list: + # entry[key] = [entry[key]] + # entry[key].append(value) + #else: entry[key] = value if entry: yield entry @@ -855,13 +863,13 @@ class Client(Base): album = None if 'album' not in song: song['album'] = MCGAlbum.DEFAULT_ALBUM - album_id = Utils.generate_id(song['album']) - if lookup and album_id in self._albums.keys(): - album = self._albums[album_id] + id = Utils.generate_id(song['album']) + if lookup and id in self._albums.keys(): + album = self._albums[id] else: album = MCGAlbum(song['album'], self._host) if lookup: - self._albums[album_id] = album + self._albums[id] = album return album def _extract_track(self, song): @@ -919,7 +927,7 @@ class MCGAlbum: def __init__(self, title, host): self._artists = [] self._albumartists = [] - self._paths = [] + self._pathes = [] if type(title) is list: title = title[0] self._title = title @@ -981,8 +989,8 @@ class MCGAlbum: ): self._dates.append(track.get_date()) path = os.path.dirname(track.get_file()) - if path not in self._paths: - self._paths.append(path) + if path not in self._pathes: + self._pathes.append(path) if track.get_last_modified(): if ( not self._last_modified @@ -1027,9 +1035,8 @@ class MCGAlbum: return False return True - @staticmethod def compare(album1, album2, criterion=None, reverse=False): - if criterion is None: + if criterion == None: criterion = SortOrder.TITLE if criterion == SortOrder.ARTIST: value_function = "get_artists" @@ -1040,22 +1047,22 @@ class MCGAlbum: elif criterion == SortOrder.MODIFIED: value_function = "get_last_modified" - reverse_multiplier = -1 if reverse else 1 + reverseMultiplier = -1 if reverse else 1 value1 = getattr(album1, value_function)() value2 = getattr(album2, value_function)() if value1 is None and value2 is None: return 0 elif value1 is None: - return -1 * reverse_multiplier + return -1 * reverseMultiplier elif value2 is None: - return 1 * reverse_multiplier + return 1 * reverseMultiplier if value1 < value2: - return -1 * reverse_multiplier + return -1 * reverseMultiplier elif value1 == value2: return 0 else: - return 1 * reverse_multiplier + return 1 * reverseMultiplier class MCGTrack: @@ -1140,7 +1147,7 @@ class MCGTrack: if date_string: try: self._last_modified = dateutil.parser.isoparse(date_string) - except ValueError: + except ValueError as e: self._logger.debug("Invalid date format: %s", date_string) def get_last_modified(self): diff --git a/src/coverpanel.py b/src/coverpanel.py index ba09e16..88988b5 100644 --- a/src/coverpanel.py +++ b/src/coverpanel.py @@ -54,22 +54,21 @@ class CoverPanel(Gtk.Overlay): GObject.idle_add(self._enable_tracklist) # Click handler for image - click_controller = Gtk.GestureClick() - click_controller.connect('pressed', self.on_cover_box_pressed) - self.cover_box.add_controller(click_controller) + clickController = Gtk.GestureClick() + clickController.connect('pressed', self.on_cover_box_pressed) + self.cover_box.add_controller(clickController) # Button controller for songs scale - button_controller = Gtk.GestureClick() - button_controller.connect('pressed', self.on_songs_scale_pressed) - button_controller.connect('unpaired-release', - self.on_songs_scale_released) - self.songs_scale.add_controller(button_controller) + buttonController = Gtk.GestureClick() + buttonController.connect('pressed', self.on_songs_scale_pressed) + buttonController.connect('unpaired-release', + self.on_songs_scale_released) + self.songs_scale.add_controller(buttonController) def get_toolbar(self): return self.toolbar def set_selected(self, selected): - """The cover panel does not use selections""" pass def on_cover_box_pressed(self, widget, npress, x, y): @@ -153,7 +152,7 @@ class CoverPanel(Gtk.Overlay): # Load image and draw it try: self._cover_pixbuf = Utils.load_pixbuf(data) - except Exception: + except Exception as e: self._logger.exception("Failed to set albumart") self._cover_pixbuf = None else: @@ -204,6 +203,9 @@ class CoverPanel(Gtk.Overlay): self.cover_spinner.stop() def _resize_image(self): + """Diese Methode skaliert das geladene Bild aus dem Pixelpuffer + auf die Größe des Fensters unter Beibehalt der Seitenverhältnisse + """ # Get size size_width = self.cover_stack.get_size(Gtk.Orientation.HORIZONTAL) size_height = self.cover_stack.get_size(Gtk.Orientation.HORIZONTAL) @@ -224,10 +226,10 @@ class CoverPanel(Gtk.Overlay): return # Skalierungswert für Breite und Höhe ermitteln - ratio_w = float(size_width) / float(pixbuf.get_width()) - ratio_h = float(size_height) / float(pixbuf.get_height()) + ratioW = float(size_width) / float(pixbuf.get_width()) + ratioH = float(size_height) / float(pixbuf.get_height()) # Kleineren beider Skalierungswerte nehmen, nicht Hochskalieren - ratio = min(ratio_w, ratio_h) + ratio = min(ratioW, ratioH) ratio = min(ratio, 1) # Neue Breite und Höhe berechnen width = int(math.floor(pixbuf.get_width() * ratio)) diff --git a/src/librarypanel.py b/src/librarypanel.py index 488528b..8027620 100644 --- a/src/librarypanel.py +++ b/src/librarypanel.py @@ -116,10 +116,10 @@ class LibraryPanel(Adw.Bin): } # Button controller for grid scale - button_controller = Gtk.GestureClick() - button_controller.connect('unpaired-release', - self.on_grid_scale_released) - self.grid_scale.add_controller(button_controller) + buttonController = Gtk.GestureClick() + buttonController.connect('unpaired-release', + self.on_grid_scale_released) + self.grid_scale.add_controller(buttonController) def get_headerbar_standalone(self): return self._headerbar_standalone @@ -151,8 +151,8 @@ class LibraryPanel(Adw.Bin): def on_grid_scale_released(self, widget, x, y, npress, sequence): size = math.floor(self.grid_scale.get_value()) - grid_range = self.grid_scale.get_adjustment() - if size < grid_range.get_lower() or size > grid_range.get_upper(): + range = self.grid_scale.get_adjustment() + if size < range.get_lower() or size > range.get_upper(): return self._item_size = size self.emit('item-size-changed', size) @@ -162,8 +162,8 @@ class LibraryPanel(Adw.Bin): @Gtk.Template.Callback() def on_grid_scale_changed(self, widget): size = math.floor(self.grid_scale.get_value()) - grid_range = widget.get_adjustment() - if size < grid_range.get_lower() or size > grid_range.get_upper(): + range = widget.get_adjustment() + if size < range.get_lower() or size > range.get_upper(): return self._set_widget_grid_size(self.library_grid, size, True) @@ -200,9 +200,9 @@ class LibraryPanel(Adw.Bin): # Get selected album item = self._library_grid_filter.get_item(position) album = item.get_album() - album_id = album.get_id() + id = album.get_id() self._selected_albums = [album] - self.emit('albumart', album_id) + self.emit('albumart', id) # Show standalone album if widget.get_model() == self._library_grid_selection_single: @@ -297,7 +297,7 @@ class LibraryPanel(Adw.Bin): # Load image and draw it try: self._standalone_pixbuf = Utils.load_pixbuf(data) - except Exception: + except Exception as e: self._logger.exception("Failed to set albumart") self._standalone_pixbuf = self._get_default_image() else: @@ -415,9 +415,9 @@ class LibraryPanel(Adw.Bin): lower = int(self.grid_scale.get_adjustment().get_lower()) upper = int(self.grid_scale.get_adjustment().get_upper()) - count_min = max(int(width / upper), 1) - count_max = max(int(width / lower), 1) - for index in range(count_min, count_max): + countMin = max(int(width / upper), 1) + countMax = max(int(width / lower), 1) + for index in range(countMin, countMax): pixel = int(width / index) pixel = pixel - (2 * int(pixel / 100)) self.grid_scale.add_mark(pixel, Gtk.PositionType.BOTTOM, None) @@ -431,6 +431,9 @@ class LibraryPanel(Adw.Bin): self.emit('close-standalone') def _resize_standalone_image(self): + """Diese Methode skaliert das geladene Bild aus dem Pixelpuffer + auf die Größe des Fensters unter Beibehalt der Seitenverhältnisse + """ # Get size size_width = self.standalone_stack.get_width() size_height = self.standalone_stack.get_height() @@ -442,10 +445,10 @@ class LibraryPanel(Adw.Bin): return # Skalierungswert für Breite und Höhe ermitteln - ratio_w = float(size_width) / float(pixbuf.get_width()) - ratio_h = float(size_height) / float(pixbuf.get_height()) + ratioW = float(size_width) / float(pixbuf.get_width()) + ratioH = float(size_height) / float(pixbuf.get_height()) # Kleineren beider Skalierungswerte nehmen, nicht Hochskalieren - ratio = min(ratio_w, ratio_h) + ratio = min(ratioW, ratioH) ratio = min(ratio, 1) # Neue Breite und Höhe berechnen width = int(math.floor(pixbuf.get_width() * ratio)) diff --git a/src/main.py b/src/main.py index 319beff..bc1476c 100644 --- a/src/main.py +++ b/src/main.py @@ -4,5 +4,5 @@ from .application import Application def main(version): - app = Application(version) + app = Application() return app.run(sys.argv) diff --git a/src/playlistpanel.py b/src/playlistpanel.py index 34abfee..02526e0 100644 --- a/src/playlistpanel.py +++ b/src/playlistpanel.py @@ -110,9 +110,9 @@ class PlaylistPanel(Adw.Bin): # Get selected album item = self._playlist_grid_model.get_item(position) album = item.get_album() - album_id = album.get_id() + id = album.get_id() self._selected_albums = [album] - self.emit('albumart', album_id) + self.emit('albumart', id) # Show standalone album if widget.get_model() == self._playlist_grid_selection_single: @@ -175,7 +175,7 @@ class PlaylistPanel(Adw.Bin): # Load image and draw it try: self._standalone_pixbuf = Utils.load_pixbuf(data) - except Exception: + except Exception as e: self._logger.exception("Failed to set albumart") self._cover_pixbuf = self._get_default_image() else: @@ -239,6 +239,9 @@ class PlaylistPanel(Adw.Bin): self.emit('close-standalone') def _resize_standalone_image(self): + """Diese Methode skaliert das geladene Bild aus dem Pixelpuffer + auf die Größe des Fensters unter Beibehalt der Seitenverhältnisse + """ # Get size size_width = self.standalone_stack.get_width() size_height = self.standalone_stack.get_height() @@ -250,10 +253,10 @@ class PlaylistPanel(Adw.Bin): return # Skalierungswert für Breite und Höhe ermitteln - ratio_w = float(size_width) / float(pixbuf.get_width()) - ratio_h = float(size_height) / float(pixbuf.get_height()) + ratioW = float(size_width) / float(pixbuf.get_width()) + ratioH = float(size_height) / float(pixbuf.get_height()) # Kleineren beider Skalierungswerte nehmen, nicht Hochskalieren - ratio = min(ratio_w, ratio_h) + ratio = min(ratioW, ratioH) ratio = min(ratio, 1) # Neue Breite und Höhe berechnen width = int(math.floor(pixbuf.get_width() * ratio)) diff --git a/src/serverpanel.py b/src/serverpanel.py index f29c7c4..be7bd97 100644 --- a/src/serverpanel.py +++ b/src/serverpanel.py @@ -31,7 +31,7 @@ class ServerPanel(Adw.Bin): stats_dbplaytime = Gtk.Template.Child() stats_playtime = Gtk.Template.Child() stats_uptime = Gtk.Template.Child() - # Audio output devices widgets + # Audio ouptut devices widgets output_devices = Gtk.Template.Child() def __init__(self, **kwargs): @@ -103,8 +103,8 @@ class ServerPanel(Adw.Bin): button = Gtk.CheckButton.new_with_label(device.get_name()) if device.is_enabled(): button.set_active(True) - button.connect('toggled', self.on_output_device_toggled, - device) + handler = button.connect('toggled', + self.on_output_device_toggled, device) self.output_devices.insert(button, -1) self._output_buttons[device.get_id()] = button @@ -113,3 +113,4 @@ class ServerPanel(Adw.Bin): if id not in device_ids: self.output_devices.remove( self._output_buttons[id].get_parent()) + diff --git a/src/utils.py b/src/utils.py index ed8a04f..1a9e6e7 100644 --- a/src/utils.py +++ b/src/utils.py @@ -13,7 +13,6 @@ class Utils: CSS_SELECTION = 'selection' STOCK_ICON_DEFAULT = 'image-x-generic-symbolic' - @staticmethod def load_pixbuf(data): loader = GdkPixbuf.PixbufLoader() try: @@ -22,7 +21,6 @@ class Utils: loader.close() return loader.get_pixbuf() - @staticmethod def load_thumbnail(cache, client, album, size): cache_url = cache.create_filename(album) pixbuf = None @@ -40,7 +38,6 @@ class Utils: pixbuf.savev(cache_url, 'jpeg', [], []) return pixbuf - @staticmethod def create_artists_label(album): label = ', '.join(album.get_albumartists()) if album.get_artists(): @@ -48,14 +45,12 @@ class Utils: label, ", ".join(album.get_artists())) return label - @staticmethod def create_length_label(album): minutes = album.get_length() // 60 seconds = album.get_length() - minutes * 60 return locale.gettext("{}:{} minutes").format(minutes, seconds) - @staticmethod def create_track_title(track): title = track.get_title() if track.get_artists(): @@ -63,7 +58,6 @@ class Utils: title, ", ".join(track.get_artists())) return title - @staticmethod def generate_id(values): if type(values) is not list: values = [values] diff --git a/src/window.py b/src/window.py index 648853d..1c6d25c 100644 --- a/src/window.py +++ b/src/window.py @@ -23,10 +23,10 @@ from .zeroconf import ZeroconfProvider class WindowState(GObject.Object): - PROP_WIDTH = 'width' - PROP_HEIGHT = 'height' - PROP_MAXIMIZED = 'is_maximized' - PROP_FULLSCREENED = 'is_fullscreened' + WIDTH = 'width' + HEIGHT = 'height' + IS_MAXIMIZED = 'is_maximized' + IS_FULLSCREENED = 'is_fullscreened' width = GObject.Property(type=int, default=800) height = GObject.Property(type=int, default=600) is_maximized = GObject.Property(type=bool, default=False) @@ -206,18 +206,16 @@ class Window(Adw.ApplicationWindow): self._settings.connect('changed::' + Window.SETTING_SORT_TYPE, self.on_settings_sort_type_changed) self._settings.bind(Window.SETTING_WINDOW_WIDTH, self._state, - WindowState.PROP_WIDTH, - Gio.SettingsBindFlags.DEFAULT) + WindowState.WIDTH, Gio.SettingsBindFlags.DEFAULT) self._settings.bind(Window.SETTING_WINDOW_HEIGHT, self._state, - WindowState.PROP_HEIGHT, - Gio.SettingsBindFlags.DEFAULT) + WindowState.HEIGHT, Gio.SettingsBindFlags.DEFAULT) self._settings.bind(Window.SETTING_WINDOW_MAXIMIZED, self._state, - WindowState.PROP_MAXIMIZED, + WindowState.IS_MAXIMIZED, Gio.SettingsBindFlags.DEFAULT) # Actions self.set_default_size(self._state.width, self._state.height) - if self._state.get_property(WindowState.PROP_MAXIMIZED): + if self._state.get_property(WindowState.IS_MAXIMIZED): self.maximize() self.content_stack.set_visible_child(self._connection_panel) if self._settings.get_boolean(Window.SETTING_CONNECTED): @@ -276,7 +274,7 @@ class Window(Adw.ApplicationWindow): def on_menu_toggle_fullscreen(self, action, value): self.panel_stack.set_visible_child(self._cover_panel) - if not self._state.get_property(WindowState.PROP_FULLSCREENED): + if not self._state.get_property(WindowState.IS_FULLSCREENED): self.fullscreen() else: self.unfullscreen() @@ -292,14 +290,14 @@ class Window(Adw.ApplicationWindow): height = self.get_size(Gtk.Orientation.VERTICAL) if width > 0: self._cover_panel.set_width(width) - if not self._state.get_property(WindowState.PROP_MAXIMIZED): - self._state.set_property(WindowState.PROP_WIDTH, width) - self._state.set_property(WindowState.PROP_HEIGHT, height) + if not self._state.get_property(WindowState.IS_MAXIMIZED): + self._state.set_property(WindowState.WIDTH, width) + self._state.set_property(WindowState.HEIGHT, height) GObject.idle_add(self._playlist_panel.set_size, width, height) GObject.idle_add(self._library_panel.set_size, width, height) def on_maximized(self, widget, maximized): - self._state.set_property(WindowState.PROP_MAXIMIZED, maximized is True) + self._state.set_property(WindowState.IS_MAXIMIZED, maximized is True) def on_fullscreened(self, widget, fullscreened): self._fullscreen(self.is_fullscreen()) @@ -373,7 +371,7 @@ class Window(Adw.ApplicationWindow): self._mcg.enable_output_device(device, enabled) def on_cover_panel_toggle_fullscreen(self, widget): - if not self._state.get_property(WindowState.PROP_FULLSCREENED): + if not self._state.get_property(WindowState.IS_FULLSCREENED): self.fullscreen() else: self.unfullscreen() @@ -435,10 +433,7 @@ class Window(Adw.ApplicationWindow): bitrate, error): # Album GObject.idle_add(self._cover_panel.set_album, album) - if ( - not album - and self._state.get_property(WindowState.PROP_FULLSCREENED) - ): + if not album and self._state.get_property(WindowState.IS_FULLSCREENED): self._fullscreen(False) # State if state == 'play': @@ -539,11 +534,10 @@ class Window(Adw.ApplicationWindow): def _fullscreen(self, fullscreened_new): if fullscreened_new != self._state.get_property( - WindowState.PROP_FULLSCREENED - ): - self._state.set_property(WindowState.PROP_FULLSCREENED, + WindowState.IS_FULLSCREENED): + self._state.set_property(WindowState.IS_FULLSCREENED, fullscreened_new) - if self._state.get_property(WindowState.PROP_FULLSCREENED): + if self._state.get_property(WindowState.IS_FULLSCREENED): self.headerbar.hide() self._cover_panel.set_fullscreen(True) self.set_cursor(Gdk.Cursor.new_from_name("none", None)) diff --git a/src/zeroconf.py b/src/zeroconf.py index 6dc1f00..5fa3363 100644 --- a/src/zeroconf.py +++ b/src/zeroconf.py @@ -29,6 +29,7 @@ class ZeroconfProvider(client.Base): def on_new_service(self, browser, interface, protocol, name, type, domain, flags): + #if not (flags & Avahi.LookupResultFlags.GA_LOOKUP_RESULT_LOCAL): service_resolver = Avahi.ServiceResolver( interface=interface, protocol=protocol,