From ccd355d4c200969465d9d802c46a22f3a5850717 Mon Sep 17 00:00:00 2001 From: coderkun Date: Sun, 24 Dec 2017 14:36:43 +0100 Subject: [PATCH 1/6] Separate Connection panel and add Server panel (#36) --- data/de.coderkun.mcg.gschema.xml | 2 +- data/gtk.glade | 961 +++++++++++++++++-------------- mcg/widgets.py | 74 ++- 3 files changed, 569 insertions(+), 468 deletions(-) diff --git a/data/de.coderkun.mcg.gschema.xml b/data/de.coderkun.mcg.gschema.xml index 89e599a..57e9896 100644 --- a/data/de.coderkun.mcg.gschema.xml +++ b/data/de.coderkun.mcg.gschema.xml @@ -42,7 +42,7 @@ Window maximized state. - + 1 Last selected panel The index of the last selected panel. diff --git a/data/gtk.glade b/data/gtk.glade index 747c3b0..4e8fa14 100644 --- a/data/gtk.glade +++ b/data/gtk.glade @@ -1,5 +1,5 @@ - + @@ -366,11 +366,13 @@ True False - + True False + 100 + crossfade - + True False vertical @@ -396,7 +398,7 @@ True - + @@ -411,7 +413,6 @@ True False - 5 vertical @@ -469,6 +470,7 @@ True True + 6600 server-port-adjustment 6600 @@ -541,508 +543,555 @@ - connection - Connection + page1 + page1 - + True False - True - + True False - + True False + server-stack - cover-spinner + False + True + 0 - + True - True - False - False - + False - - True - False - - - True - False - - - - True - False - 0 - - - - - + - cover-scroll + True + True 1 - True - True - 0 + server + Server - + True False - slide-right + True - + True - True - never - never + False - + True False - none + + + cover-spinner + + + + + True + True + False + False + - + True False - vertical - + True False - 5 - 5 - 5 - True + - + True False - Album - True + 0 - - 0 - 0 - - - - True - False - Date - True - - - 0 - 1 - - - - - True - False - Artist - True - - - 0 - 2 - - - - - False - True - 10 - 0 - + + + + + cover-scroll + 1 + + + + + True + True + 0 + + + + + True + False + slide-right + + + True + True + never + never + + + True + False + none - + True - True - start + False vertical - False - - + + + True + False + 5 + 5 + 5 + True + + + True + False + Album + True + + + 0 + 0 + + + + + True + False + Date + True + + + 0 + 1 + + + + + True + False + Artist + True + + + 0 + 2 + + + + + + False + True + 10 + 0 + + + + + True + True + start + vertical + False + + + + + True + True + 1 + + - - True - True - 1 - + + False + True + 1 + - False - True + cover + Cover 1 + + + True + False + slide-left-right + + + True + False + vertical + + + True + True + + + True + True + 0 + horizontal + 0 + 0 + 1 + 0 + True + + + + + + + + + True + True + 0 + + + + + True + False + slide-up + + + True + False + + + + + False + True + 1 + + + + + page2 + page2 + + + + + True + False + vertical + + + True + False + + + True + False + + + standalone-spinne + + + + + True + True + False + False + + + True + False + + + True + False + gtk-missing-image + 6 + + + + + + + standalone-scroll + 1 + + + + + True + True + 0 + + + + + True + False + + + False + True + 1 + + + + + page1 + page1 + 1 + + + + + playlist + Playlist + 2 + + + + + True + False + slide-left-right + + + True + False + vertical + + + True + True + False + + + + True + True + edit-find-symbolic + False + False + search library + + + + + + False + True + 0 + + + + + True + False + none + + + True + False + 0.5 + + + + + False + True + 1 + + + + + True + True + + + True + True + 0 + horizontal + 0 + 0 + 1 + 0 + True + + + + + + + + + True + True + 2 + + + + + True + False + none + + + True + False + + + + + False + True + 3 + + + + + page0 + page0 + + + + + True + False + vertical + + + True + False + + + True + False + + + standalone-spinne + + + + + True + True + False + False + + + + True + False + + + True + False + gtk-missing-image + 6 + + + + + + + standalone-scroll + 1 + + + + + True + True + 0 + + + + + True + False + + + False + True + 1 + + + + + page1 + page1 + 1 + + + + + library + Library + 3 + + - cover - Cover + page0 + page0 1 - - - True - False - slide-left-right - - - True - False - vertical - - - True - True - - - True - True - 0 - horizontal - 0 - 0 - 1 - 0 - True - - - - - - - - - True - True - 0 - - - - - True - False - slide-up - - - True - False - - - - - False - True - 1 - - - - - page2 - page2 - - - - - True - False - vertical - - - True - False - - - True - False - - - standalone-spinne - - - - - True - True - False - False - - - True - False - - - True - False - gtk-missing-image - 6 - - - - - - - standalone-scroll - 1 - - - - - True - True - 0 - - - - - True - False - - - False - True - 1 - - - - - page1 - page1 - 1 - - - - - playlist - Playlist - 2 - - - - - True - False - slide-left-right - - - True - False - vertical - - - True - True - False - - - - True - True - edit-find-symbolic - False - False - search library - - - - - - False - True - 0 - - - - - True - False - none - - - True - False - 0.5 - - - - - False - True - 1 - - - - - True - True - - - True - True - 0 - horizontal - 0 - 0 - 1 - 0 - True - - - - - - - - - True - True - 2 - - - - - True - False - none - - - True - False - - - - - False - True - 3 - - - - - page0 - page0 - - - - - True - False - vertical - - - True - False - - - True - False - - - standalone-spinne - - - - - True - True - False - False - - - - True - False - - - True - False - gtk-missing-image - 6 - - - - - - - standalone-scroll - 1 - - - - - True - True - 0 - - - - - True - False - - - False - True - 1 - - - - - page1 - page1 - 1 - - - - - library - Library - 3 - - -1 @@ -1186,15 +1235,43 @@ 4 - - - - + + headerbar-connection True False - panelstack + 100 + crossfade + + + True + False + Connect to MPD + + + + + + page1 + page1 + + + + + True + False + panelstack + + + page0 + page0 + 1 + + + + 4 + diff --git a/mcg/widgets.py b/mcg/widgets.py index 021fe1d..4f5ea08 100644 --- a/mcg/widgets.py +++ b/mcg/widgets.py @@ -88,7 +88,7 @@ class Window(): SETTING_SORT_ORDER = 'sort-order' SETTING_SORT_TYPE = 'sort-type' STOCK_ICON_DEFAULT = 'image-x-generic-symbolic' - _PANEL_INDEX_CONNECTION = 0 + _PANEL_INDEX_SERVER = 0 _PANEL_INDEX_COVER = 1 _PANEL_INDEX_PLAYLIST = 2 _PANEL_INDEX_LIBRARY = 3 @@ -107,8 +107,10 @@ class Window(): self._maximized = self._settings.get_boolean(Window.SETTING_WINDOW_MAXIMIZED) self._fullscreened = False + # Login screen + self._connection_panel = ConnectionPanel(builder) # Panels - self._panels.append(ConnectionPanel(builder)) + self._panels.append(ServerPanel(builder)) self._panels.append(CoverPanel(builder)) self._panels.append(PlaylistPanel(builder)) self._panels.append(LibraryPanel(builder)) @@ -117,6 +119,7 @@ class Window(): # InfoBar self._infobar = InfoBar(builder) # Stack + self._content_stack = builder.get_object('contentstack') self._stack = builder.get_object('panelstack') # Header self._header_bar = HeaderBar(builder) @@ -125,11 +128,11 @@ class Window(): # Properties self._header_bar.set_sensitive(False, False) - self._panels[Window._PANEL_INDEX_CONNECTION].set_host(self._settings.get_string(Window.SETTING_HOST)) - self._panels[Window._PANEL_INDEX_CONNECTION].set_port(self._settings.get_int(Window.SETTING_PORT)) + self._connection_panel.set_host(self._settings.get_string(Window.SETTING_HOST)) + self._connection_panel.set_port(self._settings.get_int(Window.SETTING_PORT)) if use_keyring: - self._panels[Window._PANEL_INDEX_CONNECTION].set_password(keyring.get_password(ZeroconfProvider.KEYRING_SYSTEM, ZeroconfProvider.KEYRING_USERNAME)) - self._panels[Window._PANEL_INDEX_CONNECTION].set_image_dir(self._settings.get_string(Window.SETTING_IMAGE_DIR)) + self._connection_panel.set_password(keyring.get_password(ZeroconfProvider.KEYRING_SYSTEM, ZeroconfProvider.KEYRING_USERNAME)) + self._connection_panel.set_image_dir(self._settings.get_string(Window.SETTING_IMAGE_DIR)) self._panels[Window._PANEL_INDEX_COVER].set_tracklist_size(self._settings.get_enum(Window.SETTING_TRACKLIST_SIZE)) self._panels[Window._PANEL_INDEX_PLAYLIST].set_item_size(self._settings.get_int(Window.SETTING_ITEM_SIZE)) self._panels[Window._PANEL_INDEX_LIBRARY].set_item_size(self._settings.get_int(Window.SETTING_ITEM_SIZE)) @@ -141,7 +144,7 @@ class Window(): self._header_bar.connect('toolbar-connect', self.on_header_bar_connect) self._header_bar.connect('toolbar-playpause', self.on_header_bar_playpause) self._header_bar.connect('toolbar-set-volume', self.on_header_bar_set_volume) - self._panels[Window._PANEL_INDEX_CONNECTION].connect('connection-changed', self.on_connection_panel_connection_changed) + self._connection_panel.connect('connection-changed', self.on_connection_panel_connection_changed) self._panels[Window._PANEL_INDEX_COVER].connect('toggle-fullscreen', self.on_cover_panel_toggle_fullscreen) self._panels[Window._PANEL_INDEX_COVER].connect('tracklist-size-changed', self.on_cover_panel_tracklist_size_changed) self._panels[Window._PANEL_INDEX_COVER].connect('set-song', self.on_cover_panel_set_song) @@ -172,7 +175,7 @@ class Window(): } handlers.update(self._header_bar.get_signal_handlers()) handlers.update(self._infobar.get_signal_handlers()) - handlers.update(self._panels[Window._PANEL_INDEX_CONNECTION].get_signal_handlers()) + handlers.update(self._connection_panel.get_signal_handlers()) handlers.update(self._panels[Window._PANEL_INDEX_COVER].get_signal_handlers()) handlers.update(self._panels[Window._PANEL_INDEX_PLAYLIST].get_signal_handlers()) handlers.update(self._panels[Window._PANEL_INDEX_LIBRARY].get_signal_handlers()) @@ -183,7 +186,7 @@ class Window(): if self._maximized: self._appwindow.maximize() self._appwindow.show_all() - self._stack.set_visible_child(self._panels[Window._PANEL_INDEX_CONNECTION].get()) + self._content_stack.set_visible_child(self._connection_panel.get()) if self._settings.get_boolean(Window.SETTING_CONNECTED): self._connect() @@ -380,11 +383,11 @@ class Window(): def on_mcg_load_playlist(self, playlist): - self._panels[self._PANEL_INDEX_PLAYLIST].set_playlist(self._panels[self._PANEL_INDEX_CONNECTION].get_host(), playlist) + self._panels[self._PANEL_INDEX_PLAYLIST].set_playlist(self._connection_panel.get_host(), playlist) def on_mcg_load_albums(self, albums): - self._panels[self._PANEL_INDEX_LIBRARY].set_albums(self._panels[self._PANEL_INDEX_CONNECTION].get_host(), albums) + self._panels[self._PANEL_INDEX_LIBRARY].set_albums(self._connection_panel.get_host(), albums) def on_mcg_error(self, error): @@ -422,17 +425,16 @@ class Window(): # Private methods def _connect(self): - connection_panel = self._panels[Window._PANEL_INDEX_CONNECTION] - connection_panel.get().set_sensitive(False) + self._connection_panel.get().set_sensitive(False) self._header_bar.set_sensitive(False, True) if self._mcg.is_connected(): self._mcg.disconnect() self._settings.set_boolean(Window.SETTING_CONNECTED, False) else: - host = connection_panel.get_host() - port = connection_panel.get_port() - password = connection_panel.get_password() - image_dir = connection_panel.get_image_dir() + host = self._connection_panel.get_host() + port = self._connection_panel.get_port() + password = self._connection_panel.get_password() + image_dir = self._connection_panel.get_image_dir() self._mcg.connect(host, port, password, image_dir) self._settings.set_boolean(Window.SETTING_CONNECTED, True) @@ -440,6 +442,7 @@ class Window(): def _connect_connected(self): self._header_bar.connected() self._header_bar.set_sensitive(True, False) + self._content_stack.set_visible_child(self._stack) self._stack.set_visible_child(self._panels[self._settings.get_int(Window.SETTING_PANEL)].get()) @@ -449,8 +452,8 @@ class Window(): self._header_bar.disconnected() self._header_bar.set_sensitive(False, False) self._save_visible_panel() - self._stack.set_visible_child(self._panels[Window._PANEL_INDEX_CONNECTION].get()) - self._panels[Window._PANEL_INDEX_CONNECTION].get().set_sensitive(True) + self._content_stack.set_visible_child(self._connection_panel.get()) + self._connection_panel.get().set_sensitive(True) def _fullscreen(self, fullscreened_new): @@ -506,6 +509,8 @@ class HeaderBar(GObject.GObject): # Widgets self._header_bar = builder.get_object('headerbar') + self._title_stack = builder.get_object('headerbar-title-stack') + self._connection_label = builder.get_object('headerbar-connectionn-label') self._stack_switcher = StackSwitcher(builder) self._button_connect = builder.get_object('headerbar-connection') self._button_playpause = builder.get_object('headerbar-playpause') @@ -580,6 +585,7 @@ class HeaderBar(GObject.GObject): self._button_connect.handler_unblock_by_func( self.on_connection_active_notify ) + self._title_stack.set_visible_child(self._stack_switcher.get()) def disconnected(self): @@ -591,6 +597,7 @@ class HeaderBar(GObject.GObject): self._button_connect.handler_unblock_by_func( self.on_connection_active_notify ) + self._title_stack.set_visible_child(self._connection_label) def set_play(self): @@ -673,8 +680,7 @@ class ConnectionPanel(GObject.GObject): self._profile = None # Widgets - self._panel = builder.get_object('server-panel') - self._toolbar = builder.get_object('server-toolbar') + self._panel = builder.get_object('connection-panel') # Zeroconf self._zeroconf_list = builder.get_object('server-zeroconf-list') self._zeroconf_list.set_model(self._services) @@ -699,10 +705,6 @@ class ConnectionPanel(GObject.GObject): return self._panel - def get_toolbar(self): - return self._toolbar - - def get_signal_handlers(self): return { 'on_server-zeroconf-list-selection_changed': self.on_service_selected, @@ -790,6 +792,28 @@ class ConnectionPanel(GObject.GObject): +class ServerPanel(GObject.GObject): + + + def __init__(self, builder): + GObject.GObject.__init__(self) + + # Widgets + self._panel = builder.get_object('server-panel') + self._toolbar = builder.get_object('server-toolbar') + self._stack = builder.get_object('server-stack') + + + def get(self): + return self._panel + + + def get_toolbar(self): + return self._toolbar + + + + class CoverPanel(GObject.GObject): __gsignals__ = { 'toggle-fullscreen': (GObject.SIGNAL_RUN_FIRST, None, ()), From fe1b60ea170bdf620a5e4111987ce1a67da4514e Mon Sep 17 00:00:00 2001 From: coderkun Date: Sun, 24 Dec 2017 15:47:12 +0100 Subject: [PATCH 2/6] Add status information to new Server panel (close #37) --- data/gtk.glade | 137 +++++++++++++++++++++++++++++++++++++++++++++++++ mcg/client.py | 14 ++++- mcg/widgets.py | 37 +++++++++++-- 3 files changed, 184 insertions(+), 4 deletions(-) diff --git a/data/gtk.glade b/data/gtk.glade index 4e8fa14..c2ec509 100644 --- a/data/gtk.glade +++ b/data/gtk.glade @@ -571,6 +571,143 @@ True False + + + True + False + + + + + + True + False + vertical + + + + + + True + False + 2 + 5 + + + True + False + start + file: + + + 0 + 0 + + + + + True + False + start + audio: + + + 0 + 1 + + + + + True + False + start + bitrate: + + + 0 + 2 + + + + + True + False + start + error: + + + 0 + 3 + + + + + True + False + start + True + + + 1 + 2 + + + + + True + False + start + True + + + 1 + 1 + + + + + True + False + start + True + + + 1 + 0 + + + + + True + False + start + True + + + 1 + 3 + + + + + False + True + 1 + + + + + False + True + 1 + + + + + page0 + Status + + diff --git a/mcg/client.py b/mcg/client.py index 2ddd75a..39c8764 100644 --- a/mcg/client.py +++ b/mcg/client.py @@ -375,10 +375,14 @@ class Client(Base): if 'error' in status: error = status['error'] # Album + file = None album = None pos = 0 song = self._parse_dict(self._call("currentsong")) if song: + # File + if 'file' in song: + file = song['file'] # Track track = self._extract_playlist_track(song) if track: @@ -391,7 +395,15 @@ class Client(Base): album = palbum break pos = pos - len(palbum.get_tracks()) - self._callback(Client.SIGNAL_STATUS, state, album, pos, time, volume, error) + # Audio + audio = None + if 'audio' in status: + audio = status['audio'] + # Bitrate + bitrate = None + if 'bitrate' in status: + bitrate = status['bitrate'] + self._callback(Client.SIGNAL_STATUS, state, album, pos, time, volume, file, audio, bitrate, error) def _load_albums(self): diff --git a/mcg/widgets.py b/mcg/widgets.py index 4f5ea08..dbe53b1 100644 --- a/mcg/widgets.py +++ b/mcg/widgets.py @@ -361,7 +361,7 @@ class Window(): self._panel_action.set_enabled(False) - def on_mcg_status(self, state, album, pos, time, volume, error): + def on_mcg_status(self, state, album, pos, time, volume, file, audio, bitrate, error): # Album GObject.idle_add(self._panels[Window._PANEL_INDEX_COVER].set_album, album) # State @@ -375,6 +375,8 @@ class Window(): self._play_action.set_state(GLib.Variant.new_boolean(False)) # Volume GObject.idle_add(self._header_bar.set_volume, volume) + # Audio + self._panels[Window._PANEL_INDEX_SERVER].set_status(file, audio, bitrate, error) # Error if error is None: self._infobar.hide() @@ -470,8 +472,7 @@ class Window(): def _save_visible_panel(self): panels = [panel.get() for panel in self._panels] panel_index_selected = panels.index(self._stack.get_visible_child()) - if panel_index_selected > 0: - self._settings.set_int(Window.SETTING_PANEL, panel_index_selected) + self._settings.set_int(Window.SETTING_PANEL, panel_index_selected) def _set_menu_visible_panel(self): @@ -803,6 +804,12 @@ class ServerPanel(GObject.GObject): self._toolbar = builder.get_object('server-toolbar') self._stack = builder.get_object('server-stack') + # Status widgets + self._status_file = builder.get_object('server-status-file') + self._status_audio = builder.get_object('server-status-audio') + self._status_bitrate = builder.get_object('server-status-bitrate') + self._status_error = builder.get_object('server-status-error') + def get(self): return self._panel @@ -812,6 +819,30 @@ class ServerPanel(GObject.GObject): return self._toolbar + def set_status(self, file, audio, bitrate, error): + if not file: + file = "" + self._status_file.set_text(file) + # Audio information + if audio: + parts = audio.split(":") + if len(parts) == 3: + audio = "{} Hz, {} bit, {} channels".format(parts[0], parts[1], parts[2]) + else: + audio = "" + self._status_audio.set_text(audio) + # Bitrate + if bitrate: + bitrate = bitrate + " kb/s" + else: + bitrate = "" + self._status_bitrate.set_text(bitrate) + # Error + if not error: + error = "" + self._status_error.set_markup(error) + + class CoverPanel(GObject.GObject): From 30175ee86afe714c26b0c82bde89a524a241e117 Mon Sep 17 00:00:00 2001 From: coderkun Date: Sun, 24 Dec 2017 22:29:43 +0100 Subject: [PATCH 3/6] Add stats to new Server panel (close #38) --- data/gtk.glade | 196 ++++++++++++++++++++++++++++++++++++++++++++++++- mcg/client.py | 41 +++++++++++ mcg/widgets.py | 25 ++++++- 3 files changed, 260 insertions(+), 2 deletions(-) diff --git a/data/gtk.glade b/data/gtk.glade index c2ec509..cc6be64 100644 --- a/data/gtk.glade +++ b/data/gtk.glade @@ -709,7 +709,201 @@ - + + True + False + + + + + + True + False + vertical + + + + + + True + False + 2 + 5 + + + True + False + end + right + True + + + 0 + 0 + + + + + True + False + end + right + + + 0 + 1 + + + + + True + False + end + right + + + 0 + 2 + + + + + True + False + start + albums + + + 1 + 1 + + + + + True + False + start + songs + + + 1 + 2 + + + + + True + False + start + artists + + + 1 + 0 + + + + + True + False + end + right + + + 0 + 3 + + + + + True + False + start + seconds + + + 1 + 3 + + + + + True + False + end + right + + + 0 + 6 + + + + + True + False + end + right + + + 0 + 5 + + + + + True + False + + + 0 + 4 + 2 + + + + + True + False + start + seconds played + + + 1 + 5 + + + + + True + False + seconds running + + + 1 + 6 + + + + + False + True + 1 + + + + + False + True + 1 + + + + + page1 + Statistics + 1 + diff --git a/mcg/client.py b/mcg/client.py index 39c8764..22cf6b7 100644 --- a/mcg/client.py +++ b/mcg/client.py @@ -108,6 +108,8 @@ class Client(Base): SIGNAL_CONNECTION = 'connection' # Signal: status SIGNAL_STATUS = 'status' + # Signal: stats + SIGNAL_STATS = 'stats' # Signal: load albums SIGNAL_LOAD_ALBUMS = 'load-albums' # Signal: load playlist @@ -174,6 +176,12 @@ class Client(Base): self._add_action(self._get_status) + def get_stats(self): + """Load statistics.""" + self._logger.info("get stats") + self._add_action(self._get_stats) + + def load_albums(self): self._logger.info("load albums") self._add_action(self._load_albums) @@ -406,6 +414,39 @@ class Client(Base): self._callback(Client.SIGNAL_STATUS, state, album, pos, time, volume, file, audio, bitrate, error) + def _get_stats(self): + """Action: Perform the real statistics gathering.""" + self._logger.info("getting statistics") + stats = self._parse_dict(self._call("stats")) + self._logger.debug("stats: %r", stats) + + # Artists + artists = 0 + if 'artists' in stats: + artists = int(stats['artists']) + # Albums + albums = 0 + if 'albums' in stats: + albums = int(stats['albums']) + # Songs + songs = 0 + if 'songs' in stats: + songs = int(stats['songs']) + # Database playtime + dbplaytime = 0 + if 'db_playtime' in stats: + dbplaytime = stats['db_playtime'] + # Playtime + playtime = 0 + if 'playtime' in stats: + playtime = stats['playtime'] + # Uptime + uptime = 0 + if 'uptime' in stats: + uptime = stats['uptime'] + self._callback(Client.SIGNAL_STATS, artists, albums, songs, dbplaytime, playtime, uptime) + + def _load_albums(self): """Action: Perform the real update.""" self._albums = {} diff --git a/mcg/widgets.py b/mcg/widgets.py index dbe53b1..e1e12d2 100644 --- a/mcg/widgets.py +++ b/mcg/widgets.py @@ -160,6 +160,7 @@ class Window(): self._panels[Window._PANEL_INDEX_LIBRARY].connect('sort-type-changed', self.on_library_panel_sort_type_changed) self._mcg.connect_signal(client.Client.SIGNAL_CONNECTION, self.on_mcg_connect) self._mcg.connect_signal(client.Client.SIGNAL_STATUS, self.on_mcg_status) + self._mcg.connect_signal(client.Client.SIGNAL_STATS, self.on_mcg_stats) self._mcg.connect_signal(client.Client.SIGNAL_LOAD_PLAYLIST, self.on_mcg_load_playlist) self._mcg.connect_signal(client.Client.SIGNAL_LOAD_ALBUMS, self.on_mcg_load_albums) self._mcg.connect_signal(client.Client.SIGNAL_ERROR, self.on_mcg_error) @@ -349,6 +350,7 @@ class Window(): self._mcg.load_playlist() self._mcg.load_albums() self._mcg.get_status() + self._mcg.get_stats() self._connect_action.set_state(GLib.Variant.new_boolean(True)) self._play_action.set_enabled(True) self._clear_playlist_action.set_enabled(True) @@ -375,7 +377,7 @@ class Window(): self._play_action.set_state(GLib.Variant.new_boolean(False)) # Volume GObject.idle_add(self._header_bar.set_volume, volume) - # Audio + # Status self._panels[Window._PANEL_INDEX_SERVER].set_status(file, audio, bitrate, error) # Error if error is None: @@ -384,6 +386,10 @@ class Window(): self._show_error(error) + def on_mcg_stats(self, artists, albums, songs, dbplaytime, playtime, uptime): + self._panels[Window._PANEL_INDEX_SERVER].set_stats(artists, albums, songs, dbplaytime, playtime, uptime) + + def on_mcg_load_playlist(self, playlist): self._panels[self._PANEL_INDEX_PLAYLIST].set_playlist(self._connection_panel.get_host(), playlist) @@ -810,6 +816,14 @@ class ServerPanel(GObject.GObject): self._status_bitrate = builder.get_object('server-status-bitrate') self._status_error = builder.get_object('server-status-error') + # Stats widgets + self._stats_artists = builder.get_object('server-stats-artists') + self._stats_albums = builder.get_object('server-stats-albums') + self._stats_songs = builder.get_object('server-stats-songs') + self._stats_dbplaytime = builder.get_object('server-stats-dbplaytime') + self._stats_playtime = builder.get_object('server-stats-playtime') + self._stats_uptime = builder.get_object('server-stats-uptime') + def get(self): return self._panel @@ -843,6 +857,15 @@ class ServerPanel(GObject.GObject): self._status_error.set_markup(error) + def set_stats(self, artists, albums, songs, dbplaytime, playtime, uptime): + self._stats_artists.set_text(str(artists)) + self._stats_albums.set_text(str(albums)) + self._stats_songs.set_text(str(songs)) + self._stats_dbplaytime.set_text(str(dbplaytime)) + self._stats_playtime.set_text(str(playtime)) + self._stats_uptime.set_text(str(uptime)) + + class CoverPanel(GObject.GObject): From 7a28e9f4bfd90ef07f9d65e710a721cdd09751e2 Mon Sep 17 00:00:00 2001 From: coderkun Date: Mon, 25 Dec 2017 13:16:56 +0100 Subject: [PATCH 4/6] Add hadling for audio output devices (close #35) --- data/gtk.glade | 44 +++++++++++++++++++++++++++++++++++ mcg/client.py | 63 ++++++++++++++++++++++++++++++++++++++++++++++++++ mcg/widgets.py | 48 ++++++++++++++++++++++++++++++++++++++ 3 files changed, 155 insertions(+) diff --git a/data/gtk.glade b/data/gtk.glade index cc6be64..8cbb041 100644 --- a/data/gtk.glade +++ b/data/gtk.glade @@ -905,6 +905,50 @@ 1 + + + True + False + + + + + + True + False + vertical + + + + + + True + False + none + + + + False + True + 1 + + + + + False + True + 1 + + + + + page2 + Audio Devices + 2 + + True diff --git a/mcg/client.py b/mcg/client.py index 22cf6b7..ca9102d 100644 --- a/mcg/client.py +++ b/mcg/client.py @@ -114,6 +114,8 @@ class Client(Base): SIGNAL_LOAD_ALBUMS = 'load-albums' # Signal: load playlist SIGNAL_LOAD_PLAYLIST = 'load-playlist' + # Signal: load audio output devices + SIGNAL_LOAD_OUTPUT_DEVICES = 'load-output-devices' # Signal: error SIGNAL_ERROR = 'error' @@ -182,6 +184,19 @@ class Client(Base): self._add_action(self._get_stats) + def get_output_devices(self): + """Determine the list of audio output devices.""" + self._logger.info("get output devices") + self._add_action(self._get_output_devices) + + + def enable_output_device(self, device, enabled): + """Enable/disable an audio output device.""" + self._logger.info("enable output device") + self._add_action(self._enable_output_device, device, enabled) + + + def load_albums(self): self._logger.info("load albums") self._add_action(self._load_albums) @@ -351,6 +366,9 @@ class Client(Base): self.load_albums() self.load_playlist() self.get_status() + if subsystems['changed'] == 'output': + self.get_output_devices() + self.get_status() def _noidle(self): @@ -447,6 +465,24 @@ class Client(Base): self._callback(Client.SIGNAL_STATS, artists, albums, songs, dbplaytime, playtime, uptime) + def _get_output_devices(self): + """Action: Perform the real loading of output devices.""" + devices = [] + for output in self._parse_list(self._call('outputs'), ['outputid']): + device = OutputDevice(output['outputid'], output['outputname']) + device.set_enabled(int(output['outputenabled']) == 1) + devices.append(device) + self._callback(Client.SIGNAL_LOAD_OUTPUT_DEVICES, devices) + + + def _enable_output_device(self, device, enabled): + """Action: Perform the real enabling/disabling of an output device.""" + if enabled: + self._call('enableoutput ', device.get_id()) + else: + self._call('disableoutput ', device.get_id()) + + def _load_albums(self): """Action: Perform the real update.""" self._albums = {} @@ -737,6 +773,33 @@ class Client(Base): +class OutputDevice: + + + def __init__(self, id, name): + self._id = id + self._name = name + self._enabled = None + + + def get_id(self): + return self._id + + + def get_name(self): + return self._name + + + def set_enabled(self, enabled): + self._enabled = enabled + + + def is_enabled(self): + return self._enabled + + + + class MCGAlbum: DEFAULT_ALBUM = 'Various' _FILE_NAMES = ['cover', 'folder'] diff --git a/mcg/widgets.py b/mcg/widgets.py index e1e12d2..54bc881 100644 --- a/mcg/widgets.py +++ b/mcg/widgets.py @@ -145,6 +145,7 @@ class Window(): self._header_bar.connect('toolbar-playpause', self.on_header_bar_playpause) self._header_bar.connect('toolbar-set-volume', self.on_header_bar_set_volume) self._connection_panel.connect('connection-changed', self.on_connection_panel_connection_changed) + self._panels[Window._PANEL_INDEX_SERVER].connect('change-output-device', self.on_server_panel_output_device_changed) self._panels[Window._PANEL_INDEX_COVER].connect('toggle-fullscreen', self.on_cover_panel_toggle_fullscreen) self._panels[Window._PANEL_INDEX_COVER].connect('tracklist-size-changed', self.on_cover_panel_tracklist_size_changed) self._panels[Window._PANEL_INDEX_COVER].connect('set-song', self.on_cover_panel_set_song) @@ -161,6 +162,7 @@ class Window(): self._mcg.connect_signal(client.Client.SIGNAL_CONNECTION, self.on_mcg_connect) self._mcg.connect_signal(client.Client.SIGNAL_STATUS, self.on_mcg_status) self._mcg.connect_signal(client.Client.SIGNAL_STATS, self.on_mcg_stats) + self._mcg.connect_signal(client.Client.SIGNAL_LOAD_OUTPUT_DEVICES, self.on_mcg_load_output_devices) self._mcg.connect_signal(client.Client.SIGNAL_LOAD_PLAYLIST, self.on_mcg_load_playlist) self._mcg.connect_signal(client.Client.SIGNAL_LOAD_ALBUMS, self.on_mcg_load_albums) self._mcg.connect_signal(client.Client.SIGNAL_ERROR, self.on_mcg_error) @@ -302,6 +304,10 @@ class Window(): self._mcg.play_album_from_playlist(album) + def on_server_panel_output_device_changed(self, widget, device, enabled): + self._mcg.enable_output_device(device, enabled) + + def on_cover_panel_toggle_fullscreen(self, widget): if not self._fullscreened: self._appwindow.fullscreen() @@ -351,6 +357,7 @@ class Window(): self._mcg.load_albums() self._mcg.get_status() self._mcg.get_stats() + self._mcg.get_output_devices() self._connect_action.set_state(GLib.Variant.new_boolean(True)) self._play_action.set_enabled(True) self._clear_playlist_action.set_enabled(True) @@ -390,6 +397,10 @@ class Window(): self._panels[Window._PANEL_INDEX_SERVER].set_stats(artists, albums, songs, dbplaytime, playtime, uptime) + def on_mcg_load_output_devices(self, devices): + self._panels[Window._PANEL_INDEX_SERVER].set_output_devices(devices) + + def on_mcg_load_playlist(self, playlist): self._panels[self._PANEL_INDEX_PLAYLIST].set_playlist(self._connection_panel.get_host(), playlist) @@ -800,10 +811,14 @@ class ConnectionPanel(GObject.GObject): class ServerPanel(GObject.GObject): + __gsignals__ = { + 'change-output-device': (GObject.SIGNAL_RUN_FIRST, None, (GObject.TYPE_PYOBJECT,bool,)), + } def __init__(self, builder): GObject.GObject.__init__(self) + self._output_buttons = {} # Widgets self._panel = builder.get_object('server-panel') @@ -824,6 +839,9 @@ class ServerPanel(GObject.GObject): self._stats_playtime = builder.get_object('server-stats-playtime') self._stats_uptime = builder.get_object('server-stats-uptime') + # Audio ouptut devices widgets + self._output_devices = builder.get_object('server-output-devices') + def get(self): return self._panel @@ -833,6 +851,10 @@ class ServerPanel(GObject.GObject): return self._toolbar + def on_output_device_toggled(self, widget, device): + self.emit('change-output-device', device, widget.get_active()) + + def set_status(self, file, audio, bitrate, error): if not file: file = "" @@ -866,6 +888,32 @@ class ServerPanel(GObject.GObject): self._stats_uptime.set_text(str(uptime)) + def set_output_devices(self, devices): + device_ids = [] + + # Add devices + for device in devices: + device_ids.append(device.get_id()) + if device.get_id() in self._output_buttons.keys(): + self._output_buttons[device.get_id()].freeze_notify() + self._output_buttons[device.get_id()].set_active(device.is_enabled()) + self._output_buttons[device.get_id()].thaw_notify() + else: + button = Gtk.CheckButton(device.get_name()) + if device.is_enabled(): + button.set_active(True) + handler = button.connect('toggled', self.on_output_device_toggled, device) + self._output_devices.insert(button, -1) + self._output_buttons[device.get_id()] = button + self._output_devices.show_all() + + # Remove devices + for id in self._output_buttons.keys(): + if id not in device_ids: + self._output_devices.remove(self._output_buttons[id].get_parent()) + + + class CoverPanel(GObject.GObject): From abff4b9f2f86f71d81423130846535b39dd1604f Mon Sep 17 00:00:00 2001 From: coderkun Date: Mon, 25 Dec 2017 17:01:19 +0100 Subject: [PATCH 5/6] Improve visual appearance of Server panel (see #36) --- data/gtk.glade | 554 ++++++++++++++++++++++++++++--------------------- mcg/widgets.py | 24 ++- 2 files changed, 335 insertions(+), 243 deletions(-) diff --git a/data/gtk.glade b/data/gtk.glade index 8cbb041..a440b80 100644 --- a/data/gtk.glade +++ b/data/gtk.glade @@ -587,105 +587,139 @@ - + True False - 2 - 5 + vertical + 10 - + True False - start - file: + dialog-information-symbolic + 6 - 0 - 0 + False + True + 0 - + True False - start - audio: + 2 + 5 + + + True + False + start + file: + + + 0 + 0 + + + + + True + False + start + audio: + + + 0 + 1 + + + + + True + False + start + bitrate: + + + 0 + 2 + + + + + True + False + start + error: + + + 0 + 3 + + + + + True + False + start + <i>none</i> + True + True + + + 1 + 2 + + + + + True + False + start + <i>none</i> + True + True + + + 1 + 1 + + + + + True + False + start + <i>none</i> + True + True + + + 1 + 0 + + + + + True + False + start + <i>none</i> + True + True + + + 1 + 3 + + - 0 - 1 - - - - - True - False - start - bitrate: - - - 0 - 2 - - - - - True - False - start - error: - - - 0 - 3 - - - - - True - False - start - True - - - 1 - 2 - - - - - True - False - start - True - - - 1 - 1 - - - - - True - False - start - True - - - 1 - 0 - - - - - True - False - start - True - - - 1 - 3 + False + True + 1 @@ -724,164 +758,190 @@ - + True False - 2 - 5 + vertical + 10 - + True False - end - right - True + starred-symbolic + 6 - 0 - 0 + False + True + 0 - + True False - end - right + 2 + 5 + + + True + False + end + right + True + + + 0 + 0 + + + + + True + False + end + right + + + 0 + 1 + + + + + True + False + end + right + + + 0 + 2 + + + + + True + False + start + albums + + + 1 + 1 + + + + + True + False + start + songs + + + 1 + 2 + + + + + True + False + start + artists + + + 1 + 0 + + + + + True + False + end + right + + + 0 + 3 + + + + + True + False + start + seconds + + + 1 + 3 + + + + + True + False + end + right + + + 0 + 6 + + + + + True + False + end + right + + + 0 + 5 + + + + + True + False + + + 0 + 4 + 2 + + + + + True + False + start + seconds played + + + 1 + 5 + + + + + True + False + seconds running + + + 1 + 6 + + - 0 - 1 - - - - - True - False - end - right - - - 0 - 2 - - - - - True - False - start - albums - - - 1 - 1 - - - - - True - False - start - songs - - - 1 - 2 - - - - - True - False - start - artists - - - 1 - 0 - - - - - True - False - end - right - - - 0 - 3 - - - - - True - False - start - seconds - - - 1 - 3 - - - - - True - False - end - right - - - 0 - 6 - - - - - True - False - end - right - - - 0 - 5 - - - - - True - False - - - 0 - 4 - 2 - - - - - True - False - start - seconds played - - - 1 - 5 - - - - - True - False - seconds running - - - 1 - 6 + False + True + 1 @@ -921,13 +981,39 @@ - + True False - none - + vertical + 10 + + + True + False + audio-speakers-symbolic + 6 + + + False + True + 0 + + + + + True + False + none + + + + False + True + 1 + + False diff --git a/mcg/widgets.py b/mcg/widgets.py index 54bc881..7e02737 100644 --- a/mcg/widgets.py +++ b/mcg/widgets.py @@ -818,6 +818,7 @@ class ServerPanel(GObject.GObject): def __init__(self, builder): GObject.GObject.__init__(self) + self._none_label = "" self._output_buttons = {} # Widgets @@ -830,6 +831,7 @@ class ServerPanel(GObject.GObject): self._status_audio = builder.get_object('server-status-audio') self._status_bitrate = builder.get_object('server-status-bitrate') self._status_error = builder.get_object('server-status-error') + self._none_label = self._status_file.get_label() # Stats widgets self._stats_artists = builder.get_object('server-stats-artists') @@ -856,26 +858,30 @@ class ServerPanel(GObject.GObject): def set_status(self, file, audio, bitrate, error): - if not file: - file = "" - self._status_file.set_text(file) + if file: + file = GObject.markup_escape_text(file) + else: + file = self._none_label + self._status_file.set_markup(file) # Audio information if audio: parts = audio.split(":") if len(parts) == 3: audio = "{} Hz, {} bit, {} channels".format(parts[0], parts[1], parts[2]) else: - audio = "" - self._status_audio.set_text(audio) + audio = self._none_label + self._status_audio.set_markup(audio) # Bitrate if bitrate: bitrate = bitrate + " kb/s" else: - bitrate = "" - self._status_bitrate.set_text(bitrate) + bitrate = self._none_label + self._status_bitrate.set_markup(bitrate) # Error - if not error: - error = "" + if error: + error = GObject.markup_escape_text(error) + else: + error = self._none_label self._status_error.set_markup(error) From 27cb6b7effbac0fa0e2db595e4538bf5c91d4494 Mon Sep 17 00:00:00 2001 From: coderkun Date: Mon, 25 Dec 2017 17:10:47 +0100 Subject: [PATCH 6/6] Update translations for Server panel (see #36) --- data/gtk.glade | 30 ++++----- locale/de/LC_MESSAGES/mcg.mo | Bin 3574 -> 4240 bytes locale/de/LC_MESSAGES/mcg.po | 119 ++++++++++++++++++++++++++--------- locale/en/LC_MESSAGES/mcg.mo | Bin 3357 -> 4004 bytes locale/en/LC_MESSAGES/mcg.po | 119 ++++++++++++++++++++++++++--------- 5 files changed, 195 insertions(+), 73 deletions(-) diff --git a/data/gtk.glade b/data/gtk.glade index a440b80..0d6e906 100644 --- a/data/gtk.glade +++ b/data/gtk.glade @@ -470,7 +470,7 @@ True True - 6600 + 6600 server-port-adjustment 6600 @@ -544,7 +544,7 @@ page1 - page1 + page1 @@ -616,7 +616,7 @@ True False start - file: + File: 0 @@ -628,7 +628,7 @@ True False start - audio: + Audio: 0 @@ -640,7 +640,7 @@ True False start - bitrate: + Bitrate: 0 @@ -652,7 +652,7 @@ True False start - error: + Error: 0 @@ -824,7 +824,7 @@ True False start - albums + Albums 1 @@ -836,7 +836,7 @@ True False start - songs + Songs 1 @@ -848,7 +848,7 @@ True False start - artists + Artists 1 @@ -872,7 +872,7 @@ True False start - seconds + Seconds 1 @@ -919,7 +919,7 @@ True False start - seconds played + Seconds played 1 @@ -930,7 +930,7 @@ True False - seconds running + Seconds running 1 @@ -1549,7 +1549,7 @@ page0 - page0 + page0 1 @@ -1714,7 +1714,7 @@ page1 - page1 + page1 @@ -1725,7 +1725,7 @@ page0 - page0 + page0 1 diff --git a/locale/de/LC_MESSAGES/mcg.mo b/locale/de/LC_MESSAGES/mcg.mo index f9e520ac95630954dadfe0c497d888dd915f0808..c32a51590fe3f7ee7ddda220c887b2393c70341b 100644 GIT binary patch delta 1975 zcmew+JwdVlo)F7a1_lNOCk6%v83qOh9VP~bNCpN58y1i#1H%GV1_o{h28M;K3=Dz{ z3=C^o85r0Y7#Q|L>0_)64D1XH3};yx7H~+5C&C{#t8|LQcea29tH-6W==>{OyFc-&|_j?m;;qR&CS3d!N9<9 zlN;jTPuviTen4p^9*BM(9*Dywc_1OEzyooBCJ#eBgA@Y;gC!3{V+aoegBk+^LmUqz z&RTgOKA*+|v0x$8z~wv)4CM?A3|n|0A)v#{z@Wsyz~Bv~^LQa?U?MNX;+eb<^B3?! z%vr??@z4g|dPorO;bmYDW?*1A$P2OXDla6pKj4ML*(az0oO}?2g!v$eNR|)c69Ybo z!47;7i{1FZshh!%j{)q#6h4U0LBS2mMIC$)56%J!fP!!}AH=0cpc+o|F)%1IFfcsh zV_+~~U|`_lhge|E4{@L)Kg0(<{1AN+{0t1Lpj^Ta36WNQNSasz#=^ODI1;0Fr2upc)DVAR$l#rP~A;7#Kl`7*bp?*fKCMs4zg{ z9h5ym(QCrMz+et4TcBz{A??V(z@Pxi|DZy{o`HeE6e_6+r8O8J7K5^+F#`jGI#e7~ zNP(D!AOe(Y7$81_a>02V#0C{gAR3hSL1_xa29+-$8dTVUXd{MtNU(x}4iwBFK}!Zm zkb<%nh;PjR$(EuFkRaD*fCQ}>10=*iSr?S}m_Ujd7#Osmv^E0+gB6qwD*0@nY&`}@ znz3MDVBi4de>(<9kb>kv1q6teXJBAp1~C{I7#tWNB_D%Lrd?isUaF0LrX7Q0N>*uc zi9$(6szOKutV^K+FaS4w;8ZZJP>_>Y znVJIU7M14ZW#*+b1gGYtCYLDWmgbaX7UZNVBtqO0oLW?tS~S^)Elesey_g|5zo>*E zxFiwez|7=gFtfCH^Axr~Ml(YrT_aNkLvt%b18oCC0|TxAf8C(evdrSl{5)M3kYg2$ z3=GY6QPoYB=Gf0@I{7xo-&j!KWF}{n6oZ4uB{NmQC$Y4oxa9DXqU=~LLj=_1U!1XgQKg_zQYcF;O3KVjnH<9P zkIyYNBPX@UiUH)nOsmO(+z+&aQ?pC+Qd096U<`%y)Z&87)SME8NKRsDT54X(WCI>4 kHfR`m@)Rq=!YDJfs1y{a(2&Xo8CH^5Qd+$E2#*mX0NODVm;e9( delta 1301 zcmbQB_)WV0o)F7a1_lNOBL)Tr83qQ1HH-`l&I}9;Hq0PV1_lon1_nU}1_nh=2@cWnkcBU|_fcRex_{pm06N1)re; zKcNc$K@AdSV_**VgBW1T#=xM+z`zj1#=s!Wz`#(#2C;Yo8^nQA*%%n)Kt5q( zV31^BV7LTT_l6DZ69x`;h{ILcAr8@IXQ&4Ul_@&|13v=;g9|$(=t7|UWGKIw9paNF zb_NC>1_p)+?2sUv%g(@{$Hc&}lAVD;f`NhI1}DVekDL(meseM~NHH)laC1S#)wmcK z)EF2T47eas5YAN(aZwT%#NZ4r28MD528L2Dh)>>fF)%1GFfj0NLuh?&h(STz5PdP+ z5QijjLqZ~tn}I=?fq|iz8)88_HzaLL;)aCe5~%*&Q2J;+Hzdx^b3@ElJo1_c z5+z)`5WWg8L|?r#FT^M5ybz7KypXuA;Dxxnmlxvl`B45gUPu(3fU3XF3ki`&Q2Gro z0|O%iB(y+j1r)82e8Rw>3uSp@^P)Y@5HF*X|qSAuO88R?1 zs53x(p~CLpa4>*!Pd!K* z1Zy)u@*OB|g0c-L4})YBKm-E=0~3@6rF?D%NPL6h8kC?wQlK&blv_Y-6zrIiRa#u4 zP?C|VP?n!lnw!etSX7c(T*Ba-lREhutIK3hwv&_P*|&-0q$ZarS)7@lr|Xhfl4_-3 zWMF8ni>huiAJ=|H\n" "Language-Team: \n" "Language: de\n" "MIME-Version: 1.0\n" "Content-Type: text/plain; charset=UTF-8\n" "Content-Transfer-Encoding: 8bit\n" -"X-Generator: Poedit 2.0.3\n" +"X-Generator: Poedit 2.0.5\n" "X-Poedit-Basepath: ../../..\n" "Plural-Forms: nplurals=2; plural=(n != 1);\n" "X-Poedit-SourceCharset: UTF-8\n" @@ -58,87 +58,147 @@ msgstr "nach Titel" msgid "sort by year" msgstr "nach Jahr" -#: data/gtk.glade:436 +#: data/gtk.glade:437 msgid "Enter hostname or IP address" msgstr "Hostnamen oder IP-Adresse eingeben" -#: data/gtk.glade:448 +#: data/gtk.glade:449 msgid "Enter URL or local path" msgstr "URL oder lokalen Pfad eingeben" -#: data/gtk.glade:460 +#: data/gtk.glade:461 msgid "Enter password or leave blank" msgstr "Passwort eingeben oder leer lassen" -#: data/gtk.glade:485 +#: data/gtk.glade:487 msgid "Host:" msgstr "Host:" -#: data/gtk.glade:497 +#: data/gtk.glade:499 msgid "Port:" msgstr "Port:" -#: data/gtk.glade:509 +#: data/gtk.glade:511 msgid "Password:" msgstr "Passwort:" -#: data/gtk.glade:521 +#: data/gtk.glade:523 msgid "Image Directory:" msgstr "Bildordner:" -#: data/gtk.glade:545 data/gtk.menu.ui:24 -msgid "Connection" -msgstr "Verbindung" +#: data/gtk.glade:619 +msgid "File:" +msgstr "Datei:" -#: data/gtk.glade:714 data/gtk.menu.ui:30 +#: data/gtk.glade:631 +msgid "Audio:" +msgstr "Audio:" + +#: data/gtk.glade:643 +msgid "Bitrate:" +msgstr "Bitrate:" + +#: data/gtk.glade:655 +msgid "Error:" +msgstr "Fehler:" + +#: data/gtk.glade:667 data/gtk.glade:681 data/gtk.glade:695 data/gtk.glade:709 +msgid "none" +msgstr "nichts" + +#: data/gtk.glade:742 +msgid "Status" +msgstr "Status" + +#: data/gtk.glade:827 +msgid "Albums" +msgstr "Alben" + +#: data/gtk.glade:839 +msgid "Songs" +msgstr "Songs" + +#: data/gtk.glade:851 +msgid "Artists" +msgstr "Künstler" + +#: data/gtk.glade:875 +msgid "Seconds" +msgstr "Sekunden" + +#: data/gtk.glade:922 +msgid "Seconds played" +msgstr "Sekunden gespielt" + +#: data/gtk.glade:933 +msgid "Seconds running" +msgstr "Sekunden laufend" + +#: data/gtk.glade:964 +msgid "Statistics" +msgstr "Statistiken" + +#: data/gtk.glade:1034 +msgid "Audio Devices" +msgstr "Audiogeräte" + +#: data/gtk.glade:1048 +msgid "Server" +msgstr "Server" + +#: data/gtk.glade:1217 data/gtk.menu.ui:30 msgid "Cover" msgstr "Cover" -#: data/gtk.glade:856 data/gtk.menu.ui:36 +#: data/gtk.glade:1359 data/gtk.menu.ui:36 msgid "Playlist" msgstr "Wiedergabeliste" -#: data/gtk.glade:883 +#: data/gtk.glade:1386 msgid "search library" msgstr "Bibliothek durchsuchen" -#: data/gtk.glade:1042 data/gtk.menu.ui:42 +#: data/gtk.glade:1545 data/gtk.menu.ui:42 msgid "Library" msgstr "Bibliothek" -#: data/gtk.glade:1114 data/gtk.shortcuts.ui:74 +#: data/gtk.glade:1624 data/gtk.shortcuts.ui:74 msgid "Connect or disconnect" msgstr "Die Verbindung herstellen oder trennen" -#: data/gtk.glade:1136 data/gtk.shortcuts.ui:81 +#: data/gtk.glade:1646 data/gtk.shortcuts.ui:81 msgid "Switch between play and pause" msgstr "Zwischen Abspielen und Pause wechseln" -#: data/gtk.glade:1156 +#: data/gtk.glade:1666 msgid "Adjust the volume" msgstr "Die Lautstärke anpassen" -#: data/gtk.glade:1214 data/gtk.shortcuts.ui:101 +#: data/gtk.glade:1710 +msgid "Connect to MPD" +msgstr "Zu MPD verbinden" + +#: data/gtk.glade:1752 data/gtk.shortcuts.ui:101 msgid "Show the cover in fullscreen mode" msgstr "Das Cover im Vollbildmodus anzeigen" -#: data/gtk.glade:1237 data/gtk.glade:1386 +#: data/gtk.glade:1775 data/gtk.glade:1924 msgid "Settings and actions" msgstr "Einstellungen und Aktionen" -#: data/gtk.glade:1285 data/gtk.glade:1364 +#: data/gtk.glade:1823 data/gtk.glade:1902 msgid "Select multiple albums" msgstr "Mehrere Alben auswählen" -#: data/gtk.glade:1307 data/gtk.shortcuts.ui:88 +#: data/gtk.glade:1845 data/gtk.shortcuts.ui:88 msgid "Clear the playlist" msgstr "Die Wiedergabeliste leeren" -#: data/gtk.glade:1341 data/gtk.shortcuts.ui:114 +#: data/gtk.glade:1879 data/gtk.shortcuts.ui:114 msgid "Search the library" msgstr "Die Bibliothek durchsuchen" -#: data/gtk.glade:1431 +#: data/gtk.glade:1969 msgid "" "CoverGrid is a client for the Music Player Daemon, focusing on albums " "instead of single tracks." @@ -158,6 +218,10 @@ msgstr "Abspielen" msgid "Clear Playlist" msgstr "Playlist leeren" +#: data/gtk.menu.ui:24 +msgid "Connection" +msgstr "Verbindung" + #: data/gtk.menu.ui:50 msgid "Keyboard Shortcuts" msgstr "Tastenkombinationen" @@ -229,6 +293,3 @@ msgstr "{} mit {}" #~ msgid "Show the keyboard shortcuts (this dialog)" #~ msgstr "Die Tastenkombinationen anzeigen (dieser Dialog)" - -#~ msgid "Server" -#~ msgstr "Server" diff --git a/locale/en/LC_MESSAGES/mcg.mo b/locale/en/LC_MESSAGES/mcg.mo index d1b8c352653925fad219a023d61f4b9aa0796b18..d14c7d7111d3e1f303983ae5a8d7bb0bc95920fc 100644 GIT binary patch literal 4004 zcmca7#4?qEfq}t^fq_AWfq_AXiGd-Kfq}t>1tiMAuz;0;ft!JWVIeC6gCGL~!&+7b z1~vu;hW$|b7%Kw}vN14-GB7a6vO(mH*%%nOK<;2;U|?lnVDM#w*c;5oz!1;Cz!1;Iz#tB?mkr|1 z>ud}RvJ4CiU)Uh-5n_kvlVpdOFAwFbvokOVFfcIavNJG%yky4?afdThT^KvW-Er&; z3?d8+3_0u!44e!M42@9r-RuzaC$K~OGaYK~0;v2lsJ_)ua}Pkxz03~r*KKwN27XXD zurn}-F)%Rvf|@7D0kKblgMmR2?k(higi9F*#2t+s5Px@Y zFfhn5Ffc6RU|^7BU|={3)qkG@53x5K>2IAA?aZ!H^g11q4XtgNci96hM4mZD*m1u5`N#f zA@2Ck4T%Rn9*BBH9!Pr7{QH;(5-y-b z2uh!Fybyh=yb$xXp?qUrNP4j3g@mscFT@@GP<2VX5O-(sLgJ@_7ZQHGQ1#P!A^x4i z3-QllsJUyP@|&RgwnNQ512y+Plzz?&3IF%Jko52$YMvM$#6DR*NO~~hV_?u^U|wgM^O|Kg1k;eu#fe`Jv&=4{?tl zlphD>=R(!h@LWacY*SvF#`jGI!F*&Hi4LiAOe(M z7#J9op==NZ%G)3sR2G3~P@Y!24aHBI1p{b00|3K1_lNLkN^V%gCzqbJVAL1 zBxKD1$&a8i3RM2-GeE-Ci~*AFL3vgQRGxtpGcYh{L1}FU1_moA8&uxeK-qc>kZ`tO zfP|+V10)_m(x7qyM9VWUFffA{3=9ko43PBAV3TQ=m!Fqvqn~NV;FywCT3n(~l98%V zmY-9ao66vrlT?~p%-~p5l382=rHUCGOH(rQ6(;8GcPS)Atf_0CqJDb0O|}Y z22hNEiPR!61&*D7{Gt*ohQQLy5-)+jlbM`Y0t)ir)Wo9X46twx)Y9P8L?O2{rzEo=Clwmj48f^Iphyf(Eh)*&OD|SP z%u7*7Oa|Fi%n+QBUkoC=dI$p_mGO_rJY zc?t#KR0h=ymo7^!!YTue7OZlh&s*uyP7Jy(p!}_1WMF8nYiOiv zWU63jZe?JhZD43%z!l)H82{Hw*I-kVi65WuZ#Ju91#FG3XD~06zl+>c^(mVy5 z{G6Oj2N+i`CDo40CowO*G%-C@HzYMN*Gd7-w^B&Ww?_k(Yk<=x?sR70R@ecjLc$a-KWWb ys1g+Ni&9dHz_meUaS6RE25_kgE%{L^6Pi{FNtFuFmRnM#0;I-Cs#J(XuLl5bDAx}F delta 1280 zcmZ1?KUb>$o)F7a1_lNOBL)Tr83qQ1HH-`l&I}9;Hq0PV1_lon1_nU}1_nh=2@cWnkcBU|_fcRex_{pm06N1)re; zKcNc$K@AdSV_**VgBW1T#=xM+z`zj1#=s!Wz`#(#2C;Yo8^nQA*%%n)Kt5q( zV31^BV7LTT_l6DZ69x`;h{ILcAr8@IXQ&4Ul_@&|13v=;g9|$(=t7|UWGKIw9paNF zb_NC>1_p)+?2sUv%g(?cz{J3?k{uESyEq|HaE23N&Sg$Wh&!c%6sUqMsK$J#!7bd7D47lwU&jrJ zlEd5#44MoK3{SZsKI7+sI9Q4Y5+xQqkSGa<(uF(_kJWecKrCFr1990p9!Svb;DJQR zaVY;fl>ZE>?i&xp!JrfdO5L2ikPsB)Wnf@rU|>*UfH({kt&n`ez@Q6dfN}*Wrx-9W z)Pv(w1u6l`QJ|Cx%4+fq5Fcnk*YfJB8p0|SE|0|SE;1H_}C&=z2*2Wf*~Z3al3gYqUQ+ko;gNJarfFfcGM zL1|FR=VpM!pD-wQK*d3204TRWxd_TJC9AZ!M4==jRiP|Dr!+T}!Lg_$v$%x8IVW{8 z6OYSePqvej<=MAQX5ddqaj3)DO?PoNee2(kB1TOn0|Ks*RvpbQa Rs6-*ZC?&OM^8!8=MgTyugd+d| diff --git a/locale/en/LC_MESSAGES/mcg.po b/locale/en/LC_MESSAGES/mcg.po index bdc09fe..dfd501b 100644 --- a/locale/en/LC_MESSAGES/mcg.po +++ b/locale/en/LC_MESSAGES/mcg.po @@ -1,15 +1,15 @@ msgid "" msgstr "" "Project-Id-Version: CoverGrid (mcg)\n" -"POT-Creation-Date: 2017-09-10 14:15+0200\n" -"PO-Revision-Date: 2017-09-10 14:16+0200\n" +"POT-Creation-Date: 2017-12-25 17:08+0100\n" +"PO-Revision-Date: 2017-12-25 17:08+0100\n" "Last-Translator: coderkun \n" "Language-Team: \n" "Language: en\n" "MIME-Version: 1.0\n" "Content-Type: text/plain; charset=UTF-8\n" "Content-Transfer-Encoding: 8bit\n" -"X-Generator: Poedit 2.0.3\n" +"X-Generator: Poedit 2.0.5\n" "X-Poedit-Basepath: ../../..\n" "Plural-Forms: nplurals=2; plural=(n != 1);\n" "X-Poedit-SearchPath-0: data/gtk.glade\n" @@ -57,87 +57,147 @@ msgstr "by Title" msgid "sort by year" msgstr "by Year" -#: data/gtk.glade:436 +#: data/gtk.glade:437 msgid "Enter hostname or IP address" msgstr "Enter hostname or IP address" -#: data/gtk.glade:448 +#: data/gtk.glade:449 msgid "Enter URL or local path" msgstr "Enter URL or local path" -#: data/gtk.glade:460 +#: data/gtk.glade:461 msgid "Enter password or leave blank" msgstr "Enter password or leave blank" -#: data/gtk.glade:485 +#: data/gtk.glade:487 msgid "Host:" msgstr "Host:" -#: data/gtk.glade:497 +#: data/gtk.glade:499 msgid "Port:" msgstr "Port:" -#: data/gtk.glade:509 +#: data/gtk.glade:511 msgid "Password:" msgstr "Password:" -#: data/gtk.glade:521 +#: data/gtk.glade:523 msgid "Image Directory:" msgstr "Image Directory:" -#: data/gtk.glade:545 data/gtk.menu.ui:24 -msgid "Connection" -msgstr "Connection" +#: data/gtk.glade:619 +msgid "File:" +msgstr "File:" -#: data/gtk.glade:714 data/gtk.menu.ui:30 +#: data/gtk.glade:631 +msgid "Audio:" +msgstr "Audio:" + +#: data/gtk.glade:643 +msgid "Bitrate:" +msgstr "Bitrate:" + +#: data/gtk.glade:655 +msgid "Error:" +msgstr "Error:" + +#: data/gtk.glade:667 data/gtk.glade:681 data/gtk.glade:695 data/gtk.glade:709 +msgid "none" +msgstr "none" + +#: data/gtk.glade:742 +msgid "Status" +msgstr "Status" + +#: data/gtk.glade:827 +msgid "Albums" +msgstr "Albums" + +#: data/gtk.glade:839 +msgid "Songs" +msgstr "Songs" + +#: data/gtk.glade:851 +msgid "Artists" +msgstr "Artists" + +#: data/gtk.glade:875 +msgid "Seconds" +msgstr "Seconds" + +#: data/gtk.glade:922 +msgid "Seconds played" +msgstr "Seconds" + +#: data/gtk.glade:933 +msgid "Seconds running" +msgstr "Seconds running" + +#: data/gtk.glade:964 +msgid "Statistics" +msgstr "Statistics" + +#: data/gtk.glade:1034 +msgid "Audio Devices" +msgstr "Audio Devices" + +#: data/gtk.glade:1048 +msgid "Server" +msgstr "Server" + +#: data/gtk.glade:1217 data/gtk.menu.ui:30 msgid "Cover" msgstr "Cover" -#: data/gtk.glade:856 data/gtk.menu.ui:36 +#: data/gtk.glade:1359 data/gtk.menu.ui:36 msgid "Playlist" msgstr "Playlist" -#: data/gtk.glade:883 +#: data/gtk.glade:1386 msgid "search library" msgstr "search library" -#: data/gtk.glade:1042 data/gtk.menu.ui:42 +#: data/gtk.glade:1545 data/gtk.menu.ui:42 msgid "Library" msgstr "Library" -#: data/gtk.glade:1114 data/gtk.shortcuts.ui:74 +#: data/gtk.glade:1624 data/gtk.shortcuts.ui:74 msgid "Connect or disconnect" msgstr "Connect or disconnect" -#: data/gtk.glade:1136 data/gtk.shortcuts.ui:81 +#: data/gtk.glade:1646 data/gtk.shortcuts.ui:81 msgid "Switch between play and pause" msgstr "Switch between play and pause" -#: data/gtk.glade:1156 +#: data/gtk.glade:1666 msgid "Adjust the volume" msgstr "Adjust the volume" -#: data/gtk.glade:1214 data/gtk.shortcuts.ui:101 +#: data/gtk.glade:1710 +msgid "Connect to MPD" +msgstr "Connect to MPD" + +#: data/gtk.glade:1752 data/gtk.shortcuts.ui:101 msgid "Show the cover in fullscreen mode" msgstr "Show the cover in fullscreen mode" -#: data/gtk.glade:1237 data/gtk.glade:1386 +#: data/gtk.glade:1775 data/gtk.glade:1924 msgid "Settings and actions" msgstr "Settings and actions" -#: data/gtk.glade:1285 data/gtk.glade:1364 +#: data/gtk.glade:1823 data/gtk.glade:1902 msgid "Select multiple albums" msgstr "Select multiple albums" -#: data/gtk.glade:1307 data/gtk.shortcuts.ui:88 +#: data/gtk.glade:1845 data/gtk.shortcuts.ui:88 msgid "Clear the playlist" msgstr "Clear the playlist" -#: data/gtk.glade:1341 data/gtk.shortcuts.ui:114 +#: data/gtk.glade:1879 data/gtk.shortcuts.ui:114 msgid "Search the library" msgstr "Search the library" -#: data/gtk.glade:1431 +#: data/gtk.glade:1969 msgid "" "CoverGrid is a client for the Music Player Daemon, focusing on albums " "instead of single tracks." @@ -157,6 +217,10 @@ msgstr "Play" msgid "Clear Playlist" msgstr "Clear Playlist" +#: data/gtk.menu.ui:24 +msgid "Connection" +msgstr "Connection" + #: data/gtk.menu.ui:50 msgid "Keyboard Shortcuts" msgstr "Keyboard Shortcuts" @@ -228,6 +292,3 @@ msgstr "{} feat. {}" #~ msgid "_Quit" #~ msgstr "_Quit" - -#~ msgid "Server" -#~ msgstr "Server"