commit
16c2ffd775
|
@ -42,7 +42,7 @@
|
|||
<description>Window maximized state.</description>
|
||||
</key>
|
||||
<key type="i" name="panel">
|
||||
<range min="1" max="3"/>
|
||||
<range min="0" max="3"/>
|
||||
<default>1</default>
|
||||
<summary>Last selected panel</summary>
|
||||
<description>The index of the last selected panel.</description>
|
||||
|
|
1430
data/gtk.glade
1430
data/gtk.glade
File diff suppressed because it is too large
Load diff
Binary file not shown.
|
@ -1,15 +1,15 @@
|
|||
msgid ""
|
||||
msgstr ""
|
||||
"Project-Id-Version: CoverGrid (mcg)\n"
|
||||
"POT-Creation-Date: 2017-09-10 14:16+0200\n"
|
||||
"PO-Revision-Date: 2017-09-10 14:16+0200\n"
|
||||
"POT-Creation-Date: 2017-12-25 17:10+0100\n"
|
||||
"PO-Revision-Date: 2017-12-25 17:10+0100\n"
|
||||
"Last-Translator: coderkun <olli@coderkun.de>\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 "<i>none</i>"
|
||||
msgstr "<i>nichts</i>"
|
||||
|
||||
#: 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"
|
||||
|
|
Binary file not shown.
|
@ -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 <olli@coderkun.de>\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 "<i>none</i>"
|
||||
msgstr "<i>none</i>"
|
||||
|
||||
#: 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"
|
||||
|
|
118
mcg/client.py
118
mcg/client.py
|
@ -108,10 +108,14 @@ 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
|
||||
SIGNAL_LOAD_PLAYLIST = 'load-playlist'
|
||||
# Signal: load audio output devices
|
||||
SIGNAL_LOAD_OUTPUT_DEVICES = 'load-output-devices'
|
||||
# Signal: error
|
||||
SIGNAL_ERROR = 'error'
|
||||
|
||||
|
@ -174,6 +178,25 @@ 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 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)
|
||||
|
@ -343,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):
|
||||
|
@ -375,10 +401,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 +421,66 @@ 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 _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 _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):
|
||||
|
@ -684,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']
|
||||
|
|
188
mcg/widgets.py
188
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,8 @@ 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_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)
|
||||
|
@ -157,6 +161,8 @@ 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_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)
|
||||
|
@ -172,7 +178,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 +189,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()
|
||||
|
||||
|
@ -298,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()
|
||||
|
@ -346,6 +356,8 @@ class Window():
|
|||
self._mcg.load_playlist()
|
||||
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)
|
||||
|
@ -358,7 +370,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)
|
||||
if not album and self._fullscreened:
|
||||
|
@ -374,6 +386,8 @@ class Window():
|
|||
self._play_action.set_state(GLib.Variant.new_boolean(False))
|
||||
# Volume
|
||||
GObject.idle_add(self._header_bar.set_volume, volume)
|
||||
# Status
|
||||
self._panels[Window._PANEL_INDEX_SERVER].set_status(file, audio, bitrate, error)
|
||||
# Error
|
||||
if error is None:
|
||||
self._infobar.hide()
|
||||
|
@ -381,12 +395,20 @@ 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_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._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):
|
||||
|
@ -424,17 +446,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)
|
||||
|
||||
|
@ -442,6 +463,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())
|
||||
|
||||
|
||||
|
@ -451,8 +473,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):
|
||||
|
@ -469,8 +491,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):
|
||||
|
@ -508,6 +529,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')
|
||||
|
@ -582,6 +605,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):
|
||||
|
@ -593,6 +617,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):
|
||||
|
@ -675,8 +700,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)
|
||||
|
@ -701,10 +725,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,
|
||||
|
@ -792,6 +812,118 @@ 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._none_label = ""
|
||||
self._output_buttons = {}
|
||||
|
||||
# Widgets
|
||||
self._panel = builder.get_object('server-panel')
|
||||
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')
|
||||
self._none_label = self._status_file.get_label()
|
||||
|
||||
# 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')
|
||||
|
||||
# Audio ouptut devices widgets
|
||||
self._output_devices = builder.get_object('server-output-devices')
|
||||
|
||||
|
||||
def get(self):
|
||||
return self._panel
|
||||
|
||||
|
||||
def get_toolbar(self):
|
||||
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 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._none_label
|
||||
self._status_audio.set_markup(audio)
|
||||
# Bitrate
|
||||
if bitrate:
|
||||
bitrate = bitrate + " kb/s"
|
||||
else:
|
||||
bitrate = self._none_label
|
||||
self._status_bitrate.set_markup(bitrate)
|
||||
# Error
|
||||
if error:
|
||||
error = GObject.markup_escape_text(error)
|
||||
else:
|
||||
error = self._none_label
|
||||
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))
|
||||
|
||||
|
||||
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):
|
||||
__gsignals__ = {
|
||||
'toggle-fullscreen': (GObject.SIGNAL_RUN_FIRST, None, ()),
|
||||
|
|
Loading…
Reference in a new issue