mirror of
https://github.com/SoongNoonien/mpdevil.git
synced 2023-08-10 21:12:44 +03:00
Compare commits
16 Commits
Author | SHA1 | Date | |
---|---|---|---|
![]() |
79ce749f61 | ||
![]() |
75a08b6254 | ||
![]() |
ce350bca83 | ||
![]() |
6d3def7d62 | ||
![]() |
1b96ea30f5 | ||
![]() |
20566566cd | ||
![]() |
12da5321b8 | ||
![]() |
03f2ccd747 | ||
![]() |
e79b6f8d6f | ||
![]() |
c953bfa8b3 | ||
![]() |
423a123f79 | ||
![]() |
7a2c8cbf12 | ||
![]() |
4cc8c46055 | ||
![]() |
053dbbe08f | ||
![]() |
291507ca1c | ||
![]() |
a958438f32 |
455
bin/mpdevil
455
bin/mpdevil
@@ -39,8 +39,9 @@ import re
|
||||
import dbus
|
||||
import dbus.service
|
||||
from dbus.mainloop.glib import DBusGMainLoop
|
||||
DBusGMainLoop(set_as_default=True)
|
||||
|
||||
VERSION='0.9.0' # sync with setup.py
|
||||
VERSION='0.9.1' # sync with setup.py
|
||||
COVER_REGEX="^\.?(album|cover|folder|front).*\.(gif|jpeg|jpg|png)$"
|
||||
|
||||
|
||||
@@ -100,6 +101,8 @@ class MPRISInterface(dbus.service.Object): # TODO emit Seeked if needed
|
||||
self._client.emitter.connect("repeat", self._on_loop_changed)
|
||||
self._client.emitter.connect("single", self._on_loop_changed)
|
||||
self._client.emitter.connect("random", self._on_random_changed)
|
||||
self._client.emitter.connect("disconnected", self._on_disconnected)
|
||||
self._client.emitter.connect("reconnected", self._on_reconnected)
|
||||
|
||||
def acquire_name(self):
|
||||
self._bus_name=dbus.service.BusName(self._name, bus=self._bus, allow_replacement=True, replace_existing=True)
|
||||
@@ -178,7 +181,8 @@ class MPRISInterface(dbus.service.Object): # TODO emit Seeked if needed
|
||||
|
||||
if 'file' in mpd_meta:
|
||||
song_file=mpd_meta['file']
|
||||
self._metadata['xesam:url']="file://"+os.path.join(self._settings.get_value("paths")[self._settings.get_int("active-profile")], song_file)
|
||||
lib_path=self._settings.get_value("paths")[self._settings.get_int("active-profile")]
|
||||
self._metadata['xesam:url']="file://"+os.path.join(lib_path, song_file)
|
||||
cover=Cover(self._settings, mpd_meta)
|
||||
if cover.path is None:
|
||||
self._metadata['mpris:artUrl']=None
|
||||
@@ -430,6 +434,13 @@ class MPRISInterface(dbus.service.Object): # TODO emit Seeked if needed
|
||||
def _on_random_changed(self, *args):
|
||||
self.update_property('org.mpris.MediaPlayer2.Player', 'Shuffle')
|
||||
|
||||
def _on_reconnected(self, *args):
|
||||
self.acquire_name()
|
||||
|
||||
def _on_disconnected(self, *args):
|
||||
self.release_name()
|
||||
self._metadata={}
|
||||
|
||||
def _name_owner_changed_callback(self, name, old_owner, new_owner):
|
||||
if name == self._name and old_owner == self._uname and new_owner != "":
|
||||
try:
|
||||
@@ -566,8 +577,8 @@ class Cover(object):
|
||||
break
|
||||
|
||||
def get_pixbuf(self, size):
|
||||
if self.path is None:
|
||||
self.path=Gtk.IconTheme.get_default().lookup_icon("media-optical", size, Gtk.IconLookupFlags.FORCE_SVG).get_filename() # fallback cover
|
||||
if self.path is None: # fallback needed
|
||||
self.path=Gtk.IconTheme.get_default().lookup_icon("media-optical", size, Gtk.IconLookupFlags.FORCE_SVG).get_filename()
|
||||
return GdkPixbuf.Pixbuf.new_from_file_at_size(self.path, size, size)
|
||||
|
||||
######################
|
||||
@@ -590,7 +601,16 @@ class ClientHelper():
|
||||
return return_song
|
||||
|
||||
def extend_song_for_display(song):
|
||||
base_song={"title": _("Unknown Title"), "track": "0", "disc": "", "artist": _("Unknown Artist"), "album": _("Unknown Album"), "duration": "0.0", "date": "", "genre": ""}
|
||||
base_song={
|
||||
"title": _("Unknown Title"),
|
||||
"track": "0",
|
||||
"disc": "",
|
||||
"artist": _("Unknown Artist"),
|
||||
"album": _("Unknown Album"),
|
||||
"duration": "0.0",
|
||||
"date": "",
|
||||
"genre": ""
|
||||
}
|
||||
base_song.update(song)
|
||||
base_song["human_duration"]=str(datetime.timedelta(seconds=int(float(base_song["duration"])))).lstrip("0").lstrip(":")
|
||||
return base_song
|
||||
@@ -610,6 +630,7 @@ class MpdEventEmitter(GObject.Object):
|
||||
'update': (GObject.SignalFlags.RUN_FIRST, None, ()),
|
||||
'disconnected': (GObject.SignalFlags.RUN_FIRST, None, ()),
|
||||
'reconnected': (GObject.SignalFlags.RUN_FIRST, None, ()),
|
||||
'connection_error': (GObject.SignalFlags.RUN_FIRST, None, ()),
|
||||
'current_song_changed': (GObject.SignalFlags.RUN_FIRST, None, ()),
|
||||
'state': (GObject.SignalFlags.RUN_FIRST, None, (str,)),
|
||||
'elapsed_changed': (GObject.SignalFlags.RUN_FIRST, None, (float,float,)),
|
||||
@@ -619,7 +640,7 @@ class MpdEventEmitter(GObject.Object):
|
||||
'random': (GObject.SignalFlags.RUN_FIRST, None, (bool,)),
|
||||
'single': (GObject.SignalFlags.RUN_FIRST, None, (bool,)),
|
||||
'consume': (GObject.SignalFlags.RUN_FIRST, None, (bool,)),
|
||||
'audio': (GObject.SignalFlags.RUN_FIRST, None, (float,int,int,)),
|
||||
'audio': (GObject.SignalFlags.RUN_FIRST, None, (str,str,str,)),
|
||||
'bitrate': (GObject.SignalFlags.RUN_FIRST, None, (float,))
|
||||
}
|
||||
|
||||
@@ -636,6 +657,9 @@ class MpdEventEmitter(GObject.Object):
|
||||
def do_reconnected(self):
|
||||
pass
|
||||
|
||||
def do_connection_error(self):
|
||||
print("Connection error!")
|
||||
|
||||
def do_current_file_changed(self):
|
||||
pass
|
||||
|
||||
@@ -666,6 +690,7 @@ class Client(MPDClient):
|
||||
self.emitter=MpdEventEmitter()
|
||||
self._last_status={}
|
||||
self._refresh_interval=self._settings.get_int("refresh-interval")
|
||||
self._main_timeout_id=None
|
||||
|
||||
#connect
|
||||
self._settings.connect("changed::active-profile", self._on_active_profile_changed)
|
||||
@@ -678,9 +703,27 @@ class Client(MPDClient):
|
||||
return func(*args)
|
||||
|
||||
def start(self):
|
||||
if self._disconnected_loop():
|
||||
self.emitter.emit("disconnected")
|
||||
self._disconnected_timeout_id=GLib.timeout_add(1000, self._disconnected_loop)
|
||||
self.emitter.emit("disconnected") # bring player in defined state
|
||||
active=self._settings.get_int("active-profile")
|
||||
try:
|
||||
self.connect(self._settings.get_value("hosts")[active], self._settings.get_value("ports")[active])
|
||||
if self._settings.get_value("passwords")[active] != "":
|
||||
self.password(self._settings.get_value("passwords")[active])
|
||||
except:
|
||||
self.emitter.emit("connection_error")
|
||||
return False
|
||||
# connect successful
|
||||
self._main_timeout_id=GLib.timeout_add(self._refresh_interval, self._main_loop)
|
||||
self.emitter.emit("reconnected")
|
||||
return True
|
||||
|
||||
def reconnect(self):
|
||||
if self._main_timeout_id is not None:
|
||||
GLib.source_remove(self._main_timeout_id)
|
||||
self._main_timeout_id=None
|
||||
self._last_status={}
|
||||
self.disconnect()
|
||||
self.start()
|
||||
|
||||
def connected(self):
|
||||
try:
|
||||
@@ -761,8 +804,11 @@ class Client(MPDClient):
|
||||
elif key == "state":
|
||||
self.emitter.emit("state", val)
|
||||
elif key == "audio":
|
||||
# see: https://www.musicpd.org/doc/html/user.html#audio-output-format
|
||||
samplerate, bits, channels=val.split(':')
|
||||
self.emitter.emit("audio", float(samplerate), int(bits), int(channels))
|
||||
if bits == "f":
|
||||
bits="32fp"
|
||||
self.emitter.emit("audio", samplerate, bits, channels)
|
||||
elif key == "volume":
|
||||
self.emitter.emit("volume_changed", float(val))
|
||||
elif key == "playlist":
|
||||
@@ -784,27 +830,13 @@ class Client(MPDClient):
|
||||
self.disconnect()
|
||||
self._last_status={}
|
||||
self.emitter.emit("disconnected")
|
||||
if self._disconnected_loop():
|
||||
self._disconnected_timeout_id=GLib.timeout_add(1000, self._disconnected_loop)
|
||||
self.emitter.emit("connection_error")
|
||||
self._main_timeout_id=None
|
||||
return False
|
||||
return True
|
||||
|
||||
def _disconnected_loop(self, *args):
|
||||
active=self._settings.get_int("active-profile")
|
||||
try:
|
||||
self.connect(self._settings.get_value("hosts")[active], self._settings.get_value("ports")[active])
|
||||
if self._settings.get_value("passwords")[active] != "":
|
||||
self.password(self._settings.get_value("passwords")[active])
|
||||
except:
|
||||
print("connect failed")
|
||||
return True
|
||||
# connect successful
|
||||
self._main_timeout_id=GLib.timeout_add(self._refresh_interval, self._main_loop)
|
||||
self.emitter.emit("reconnected")
|
||||
return False
|
||||
|
||||
def _on_active_profile_changed(self, *args):
|
||||
self.disconnect()
|
||||
self.reconnect()
|
||||
|
||||
########################
|
||||
# gio settings wrapper #
|
||||
@@ -818,7 +850,14 @@ class Settings(Gio.Settings):
|
||||
# fix profile settings
|
||||
if len(self.get_value("profiles")) < (self.get_int("active-profile")+1):
|
||||
self.set_int("active-profile", 0)
|
||||
profile_keys=[('as', "profiles", "new profile"), ('as', "hosts", "localhost"), ('ai', "ports", 6600), ('as', "passwords", ""), ('as', "paths", ""), ('as', "regex", "")]
|
||||
profile_keys=[
|
||||
('as', "profiles", "new profile"),
|
||||
('as', "hosts", "localhost"),
|
||||
('ai', "ports", 6600),
|
||||
('as', "passwords", ""),
|
||||
('as', "paths", ""),
|
||||
('as', "regex", "")
|
||||
]
|
||||
profile_arrays=[]
|
||||
for vtype, key, default in profile_keys:
|
||||
profile_arrays.append(self.get_value(key).unpack())
|
||||
@@ -976,7 +1015,11 @@ class SearchWindow(Gtk.Box):
|
||||
songs=self._client.wrapped_call("search", self._tags.get_active_text(), self._search_entry.get_text())
|
||||
for s in songs:
|
||||
song=ClientHelper.extend_song_for_display(ClientHelper.song_to_str_dict(s))
|
||||
self._store.append([int(song["track"]), song["title"], song["artist"], song["album"], song["human_duration"], song["file"]])
|
||||
self._store.append([
|
||||
int(song["track"]), song["title"],
|
||||
song["artist"], song["album"],
|
||||
song["human_duration"], song["file"]
|
||||
])
|
||||
self._hits_label.set_text(_("%i hits") % (self._songs_view.count()))
|
||||
if self._songs_view.count() == 0:
|
||||
self._action_bar.set_sensitive(False)
|
||||
@@ -1325,8 +1368,8 @@ class ArtistWindow(FocusFrame):
|
||||
self._treeview.connect("row-activated", self._on_row_activated)
|
||||
self._settings.connect("changed::use-album-artist", self._refresh)
|
||||
self._settings.connect("changed::show-initials", self._on_show_initials_changed)
|
||||
self._client.emitter.connect("disconnected", self._clear)
|
||||
self._client.emitter.connect("reconnected", self._refresh)
|
||||
self._client.emitter.connect("disconnected", self._on_disconnected)
|
||||
self._client.emitter.connect("reconnected", self._on_reconnected)
|
||||
self._client.emitter.connect("update", self._refresh)
|
||||
self._genre_select.connect("genre_changed", self._refresh)
|
||||
|
||||
@@ -1402,6 +1445,14 @@ class ArtistWindow(FocusFrame):
|
||||
self._store[path][1]=Pango.Weight.BOLD
|
||||
self.emit("artists_changed")
|
||||
|
||||
def _on_disconnected(self, *args):
|
||||
self.set_sensitive(False)
|
||||
self._clear()
|
||||
|
||||
def _on_reconnected(self, *args):
|
||||
self._refresh()
|
||||
self.set_sensitive(True)
|
||||
|
||||
def _on_show_initials_changed(self, *args):
|
||||
self._column_initials.set_visible(self._settings.get_boolean("show-initials"))
|
||||
|
||||
@@ -1438,12 +1489,12 @@ class AlbumWindow(FocusFrame):
|
||||
self._iconview.connect("button-press-event", self._on_button_press_event)
|
||||
self._key_press_event=self.connect("key-press-event", self._on_key_press_event)
|
||||
self._client.emitter.connect("update", self._clear)
|
||||
self._client.emitter.connect("disconnected", self._clear)
|
||||
self._client.emitter.connect("disconnected", self._on_disconnected)
|
||||
self._client.emitter.connect("reconnected", self._on_reconnected)
|
||||
self._settings.connect("changed::show-album-view-tooltips", self._tooltip_settings)
|
||||
self._settings.connect("changed::sort-albums-by-year", self._sort_settings)
|
||||
self._settings.connect("changed::album-cover", self._on_cover_size_changed)
|
||||
self._settings.connect("changed::use-album-artist", self._clear)
|
||||
self.connect("done", self._on_done)
|
||||
self._artist_window.connect("artists_changed", self._refresh)
|
||||
|
||||
self.set_widget(self._iconview)
|
||||
@@ -1503,7 +1554,10 @@ class AlbumWindow(FocusFrame):
|
||||
def _refresh(self, *args):
|
||||
def callback():
|
||||
GLib.idle_add(self._workaround_clear)
|
||||
try: # self._artist_window could still be empty
|
||||
genre, artists=self._artist_window.get_selected_artists()
|
||||
except:
|
||||
GLib.idle_add(self._done_callback)
|
||||
# show artist names if all albums are shown
|
||||
if len(artists) > 1:
|
||||
self._iconview.set_markup_column(2)
|
||||
@@ -1515,22 +1569,26 @@ class AlbumWindow(FocusFrame):
|
||||
for artist in artists:
|
||||
try: # client cloud meanwhile disconnect
|
||||
if self.stop_flag:
|
||||
GLib.idle_add(self.emit, "done")
|
||||
GLib.idle_add(self._done_callback)
|
||||
return
|
||||
else:
|
||||
if genre is None:
|
||||
album_candidates=self._client.wrapped_call("comp_list", "album", artist_type, artist)
|
||||
else:
|
||||
album_candidates=self._client.wrapped_call("comp_list", "album", artist_type, artist, "genre", genre)
|
||||
album_candidates=self._client.wrapped_call(
|
||||
"comp_list", "album", artist_type, artist, "genre", genre
|
||||
)
|
||||
for album in album_candidates:
|
||||
years=self._client.wrapped_call("comp_list", "date", "album", album, artist_type, artist)
|
||||
for year in years:
|
||||
songs=self._client.wrapped_call("find", "album", album, "date", year, artist_type, artist)
|
||||
songs=self._client.wrapped_call(
|
||||
"find", "album", album, "date", year, artist_type, artist
|
||||
)
|
||||
albums.append({"artist": artist, "album": album, "year": year, "songs": songs})
|
||||
while Gtk.events_pending():
|
||||
Gtk.main_iteration_do(True)
|
||||
except MPDBase.ConnectionError:
|
||||
GLib.idle_add(self.emit, "done")
|
||||
GLib.idle_add(self._done_callback)
|
||||
return
|
||||
# display albums
|
||||
if self._settings.get_boolean("sort-albums-by-year"):
|
||||
@@ -1550,9 +1608,11 @@ class AlbumWindow(FocusFrame):
|
||||
except:
|
||||
discs=1
|
||||
if discs > 1:
|
||||
tooltip=(_("%(total_tracks)i titles on %(discs)i discs (%(total_length)s)") % {"total_tracks": len(album["songs"]), "discs": discs, "total_length": length_human_readable})
|
||||
tooltip=(_("%(total_tracks)i titles on %(discs)i discs (%(total_length)s)")
|
||||
%{"total_tracks": len(album["songs"]), "discs": discs, "total_length": length_human_readable})
|
||||
else:
|
||||
tooltip=(_("%(total_tracks)i titles (%(total_length)s)") % {"total_tracks": len(album["songs"]), "total_length": length_human_readable})
|
||||
tooltip=(_("%(total_tracks)i titles (%(total_length)s)")
|
||||
%{"total_tracks": len(album["songs"]), "total_length": length_human_readable})
|
||||
# album label
|
||||
display_label="<b>"+album["album"]+"</b>"
|
||||
if album["year"] != "":
|
||||
@@ -1561,12 +1621,14 @@ class AlbumWindow(FocusFrame):
|
||||
display_label=display_label.replace("&", "&")
|
||||
display_label_artist=display_label_artist.replace("&", "&")
|
||||
# add album
|
||||
GLib.idle_add(self._add_row, [cover, display_label, display_label_artist, tooltip, album["album"], album["year"], album["artist"]])
|
||||
GLib.idle_add(self._add_row,
|
||||
[cover, display_label, display_label_artist, tooltip, album["album"], album["year"], album["artist"]]
|
||||
)
|
||||
# execute pending events
|
||||
if i%16 == 0:
|
||||
while Gtk.events_pending():
|
||||
Gtk.main_iteration_do(True)
|
||||
GLib.idle_add(self.emit, "done")
|
||||
GLib.idle_add(self._done_callback)
|
||||
if self._done:
|
||||
self._done=False
|
||||
callback()
|
||||
@@ -1589,11 +1651,8 @@ class AlbumWindow(FocusFrame):
|
||||
album_dialog.open()
|
||||
album_dialog.destroy()
|
||||
|
||||
@GObject.Signal
|
||||
def done(self):
|
||||
def _done_callback(self, *args):
|
||||
self.stop_flag=False
|
||||
|
||||
def _on_done(self, *args):
|
||||
self._done=True
|
||||
pending=self._pending
|
||||
self._pending=[]
|
||||
@@ -1602,6 +1661,7 @@ class AlbumWindow(FocusFrame):
|
||||
p()
|
||||
except:
|
||||
pass
|
||||
return False
|
||||
|
||||
def _on_button_press_event(self, widget, event):
|
||||
path=widget.get_path_at_pos(int(event.x), int(event.y))
|
||||
@@ -1642,6 +1702,13 @@ class AlbumWindow(FocusFrame):
|
||||
selected_artist=self._store.get_value(treeiter, 6)
|
||||
self._client.wrapped_call("album_to_playlist", selected_album, selected_artist, selected_album_year, "play")
|
||||
|
||||
def _on_disconnected(self, *args):
|
||||
self._iconview.set_sensitive(False)
|
||||
self._clear()
|
||||
|
||||
def _on_reconnected(self, *args):
|
||||
self._iconview.set_sensitive(True)
|
||||
|
||||
def _on_cover_size_changed(self, *args):
|
||||
def callback():
|
||||
self._refresh()
|
||||
@@ -1782,7 +1849,13 @@ class LyricsWindow(Gtk.Overlay):
|
||||
self._client=client
|
||||
|
||||
# text view
|
||||
text_view=Gtk.TextView(editable=False, cursor_visible=False, wrap_mode=Gtk.WrapMode.WORD, justification=Gtk.Justification.CENTER, opacity=0.9)
|
||||
text_view=Gtk.TextView(
|
||||
editable=False,
|
||||
cursor_visible=False,
|
||||
wrap_mode=Gtk.WrapMode.WORD,
|
||||
justification=Gtk.Justification.CENTER,
|
||||
opacity=0.9
|
||||
)
|
||||
text_view.set_left_margin(5)
|
||||
text_view.set_bottom_margin(5)
|
||||
text_view.set_top_margin(3)
|
||||
@@ -1800,11 +1873,11 @@ class LyricsWindow(Gtk.Overlay):
|
||||
frame.set_widget(text_view)
|
||||
|
||||
# close button
|
||||
close_button=Gtk.ToggleButton(image=Gtk.Image.new_from_icon_name("window-close-symbolic", Gtk.IconSize.BUTTON))
|
||||
close_button=Gtk.Button(image=Gtk.Image.new_from_icon_name("window-close-symbolic", Gtk.IconSize.BUTTON))
|
||||
close_button.set_margin_top(6)
|
||||
close_button.set_margin_end(6)
|
||||
close_button.set_halign(2)
|
||||
close_button.set_valign(1)
|
||||
close_button.set_halign(Gtk.Align.END)
|
||||
close_button.set_valign(Gtk.Align.START)
|
||||
style_context=close_button.get_style_context()
|
||||
style_context.add_class("circular")
|
||||
|
||||
@@ -1831,7 +1904,11 @@ class LyricsWindow(Gtk.Overlay):
|
||||
GLib.idle_add(self._text_buffer.set_text, text, -1)
|
||||
|
||||
def _refresh(self, *args):
|
||||
update_thread=threading.Thread(target=self._display_lyrics, kwargs={"current_song": ClientHelper.song_to_first_str_dict(self._client.wrapped_call("currentsong"))}, daemon=True)
|
||||
update_thread=threading.Thread(
|
||||
target=self._display_lyrics,
|
||||
kwargs={"current_song": ClientHelper.song_to_first_str_dict(self._client.wrapped_call("currentsong"))},
|
||||
daemon=True
|
||||
)
|
||||
update_thread.start()
|
||||
|
||||
def _get_lyrics(self, singer, song): # partially copied from PyLyrics 1.1.0
|
||||
@@ -1897,11 +1974,15 @@ class AudioType(Gtk.Label):
|
||||
self.file_type=""
|
||||
|
||||
def _refresh(self, *args):
|
||||
string=_("%(bitrate)s kb/s, %(frequency)s kHz, %(resolution)i bit, %(channels)i channels, %(file_type)s") % {"bitrate": str(self.brate), "frequency": str(self.freq), "resolution": self.res, "channels": self.chan, "file_type": self.file_type}
|
||||
string=(_("%(bitrate)s kb/s, %(frequency)s kHz, %(resolution)s bit, %(channels)s channels, %(file_type)s")
|
||||
%{"bitrate": self.brate, "frequency": self.freq, "resolution": self.res, "channels": self.chan, "file_type": self.file_type})
|
||||
self.set_text(string)
|
||||
|
||||
def _on_audio(self, emitter, freq, res, chan):
|
||||
self.freq=freq/1000
|
||||
try:
|
||||
self.freq=str(int(freq)/1000)
|
||||
except:
|
||||
self.freq=freq
|
||||
self.res=res
|
||||
self.chan=chan
|
||||
self._refresh()
|
||||
@@ -2024,10 +2105,18 @@ class PlaylistWindow(Gtk.Box):
|
||||
css=b"""* {min-height: 8px;}""" # allow further shrinking
|
||||
provider.load_from_data(css)
|
||||
|
||||
self._back_to_current_song_button=Gtk.Button(image=self._icons["go-previous-symbolic"], tooltip_text=_("Scroll to current song"), relief=Gtk.ReliefStyle.NONE)
|
||||
self._back_to_current_song_button=Gtk.Button(
|
||||
image=self._icons["go-previous-symbolic"],
|
||||
tooltip_text=_("Scroll to current song"),
|
||||
relief=Gtk.ReliefStyle.NONE
|
||||
)
|
||||
style_context=self._back_to_current_song_button.get_style_context()
|
||||
style_context.add_provider(provider, 800)
|
||||
self._clear_button=Gtk.Button(image=self._icons["edit-clear-symbolic"], tooltip_text=_("Clear playlist"), relief=Gtk.ReliefStyle.NONE)
|
||||
self._clear_button=Gtk.Button(
|
||||
image=self._icons["edit-clear-symbolic"],
|
||||
tooltip_text=_("Clear playlist"),
|
||||
relief=Gtk.ReliefStyle.NONE
|
||||
)
|
||||
style_context=self._clear_button.get_style_context()
|
||||
style_context.add_class("destructive-action")
|
||||
style_context.add_provider(provider, 800)
|
||||
@@ -2143,7 +2232,8 @@ class PlaylistWindow(Gtk.Box):
|
||||
self._playlist_info.set_text("")
|
||||
else:
|
||||
whole_length_human_readable=ClientHelper.calc_display_length(songs)
|
||||
self._playlist_info.set_text(_("%(total_tracks)i titles (%(total_length)s)") % {"total_tracks": len(songs), "total_length": whole_length_human_readable})
|
||||
self._playlist_info.set_text(_("%(total_tracks)i titles (%(total_length)s)")
|
||||
%{"total_tracks": len(songs), "total_length": whole_length_human_readable})
|
||||
|
||||
def _scroll_to_selected_title(self, *args):
|
||||
treeview, treeiter=self._selection.get_selected()
|
||||
@@ -2219,9 +2309,26 @@ class PlaylistWindow(Gtk.Box):
|
||||
song=ClientHelper.extend_song_for_display(ClientHelper.song_to_str_dict(s))
|
||||
try:
|
||||
treeiter=self._store.get_iter(song["pos"])
|
||||
self._store.set(treeiter, 0, song["track"], 1, song["disc"], 2, song["title"], 3, song["artist"], 4, song["album"], 5, song["human_duration"], 6, song["date"], 7, song["genre"], 8, song["file"], 9, Pango.Weight.BOOK)
|
||||
self._store.set(treeiter,
|
||||
0, song["track"],
|
||||
1, song["disc"],
|
||||
2, song["title"],
|
||||
3, song["artist"],
|
||||
4, song["album"],
|
||||
5, song["human_duration"],
|
||||
6, song["date"],
|
||||
7, song["genre"],
|
||||
8, song["file"],
|
||||
9, Pango.Weight.BOOK
|
||||
)
|
||||
except:
|
||||
self._store.append([song["track"], song["disc"], song["title"], song["artist"], song["album"], song["human_duration"], song["date"], song["genre"], song["file"], Pango.Weight.BOOK])
|
||||
self._store.append([
|
||||
song["track"], song["disc"],
|
||||
song["title"], song["artist"],
|
||||
song["album"], song["human_duration"],
|
||||
song["date"], song["genre"],
|
||||
song["file"], Pango.Weight.BOOK
|
||||
])
|
||||
for i in reversed(range(int(self._client.wrapped_call("status")["playlistlength"]), len(self._store))):
|
||||
treeiter=self._store.get_iter(i)
|
||||
self._store.remove(treeiter)
|
||||
@@ -2247,6 +2354,7 @@ class PlaylistWindow(Gtk.Box):
|
||||
self._client.clear()
|
||||
|
||||
def _on_disconnected(self, *args):
|
||||
self._treeview.set_sensitive(False)
|
||||
self._clear()
|
||||
self._back_to_current_song_button.set_sensitive(False)
|
||||
self._clear_button.set_sensitive(False)
|
||||
@@ -2254,6 +2362,7 @@ class PlaylistWindow(Gtk.Box):
|
||||
def _on_reconnected(self, *args):
|
||||
self._back_to_current_song_button.set_sensitive(True)
|
||||
self._clear_button.set_sensitive(True)
|
||||
self._treeview.set_sensitive(True)
|
||||
|
||||
def _on_icon_size_changed(self, *args):
|
||||
pixel_size=self._settings.get_int("icon-size-sec")
|
||||
@@ -2273,17 +2382,20 @@ class CoverLyricsOSD(Gtk.Overlay):
|
||||
self._main_cover=MainCover(self._client, self._settings, self._window)
|
||||
|
||||
# lyrics button
|
||||
self._lyrics_button=Gtk.Button(image=Gtk.Image.new_from_icon_name("media-view-subtitles-symbolic", Gtk.IconSize.BUTTON), tooltip_text=_("Show lyrics"))
|
||||
self._lyrics_button=Gtk.Button(
|
||||
image=Gtk.Image.new_from_icon_name("media-view-subtitles-symbolic", Gtk.IconSize.BUTTON),
|
||||
tooltip_text=_("Show lyrics")
|
||||
)
|
||||
self._lyrics_button.set_margin_top(6)
|
||||
self._lyrics_button.set_margin_end(6)
|
||||
style_context=self._lyrics_button.get_style_context()
|
||||
style_context.add_class("circular")
|
||||
|
||||
# revealer
|
||||
# workaround to get tooltips in overlay
|
||||
self._revealer=Gtk.Revealer()
|
||||
self._revealer.set_halign(2)
|
||||
self._revealer.set_valign(1)
|
||||
self._revealer.set_margin_top(6)
|
||||
self._revealer.set_margin_end(6)
|
||||
self._revealer.set_halign(Gtk.Align.END)
|
||||
self._revealer.set_valign(Gtk.Align.START)
|
||||
self._revealer.add(self._lyrics_button)
|
||||
|
||||
# packing
|
||||
@@ -2306,11 +2418,11 @@ class CoverLyricsOSD(Gtk.Overlay):
|
||||
self._lyrics_button.set_sensitive(True)
|
||||
|
||||
def _on_disconnected(self, *args):
|
||||
self._lyrics_button.set_sensitive(False)
|
||||
try:
|
||||
self._lyrics_win.destroy()
|
||||
except:
|
||||
pass
|
||||
self._lyrics_button.set_sensitive(False)
|
||||
|
||||
def _on_lyrics_clicked(self, widget):
|
||||
self._lyrics_button.set_sensitive(False)
|
||||
@@ -2365,49 +2477,61 @@ class GeneralSettings(Gtk.Box):
|
||||
|
||||
# int_settings
|
||||
int_settings={}
|
||||
int_settings_data=[(_("Main cover size:"), (100, 1200, 10), "track-cover"),\
|
||||
(_("Album view cover size:"), (50, 600, 10), "album-cover"),\
|
||||
(_("Action bar icon size:"), (16, 64, 2), "icon-size"),\
|
||||
(_("Secondary icon size:"), (16, 64, 2), "icon-size-sec")]
|
||||
for data in int_settings_data:
|
||||
int_settings[data[2]]=(Gtk.Label(label=data[0], xalign=0), Gtk.SpinButton.new_with_range(data[1][0], data[1][1], data[1][2]))
|
||||
int_settings[data[2]][1].set_value(self._settings.get_int(data[2]))
|
||||
int_settings[data[2]][1].connect("value-changed", self._on_int_changed, data[2])
|
||||
self._settings_handlers.append(self._settings.connect("changed::"+data[2], self._on_int_settings_changed, int_settings[data[2]][1]))
|
||||
int_settings_data=[
|
||||
(_("Main cover size:"), (100, 1200, 10), "track-cover"),
|
||||
(_("Album view cover size:"), (50, 600, 10), "album-cover"),
|
||||
(_("Action bar icon size:"), (16, 64, 2), "icon-size"),
|
||||
(_("Secondary icon size:"), (16, 64, 2), "icon-size-sec")
|
||||
]
|
||||
for label, (vmin, vmax, step), key in int_settings_data:
|
||||
int_settings[key]=(Gtk.Label(label=label, xalign=0), Gtk.SpinButton.new_with_range(vmin, vmax, step))
|
||||
int_settings[key][1].set_value(self._settings.get_int(key))
|
||||
int_settings[key][1].connect("value-changed", self._on_int_changed, key)
|
||||
self._settings_handlers.append(
|
||||
self._settings.connect("changed::"+key, self._on_int_settings_changed, int_settings[key][1])
|
||||
)
|
||||
|
||||
# combo_settings
|
||||
combo_settings={}
|
||||
combo_settings_data=[(_("Sort albums by:"), _("name"), _("year"), "sort-albums-by-year"), \
|
||||
(_("Position of playlist:"), _("bottom"), _("right"), "playlist-right")]
|
||||
for data in combo_settings_data:
|
||||
combo_settings[data[3]]=(Gtk.Label(label=data[0], xalign=0), Gtk.ComboBoxText(entry_text_column=0))
|
||||
combo_settings[data[3]][1].append_text(data[1])
|
||||
combo_settings[data[3]][1].append_text(data[2])
|
||||
if self._settings.get_boolean(data[3]):
|
||||
combo_settings[data[3]][1].set_active(1)
|
||||
combo_settings_data=[
|
||||
(_("Sort albums by:"), _("name"), _("year"), "sort-albums-by-year"),
|
||||
(_("Position of playlist:"), _("bottom"), _("right"), "playlist-right")
|
||||
]
|
||||
for label, vfalse, vtrue, key in combo_settings_data:
|
||||
combo_settings[key]=(Gtk.Label(label=label, xalign=0), Gtk.ComboBoxText(entry_text_column=0))
|
||||
combo_settings[key][1].append_text(vfalse)
|
||||
combo_settings[key][1].append_text(vtrue)
|
||||
if self._settings.get_boolean(key):
|
||||
combo_settings[key][1].set_active(1)
|
||||
else:
|
||||
combo_settings[data[3]][1].set_active(0)
|
||||
combo_settings[data[3]][1].connect("changed", self._on_combo_changed, data[3])
|
||||
self._settings_handlers.append(self._settings.connect("changed::"+data[3], self._on_combo_settings_changed, combo_settings[data[3]][1]))
|
||||
combo_settings[key][1].set_active(0)
|
||||
combo_settings[key][1].connect("changed", self._on_combo_changed, key)
|
||||
self._settings_handlers.append(
|
||||
self._settings.connect("changed::"+key, self._on_combo_settings_changed, combo_settings[key][1])
|
||||
)
|
||||
|
||||
# check buttons
|
||||
check_buttons={}
|
||||
check_buttons_data=[(_("Use Client-side decoration"), "use-csd"), \
|
||||
(_("Show stop button"), "show-stop"), \
|
||||
(_("Show lyrics button"), "show-lyrics-button"), \
|
||||
(_("Show initials in artist view"), "show-initials"), \
|
||||
(_("Show tooltips in album view"), "show-album-view-tooltips"), \
|
||||
(_("Use 'Album Artist' tag"), "use-album-artist"), \
|
||||
(_("Send notification on title change"), "send-notify"), \
|
||||
(_("Stop playback on quit"), "stop-on-quit"), \
|
||||
(_("Play selected albums and titles immediately"), "force-mode")]
|
||||
check_buttons_data=[
|
||||
(_("Use Client-side decoration"), "use-csd"),
|
||||
(_("Show stop button"), "show-stop"),
|
||||
(_("Show lyrics button"), "show-lyrics-button"),
|
||||
(_("Show initials in artist view"), "show-initials"),
|
||||
(_("Show tooltips in album view"), "show-album-view-tooltips"),
|
||||
(_("Use 'Album Artist' tag"), "use-album-artist"),
|
||||
(_("Send notification on title change"), "send-notify"),
|
||||
(_("Stop playback on quit"), "stop-on-quit"),
|
||||
(_("Play selected albums and titles immediately"), "force-mode")
|
||||
]
|
||||
|
||||
for data in check_buttons_data:
|
||||
check_buttons[data[1]]=Gtk.CheckButton(label=data[0])
|
||||
check_buttons[data[1]].set_active(self._settings.get_boolean(data[1]))
|
||||
check_buttons[data[1]].set_margin_start(12)
|
||||
check_buttons[data[1]].connect("toggled", self._on_toggled, data[1])
|
||||
self._settings_handlers.append(self._settings.connect("changed::"+data[1], self._on_check_settings_changed, check_buttons[data[1]]))
|
||||
for label, key in check_buttons_data:
|
||||
check_buttons[key]=Gtk.CheckButton(label=label)
|
||||
check_buttons[key].set_active(self._settings.get_boolean(key))
|
||||
check_buttons[key].set_margin_start(12)
|
||||
check_buttons[key].connect("toggled", self._on_toggled, key)
|
||||
self._settings_handlers.append(
|
||||
self._settings.connect("changed::"+key, self._on_check_settings_changed, check_buttons[key])
|
||||
)
|
||||
|
||||
# headings
|
||||
view_heading=Gtk.Label(label=_("<b>View</b>"), use_markup=True, xalign=0)
|
||||
@@ -2431,7 +2555,11 @@ class GeneralSettings(Gtk.Box):
|
||||
behavior_grid=Gtk.Grid(row_spacing=6, column_spacing=12)
|
||||
behavior_grid.set_margin_start(12)
|
||||
behavior_grid.add(combo_settings["sort-albums-by-year"][0])
|
||||
behavior_grid.attach_next_to(combo_settings["sort-albums-by-year"][1], combo_settings["sort-albums-by-year"][0], Gtk.PositionType.RIGHT, 1, 1)
|
||||
behavior_grid.attach_next_to(
|
||||
combo_settings["sort-albums-by-year"][1],
|
||||
combo_settings["sort-albums-by-year"][0],
|
||||
Gtk.PositionType.RIGHT, 1, 1
|
||||
)
|
||||
|
||||
# connect
|
||||
self.connect("destroy", self._remove_handlers)
|
||||
@@ -2484,22 +2612,25 @@ class GeneralSettings(Gtk.Box):
|
||||
self._settings.set_boolean(key, widget.get_active())
|
||||
|
||||
class ProfileSettings(Gtk.Grid):
|
||||
def __init__(self, parent, settings):
|
||||
def __init__(self, parent, client, settings):
|
||||
super().__init__(row_spacing=6, column_spacing=12, border_width=18)
|
||||
|
||||
# adding vars
|
||||
self._client=client
|
||||
self._settings=settings
|
||||
self._gui_modification=False # indicates whether the settings were changed from the settings dialog
|
||||
|
||||
# widgets
|
||||
self._profiles_combo=Gtk.ComboBoxText(entry_text_column=0, hexpand=True)
|
||||
|
||||
add_button=Gtk.Button(label=None, image=Gtk.Image(stock=Gtk.STOCK_ADD))
|
||||
delete_button=Gtk.Button(label=None, image=Gtk.Image(stock=Gtk.STOCK_DELETE))
|
||||
add_button=Gtk.Button(image=Gtk.Image.new_from_icon_name("list-add", Gtk.IconSize.BUTTON))
|
||||
delete_button=Gtk.Button(image=Gtk.Image.new_from_icon_name("list-remove", Gtk.IconSize.BUTTON))
|
||||
add_delete_buttons=Gtk.ButtonBox(layout_style=Gtk.ButtonBoxStyle.EXPAND)
|
||||
add_delete_buttons.pack_start(add_button, True, True, 0)
|
||||
add_delete_buttons.pack_start(delete_button, True, True, 0)
|
||||
|
||||
connect_button=Gtk.Button(label=_("Connect"), image=Gtk.Image.new_from_icon_name("system-run", Gtk.IconSize.BUTTON))
|
||||
|
||||
self._profile_entry=Gtk.Entry(hexpand=True)
|
||||
self._host_entry=Gtk.Entry(hexpand=True)
|
||||
self._port_entry=Gtk.SpinButton.new_with_range(0, 65535, 1)
|
||||
@@ -2508,12 +2639,16 @@ class ProfileSettings(Gtk.Grid):
|
||||
address_entry.pack_start(self._port_entry, False, False, 0)
|
||||
self._password_entry=Gtk.Entry(hexpand=True, visibility=False)
|
||||
self._path_entry=Gtk.Entry(hexpand=True)
|
||||
self._path_select_button=Gtk.Button(image=Gtk.Image(stock=Gtk.STOCK_OPEN))
|
||||
self._path_select_button=Gtk.Button(image=Gtk.Image.new_from_icon_name("folder-open", Gtk.IconSize.BUTTON))
|
||||
path_box=Gtk.Box(spacing=6)
|
||||
path_box.pack_start(self._path_entry, True, True, 0)
|
||||
path_box.pack_start(self._path_select_button, False, False, 0)
|
||||
self._regex_entry=Gtk.Entry(hexpand=True, placeholder_text=COVER_REGEX)
|
||||
self._regex_entry.set_tooltip_text(_("The first image in the same directory as the song file matching this regex will be displayed. %AlbumArtist% and %Album% will be replaced by the corresponding tags of the song."))
|
||||
self._regex_entry.set_tooltip_text(
|
||||
_("The first image in the same directory as the song file "\
|
||||
"matching this regex will be displayed. %AlbumArtist% and "\
|
||||
"%Album% will be replaced by the corresponding tags of the song.")
|
||||
)
|
||||
|
||||
profiles_label=Gtk.Label(label=_("Profile:"), xalign=1)
|
||||
profile_label=Gtk.Label(label=_("Name:"), xalign=1)
|
||||
@@ -2525,6 +2660,7 @@ class ProfileSettings(Gtk.Grid):
|
||||
# connect
|
||||
add_button.connect("clicked", self._on_add_button_clicked)
|
||||
delete_button.connect("clicked", self._on_delete_button_clicked)
|
||||
connect_button.connect("clicked", self._on_connect_button_clicked)
|
||||
self._path_select_button.connect("clicked", self._on_path_select_button_clicked, parent)
|
||||
self._profiles_combo.connect("changed", self._on_profiles_changed)
|
||||
self.entry_changed_handlers=[]
|
||||
@@ -2560,6 +2696,8 @@ class ProfileSettings(Gtk.Grid):
|
||||
self.attach_next_to(self._password_entry, password_label, Gtk.PositionType.RIGHT, 2, 1)
|
||||
self.attach_next_to(path_box, path_label, Gtk.PositionType.RIGHT, 2, 1)
|
||||
self.attach_next_to(self._regex_entry, regex_label, Gtk.PositionType.RIGHT, 2, 1)
|
||||
connect_button.set_margin_top(12)
|
||||
self.attach_next_to(connect_button, self._regex_entry, Gtk.PositionType.BOTTOM, 2, 1)
|
||||
|
||||
def _block_entry_changed_handlers(self, *args):
|
||||
for obj, handler in self.entry_changed_handlers:
|
||||
@@ -2616,6 +2754,10 @@ class ProfileSettings(Gtk.Grid):
|
||||
new_pos=max(pos-1,0)
|
||||
self._profiles_combo.set_active(new_pos)
|
||||
|
||||
def _on_connect_button_clicked(self, *args):
|
||||
self._settings.set_int("active-profile", self._profiles_combo.get_active())
|
||||
self._client.reconnect()
|
||||
|
||||
def _on_profile_entry_changed(self, *args):
|
||||
self._gui_modification=True
|
||||
pos=self._profiles_combo.get_active()
|
||||
@@ -2814,7 +2956,7 @@ class PlaylistSettings(Gtk.Box):
|
||||
self._store.handler_unblock(self._row_deleted)
|
||||
|
||||
class SettingsDialog(Gtk.Dialog):
|
||||
def __init__(self, parent, settings):
|
||||
def __init__(self, parent, client, settings):
|
||||
use_csd=settings.get_boolean("use-csd")
|
||||
if use_csd:
|
||||
super().__init__(title=_("Settings"), transient_for=parent, use_header_bar=True)
|
||||
@@ -2831,7 +2973,7 @@ class SettingsDialog(Gtk.Dialog):
|
||||
|
||||
# widgets
|
||||
general=GeneralSettings(settings)
|
||||
profiles=ProfileSettings(parent, settings)
|
||||
profiles=ProfileSettings(parent, client, settings)
|
||||
playlist=PlaylistSettings(settings)
|
||||
|
||||
# packing
|
||||
@@ -2860,8 +3002,11 @@ class PlaybackControl(Gtk.ButtonBox):
|
||||
|
||||
# widgets
|
||||
self._icons={}
|
||||
icons_data=["media-playback-start-symbolic", "media-playback-stop-symbolic", "media-playback-pause-symbolic", \
|
||||
"media-skip-backward-symbolic", "media-skip-forward-symbolic"]
|
||||
icons_data=[
|
||||
"media-playback-start-symbolic", "media-playback-stop-symbolic",
|
||||
"media-playback-pause-symbolic", "media-skip-backward-symbolic",
|
||||
"media-skip-forward-symbolic"
|
||||
]
|
||||
for data in icons_data:
|
||||
self._icons[data]=PixelSizedIcon(data, self._icon_size)
|
||||
|
||||
@@ -3013,6 +3158,7 @@ class SeekBar(Gtk.Box):
|
||||
|
||||
def _disable(self, *args):
|
||||
self.set_sensitive(False)
|
||||
self.scale.set_fill_level(0)
|
||||
self.scale.set_range(0, 0)
|
||||
self._elapsed.set_text("00:00")
|
||||
self._rest.set_text("-00:00")
|
||||
@@ -3254,7 +3400,7 @@ class AboutDialog(Gtk.AboutDialog):
|
||||
super().__init__(transient_for=window, modal=True)
|
||||
self.set_program_name("mpdevil")
|
||||
self.set_version(VERSION)
|
||||
self.set_comments(_("A small MPD client written in python"))
|
||||
self.set_comments(_("A simple music browser for MPD"))
|
||||
self.set_authors(["Martin Wagner"])
|
||||
self.set_website("https://github.com/SoongNoonien/mpdevil")
|
||||
self.set_copyright("\xa9 2020 Martin Wagner")
|
||||
@@ -3279,6 +3425,7 @@ class ProfileSelect(Gtk.ComboBoxText):
|
||||
self._settings.connect("changed::ports", self._refresh)
|
||||
self._settings.connect("changed::passwords", self._refresh)
|
||||
self._settings.connect("changed::paths", self._refresh)
|
||||
self._settings.connect("changed::active-profile", self._on_active_profile_changed)
|
||||
|
||||
self._refresh()
|
||||
|
||||
@@ -3294,6 +3441,57 @@ class ProfileSelect(Gtk.ComboBoxText):
|
||||
active=self.get_active()
|
||||
self._settings.set_int("active-profile", active)
|
||||
|
||||
def _on_active_profile_changed(self, *args):
|
||||
self.handler_block(self._changed)
|
||||
self.set_active(self._settings.get_int("active-profile"))
|
||||
self.handler_unblock(self._changed)
|
||||
|
||||
class ConnectionNotify(Gtk.Revealer):
|
||||
def __init__(self, client, settings):
|
||||
super().__init__(valign=Gtk.Align.START, halign=Gtk.Align.CENTER)
|
||||
|
||||
# adding vars
|
||||
self._client=client
|
||||
self._settings=settings
|
||||
|
||||
# widgets
|
||||
self._label=Gtk.Label(wrap=True)
|
||||
close_button=Gtk.Button(image=Gtk.Image.new_from_icon_name("window-close-symbolic", Gtk.IconSize.BUTTON))
|
||||
close_button.set_relief(Gtk.ReliefStyle.NONE)
|
||||
connect_button=Gtk.Button(label=_("Connect"))
|
||||
|
||||
# connect
|
||||
close_button.connect("clicked", self._on_close_button_clicked)
|
||||
connect_button.connect("clicked", self._on_connect_button_clicked)
|
||||
self._client.emitter.connect("connection_error", self._on_connection_error)
|
||||
self._client.emitter.connect("reconnected", self._on_reconnected)
|
||||
|
||||
# packing
|
||||
box=Gtk.Box(spacing=12)
|
||||
box.get_style_context().add_class("app-notification")
|
||||
box.pack_start(self._label, False, True, 6)
|
||||
box.pack_end(close_button, False, True, 0)
|
||||
box.pack_end(connect_button, False, True, 0)
|
||||
self.add(box)
|
||||
|
||||
def _on_connection_error(self, *args):
|
||||
active=self._settings.get_int("active-profile")
|
||||
profile=self._settings.get_value("profiles")[active]
|
||||
host=self._settings.get_value("hosts")[active]
|
||||
port=self._settings.get_value("ports")[active]
|
||||
string=_('Connection to "%(profile)s" (%(host)s:%(port)s) failed') % {"profile": profile, "host": host, "port": port}
|
||||
self._label.set_text(string)
|
||||
self.set_reveal_child(True)
|
||||
|
||||
def _on_reconnected(self, *args):
|
||||
self.set_reveal_child(False)
|
||||
|
||||
def _on_close_button_clicked(self, *args):
|
||||
self.set_reveal_child(False)
|
||||
|
||||
def _on_connect_button_clicked(self, *args):
|
||||
self._client.reconnect()
|
||||
|
||||
class MainWindow(Gtk.ApplicationWindow):
|
||||
def __init__(self, app, client, settings):
|
||||
super().__init__(title=("mpdevil"), icon_name="mpdevil", application=app)
|
||||
@@ -3310,8 +3508,7 @@ class MainWindow(Gtk.ApplicationWindow):
|
||||
self._icon_size=self._settings.get_int("icon-size")
|
||||
|
||||
# MPRIS
|
||||
DBusGMainLoop(set_as_default=True)
|
||||
self._dbus_service=MPRISInterface(self, self._client, self._settings)
|
||||
dbus_service=MPRISInterface(self, self._client, self._settings)
|
||||
|
||||
# actions
|
||||
save_action=Gio.SimpleAction.new("save", None)
|
||||
@@ -3322,9 +3519,9 @@ class MainWindow(Gtk.ApplicationWindow):
|
||||
settings_action.connect("activate", self._on_settings)
|
||||
self.add_action(settings_action)
|
||||
|
||||
stats_action=Gio.SimpleAction.new("stats", None)
|
||||
stats_action.connect("activate", self._on_stats)
|
||||
self.add_action(stats_action)
|
||||
self._stats_action=Gio.SimpleAction.new("stats", None)
|
||||
self._stats_action.connect("activate", self._on_stats)
|
||||
self.add_action(self._stats_action)
|
||||
|
||||
self._update_action=Gio.SimpleAction.new("update", None)
|
||||
self._update_action.connect("activate", self._on_update)
|
||||
@@ -3346,6 +3543,7 @@ class MainWindow(Gtk.ApplicationWindow):
|
||||
self._playback_control=PlaybackControl(self._client, self._settings)
|
||||
self._seek_bar=SeekBar(self._client)
|
||||
playback_options=PlaybackOptions(self._client, self._settings)
|
||||
connection_notify=ConnectionNotify(self._client, self._settings)
|
||||
|
||||
# menu
|
||||
subsection=Gio.Menu()
|
||||
@@ -3354,10 +3552,13 @@ class MainWindow(Gtk.ApplicationWindow):
|
||||
subsection.append(_("About"), "app.about")
|
||||
subsection.append(_("Quit"), "app.quit")
|
||||
|
||||
mpd_subsection=Gio.Menu()
|
||||
mpd_subsection.append(_("Update database"), "win.update")
|
||||
mpd_subsection.append(_("Server stats"), "win.stats")
|
||||
|
||||
menu=Gio.Menu()
|
||||
menu.append(_("Save window layout"), "win.save")
|
||||
menu.append(_("Update database"), "win.update")
|
||||
menu.append(_("Server stats"), "win.stats")
|
||||
menu.append_section(None, mpd_subsection)
|
||||
menu.append_section(None, subsection)
|
||||
|
||||
menu_button=Gtk.MenuButton(image=self._icons["open-menu-symbolic"], tooltip_text=_("Menu"))
|
||||
@@ -3393,6 +3594,9 @@ class MainWindow(Gtk.ApplicationWindow):
|
||||
vbox=Gtk.Box(orientation=Gtk.Orientation.VERTICAL)
|
||||
vbox.pack_start(self._paned2, True, True, 0)
|
||||
vbox.pack_start(action_bar, False, False, 0)
|
||||
overlay=Gtk.Overlay()
|
||||
overlay.add(vbox)
|
||||
overlay.add_overlay(connection_notify)
|
||||
|
||||
if self._use_csd:
|
||||
self._header_bar=Gtk.HeaderBar()
|
||||
@@ -3408,7 +3612,7 @@ class MainWindow(Gtk.ApplicationWindow):
|
||||
action_bar.pack_start(self._profile_select)
|
||||
action_bar.pack_start(menu_button)
|
||||
|
||||
self.add(vbox)
|
||||
self.add(overlay)
|
||||
|
||||
self.show_all()
|
||||
if self._settings.get_boolean("maximize"):
|
||||
@@ -3443,18 +3647,17 @@ class MainWindow(Gtk.ApplicationWindow):
|
||||
notify.show()
|
||||
|
||||
def _on_reconnected(self, *args):
|
||||
self._dbus_service.acquire_name()
|
||||
self._playback_control.set_sensitive(True)
|
||||
self._update_action.set_enabled(True)
|
||||
self._stats_action.set_enabled(True)
|
||||
|
||||
def _on_disconnected(self, *args):
|
||||
self._dbus_service.release_name()
|
||||
if self._use_csd:
|
||||
self.set_title("mpdevil")
|
||||
self._header_bar.set_subtitle(_("not connected"))
|
||||
else:
|
||||
self.set_title("mpdevil ("+_("not connected")+")")
|
||||
self.songid_playing=None
|
||||
if self._use_csd:
|
||||
self._header_bar.set_subtitle("")
|
||||
self._playback_control.set_sensitive(False)
|
||||
self._update_action.set_enabled(False)
|
||||
self._stats_action.set_enabled(False)
|
||||
|
||||
def _on_key_press_event(self, widget, event):
|
||||
ctrl = (event.state & Gdk.ModifierType.CONTROL_MASK)
|
||||
@@ -3507,17 +3710,15 @@ class MainWindow(Gtk.ApplicationWindow):
|
||||
self._settings.set_int("paned2", self._paned2.get_position())
|
||||
|
||||
def _on_settings(self, action, param):
|
||||
settings=SettingsDialog(self, self._settings)
|
||||
settings=SettingsDialog(self, self._client, self._settings)
|
||||
settings.run()
|
||||
settings.destroy()
|
||||
|
||||
def _on_stats(self, action, param):
|
||||
if self._client.connected():
|
||||
stats=ServerStats(self, self._client, self._settings)
|
||||
stats.destroy()
|
||||
|
||||
def _on_update(self, action, param):
|
||||
if self._client.connected():
|
||||
self._client.wrapped_call("update")
|
||||
|
||||
def _on_help(self, action, param):
|
||||
|
@@ -1,11 +1,11 @@
|
||||
[Desktop Entry]
|
||||
Version=1.0
|
||||
_Name=mpdevil
|
||||
_GenericName=MPD Client
|
||||
_Comment=A small MPD client written in python
|
||||
Name=mpdevil
|
||||
GenericName=MPD Client
|
||||
_Comment=A simple music browser for MPD
|
||||
Exec=mpdevil
|
||||
Icon=mpdevil
|
||||
Terminal=false
|
||||
Type=Application
|
||||
StartupNotify=true
|
||||
Categories=GTK;AudioVideo;Player;
|
||||
Categories=Audio;AudioVideo;Player;GTK
|
||||
|
||||
|
@@ -1,3 +1,4 @@
|
||||
[encoding: UTF-8]
|
||||
bin/mpdevil
|
||||
data/mpdevil.desktop.in
|
||||
|
||||
|
198
po/de.po
198
po/de.po
@@ -7,8 +7,8 @@ msgid ""
|
||||
msgstr ""
|
||||
"Project-Id-Version: \n"
|
||||
"Report-Msgid-Bugs-To: \n"
|
||||
"POT-Creation-Date: 2020-08-29 10:57+0200\n"
|
||||
"PO-Revision-Date: 2020-08-29 10:57+0200\n"
|
||||
"POT-Creation-Date: 2020-09-13 21:30+0200\n"
|
||||
"PO-Revision-Date: 2020-09-13 21:32+0200\n"
|
||||
"Last-Translator: \n"
|
||||
"Language-Team: \n"
|
||||
"Language: de\n"
|
||||
@@ -18,72 +18,72 @@ msgstr ""
|
||||
"X-Generator: Poedit 2.3.1\n"
|
||||
"Plural-Forms: nplurals=2; plural=(n != 1);\n"
|
||||
|
||||
#: mpdevil:515
|
||||
#: mpdevil:518
|
||||
msgid "MPD-Tag"
|
||||
msgstr "MPD-Tag"
|
||||
|
||||
#: mpdevil:519
|
||||
#: mpdevil:522
|
||||
msgid "Value"
|
||||
msgstr "Wert"
|
||||
|
||||
#: mpdevil:601
|
||||
#: mpdevil:605
|
||||
msgid "Unknown Title"
|
||||
msgstr "Unbekannter Titel"
|
||||
|
||||
#: mpdevil:601
|
||||
#: mpdevil:608
|
||||
msgid "Unknown Artist"
|
||||
msgstr "Unbekannter Interpret"
|
||||
|
||||
#: mpdevil:601
|
||||
#: mpdevil:609
|
||||
msgid "Unknown Album"
|
||||
msgstr "Unbekanntes Album"
|
||||
|
||||
#: mpdevil:906 mpdevil:1209 mpdevil:2084 mpdevil:2771
|
||||
#: mpdevil:936 mpdevil:1240 mpdevil:2141 mpdevil:2846
|
||||
msgid "No"
|
||||
msgstr "Nr."
|
||||
|
||||
#: mpdevil:911 mpdevil:1214 mpdevil:2086 mpdevil:2771
|
||||
#: mpdevil:941 mpdevil:1245 mpdevil:2143 mpdevil:2846
|
||||
msgid "Title"
|
||||
msgstr "Titel"
|
||||
|
||||
#: mpdevil:917 mpdevil:1393 mpdevil:2087 mpdevil:2771
|
||||
#: mpdevil:947 mpdevil:1422 mpdevil:2144 mpdevil:2846
|
||||
msgid "Artist"
|
||||
msgstr "Interpret"
|
||||
|
||||
#: mpdevil:923 mpdevil:2088 mpdevil:2771
|
||||
#: mpdevil:953 mpdevil:2145 mpdevil:2846
|
||||
msgid "Album"
|
||||
msgstr "Album"
|
||||
|
||||
#: mpdevil:929 mpdevil:1220 mpdevil:2089 mpdevil:2771
|
||||
#: mpdevil:959 mpdevil:1251 mpdevil:2146 mpdevil:2846
|
||||
msgid "Length"
|
||||
msgstr "Länge"
|
||||
|
||||
#: mpdevil:990
|
||||
#: mpdevil:1023
|
||||
#, python-format
|
||||
msgid "%i hits"
|
||||
msgstr "%i Treffer"
|
||||
|
||||
#: mpdevil:1092
|
||||
#: mpdevil:1124
|
||||
msgid "Append"
|
||||
msgstr "Anhängen"
|
||||
|
||||
#: mpdevil:1093
|
||||
#: mpdevil:1125
|
||||
msgid "Add all titles to playlist"
|
||||
msgstr "Alle Titel der Wiedergabeliste anhängen"
|
||||
|
||||
#: mpdevil:1094
|
||||
#: mpdevil:1126
|
||||
msgid "Play"
|
||||
msgstr "Abspielen"
|
||||
|
||||
#: mpdevil:1095
|
||||
#: mpdevil:1127
|
||||
msgid "Directly play all titles"
|
||||
msgstr "Alle Titel sofort abspielen"
|
||||
|
||||
#: mpdevil:1096
|
||||
#: mpdevil:1128
|
||||
msgid "Enqueue"
|
||||
msgstr "Einreihen"
|
||||
|
||||
#: mpdevil:1097
|
||||
#: mpdevil:1129
|
||||
msgid ""
|
||||
"Append all titles after the currently playing track and clear the playlist "
|
||||
"from all other songs"
|
||||
@@ -91,170 +91,174 @@ msgstr ""
|
||||
"Alle Titel hinter dem aktuellen Stück einreihen und die weitere "
|
||||
"Wiedergabeliste leeren"
|
||||
|
||||
#: mpdevil:1226
|
||||
#: mpdevil:1257
|
||||
msgid "Close"
|
||||
msgstr "Schließen"
|
||||
|
||||
#: mpdevil:1279
|
||||
#: mpdevil:1310
|
||||
msgid "all genres"
|
||||
msgstr "Alle Genres"
|
||||
|
||||
#: mpdevil:1391
|
||||
#: mpdevil:1420
|
||||
msgid "Album Artist"
|
||||
msgstr "Albuminterpret"
|
||||
|
||||
#: mpdevil:1394
|
||||
#: mpdevil:1423
|
||||
msgid "all artists"
|
||||
msgstr "Alle Interpreten"
|
||||
|
||||
#: mpdevil:1571
|
||||
#: mpdevil:1611
|
||||
#, python-format
|
||||
msgid "%(total_tracks)i titles on %(discs)i discs (%(total_length)s)"
|
||||
msgstr "%(total_tracks)i Titel auf %(discs)i CDs (%(total_length)s)"
|
||||
|
||||
#: mpdevil:1573 mpdevil:2180
|
||||
#: mpdevil:1614 mpdevil:2235
|
||||
#, python-format
|
||||
msgid "%(total_tracks)i titles (%(total_length)s)"
|
||||
msgstr "%(total_tracks)i Titel (%(total_length)s)"
|
||||
|
||||
#: mpdevil:1691
|
||||
#: mpdevil:1738
|
||||
msgid "Back to current album"
|
||||
msgstr "Zurück zu aktuellem Album"
|
||||
|
||||
#: mpdevil:1693
|
||||
#: mpdevil:1739
|
||||
msgid "Search"
|
||||
msgstr "Suche"
|
||||
|
||||
#: mpdevil:1853
|
||||
#: mpdevil:1899
|
||||
msgid "searching..."
|
||||
msgstr "suche..."
|
||||
|
||||
#: mpdevil:1857
|
||||
#: mpdevil:1903
|
||||
msgid "lyrics not found"
|
||||
msgstr "Liedtext nicht gefunden"
|
||||
|
||||
#: mpdevil:1927
|
||||
#: mpdevil:1977
|
||||
#, python-format
|
||||
msgid ""
|
||||
"%(bitrate)s kb/s, %(frequency)s kHz, %(resolution)i bit, %(channels)i "
|
||||
"%(bitrate)s kb/s, %(frequency)s kHz, %(resolution)s bit, %(channels)s "
|
||||
"channels, %(file_type)s"
|
||||
msgstr ""
|
||||
"%(bitrate)s kb/s, %(frequency)s kHz, %(resolution)i bit, %(channels)i "
|
||||
"%(bitrate)s kb/s, %(frequency)s kHz, %(resolution)s bit, %(channels)s "
|
||||
"Kanäle, %(file_type)s"
|
||||
|
||||
#: mpdevil:2055
|
||||
#: mpdevil:2110
|
||||
msgid "Scroll to current song"
|
||||
msgstr "Gehe zu aktuellem Lied"
|
||||
|
||||
#: mpdevil:2060
|
||||
#: mpdevil:2117
|
||||
msgid "Clear playlist"
|
||||
msgstr "Wiedergabeliste leeren"
|
||||
|
||||
#: mpdevil:2085 mpdevil:2771
|
||||
#: mpdevil:2142 mpdevil:2846
|
||||
msgid "Disc"
|
||||
msgstr "CD"
|
||||
|
||||
#: mpdevil:2090 mpdevil:2771
|
||||
#: mpdevil:2147 mpdevil:2846
|
||||
msgid "Year"
|
||||
msgstr "Jahr"
|
||||
|
||||
#: mpdevil:2091 mpdevil:2771
|
||||
#: mpdevil:2148 mpdevil:2846
|
||||
msgid "Genre"
|
||||
msgstr "Genre"
|
||||
|
||||
#: mpdevil:2311
|
||||
#: mpdevil:2387
|
||||
msgid "Show lyrics"
|
||||
msgstr "Zeige Liedtext"
|
||||
|
||||
#: mpdevil:2404
|
||||
#: mpdevil:2481
|
||||
msgid "Main cover size:"
|
||||
msgstr "Größe des Haupt-Covers:"
|
||||
|
||||
#: mpdevil:2405
|
||||
#: mpdevil:2482
|
||||
msgid "Album view cover size:"
|
||||
msgstr "Covergröße in Albumliste:"
|
||||
|
||||
#: mpdevil:2406
|
||||
#: mpdevil:2483
|
||||
msgid "Action bar icon size:"
|
||||
msgstr "Symbolgröße Aktionsleiste:"
|
||||
|
||||
#: mpdevil:2407
|
||||
#: mpdevil:2484
|
||||
msgid "Secondary icon size:"
|
||||
msgstr "Sekundäre Symbolgröße:"
|
||||
|
||||
#: mpdevil:2418
|
||||
#: mpdevil:2497
|
||||
msgid "Sort albums by:"
|
||||
msgstr "Sortiere Alben nach:"
|
||||
|
||||
#: mpdevil:2418
|
||||
#: mpdevil:2497
|
||||
msgid "name"
|
||||
msgstr "Name"
|
||||
|
||||
#: mpdevil:2418
|
||||
#: mpdevil:2497
|
||||
msgid "year"
|
||||
msgstr "Jahr"
|
||||
|
||||
#: mpdevil:2419
|
||||
#: mpdevil:2498
|
||||
msgid "Position of playlist:"
|
||||
msgstr "Wiedergabelistenposition:"
|
||||
|
||||
#: mpdevil:2419
|
||||
#: mpdevil:2498
|
||||
msgid "bottom"
|
||||
msgstr "unten"
|
||||
|
||||
#: mpdevil:2419
|
||||
#: mpdevil:2498
|
||||
msgid "right"
|
||||
msgstr "rechts"
|
||||
|
||||
#: mpdevil:2436
|
||||
#: mpdevil:2516
|
||||
msgid "Use Client-side decoration"
|
||||
msgstr "Benutze \"Client-side decoration\""
|
||||
|
||||
#: mpdevil:2437
|
||||
#: mpdevil:2517
|
||||
msgid "Show stop button"
|
||||
msgstr "Zeige Stopp-Knopf"
|
||||
|
||||
#: mpdevil:2438
|
||||
#: mpdevil:2518
|
||||
msgid "Show lyrics button"
|
||||
msgstr "Zeige Liedtext-Knopf"
|
||||
|
||||
#: mpdevil:2439
|
||||
#: mpdevil:2519
|
||||
msgid "Show initials in artist view"
|
||||
msgstr "Zeige Anfangsbuchstaben in Interpretenliste"
|
||||
|
||||
#: mpdevil:2440
|
||||
#: mpdevil:2520
|
||||
msgid "Show tooltips in album view"
|
||||
msgstr "Zeige Tooltips in Albumliste"
|
||||
|
||||
#: mpdevil:2441
|
||||
#: mpdevil:2521
|
||||
msgid "Use 'Album Artist' tag"
|
||||
msgstr "Benutze \"Album Artist\" Tag"
|
||||
|
||||
#: mpdevil:2442
|
||||
#: mpdevil:2522
|
||||
msgid "Send notification on title change"
|
||||
msgstr "Sende Benachrichtigung bei Titelwechsel"
|
||||
|
||||
#: mpdevil:2443
|
||||
#: mpdevil:2523
|
||||
msgid "Stop playback on quit"
|
||||
msgstr "Wiedergabe beim Beenden stoppen"
|
||||
|
||||
#: mpdevil:2444
|
||||
#: mpdevil:2524
|
||||
msgid "Play selected albums and titles immediately"
|
||||
msgstr "Ausgewählte Alben und Titel sofort abspielen"
|
||||
|
||||
#: mpdevil:2455
|
||||
#: mpdevil:2537
|
||||
msgid "<b>View</b>"
|
||||
msgstr "<b>Ansicht</b>"
|
||||
|
||||
#: mpdevil:2458
|
||||
#: mpdevil:2538
|
||||
msgid "<b>Behavior</b>"
|
||||
msgstr "<b>Verhalten</b>"
|
||||
|
||||
#: mpdevil:2491
|
||||
#: mpdevil:2570
|
||||
msgid "(restart required)"
|
||||
msgstr "(Neustart erforderlich)"
|
||||
|
||||
#: mpdevil:2572
|
||||
#: mpdevil:2632 mpdevil:3461
|
||||
msgid "Connect"
|
||||
msgstr "Verbinden"
|
||||
|
||||
#: mpdevil:2648
|
||||
msgid ""
|
||||
"The first image in the same directory as the song file matching this regex "
|
||||
"will be displayed. %AlbumArtist% and %Album% will be replaced by the "
|
||||
@@ -264,115 +268,119 @@ msgstr ""
|
||||
"regulären Ausdruck entspricht, wird angezeigt. %AlbumArtist% und %Album% "
|
||||
"werden durch die entsprechenden Tags des Liedes ersetzt."
|
||||
|
||||
#: mpdevil:2574
|
||||
#: mpdevil:2653
|
||||
msgid "Profile:"
|
||||
msgstr "Profil:"
|
||||
|
||||
#: mpdevil:2576
|
||||
#: mpdevil:2654
|
||||
msgid "Name:"
|
||||
msgstr "Name:"
|
||||
|
||||
#: mpdevil:2578
|
||||
#: mpdevil:2655
|
||||
msgid "Host:"
|
||||
msgstr "Host:"
|
||||
|
||||
#: mpdevil:2580
|
||||
#: mpdevil:2656
|
||||
msgid "Password:"
|
||||
msgstr "Passwort:"
|
||||
|
||||
#: mpdevil:2582
|
||||
#: mpdevil:2657
|
||||
msgid "Music lib:"
|
||||
msgstr "Musikverzeichnis:"
|
||||
|
||||
#: mpdevil:2584
|
||||
#: mpdevil:2658
|
||||
msgid "Cover regex:"
|
||||
msgstr "Cover-Regex:"
|
||||
|
||||
#: mpdevil:2709
|
||||
#: mpdevil:2789
|
||||
msgid "Choose directory"
|
||||
msgstr "Verzeichnis Wählen"
|
||||
|
||||
#: mpdevil:2743
|
||||
#: mpdevil:2822
|
||||
msgid "Choose the order of information to appear in the playlist:"
|
||||
msgstr ""
|
||||
"Lege die Reihenfolge fest, in der Informationen in der Wiedergabeliste "
|
||||
"angezeigt werden sollen:"
|
||||
|
||||
#: mpdevil:2887 mpdevil:2895 mpdevil:3434
|
||||
#: mpdevil:2962 mpdevil:2970 mpdevil:3550
|
||||
msgid "Settings"
|
||||
msgstr "Einstellungen"
|
||||
|
||||
#: mpdevil:2906
|
||||
#: mpdevil:2981
|
||||
msgid "General"
|
||||
msgstr "Allgemein"
|
||||
|
||||
#: mpdevil:2907
|
||||
#: mpdevil:2982
|
||||
msgid "Profiles"
|
||||
msgstr "Profile"
|
||||
|
||||
#: mpdevil:2908
|
||||
#: mpdevil:2983
|
||||
msgid "Playlist"
|
||||
msgstr "Wiedergabeliste"
|
||||
|
||||
#: mpdevil:3168
|
||||
#: mpdevil:3242
|
||||
msgid "Random mode"
|
||||
msgstr "Zufallsmodus"
|
||||
|
||||
#: mpdevil:3170
|
||||
#: mpdevil:3243
|
||||
msgid "Repeat mode"
|
||||
msgstr "Dauerschleife"
|
||||
|
||||
#: mpdevil:3172
|
||||
#: mpdevil:3244
|
||||
msgid "Single mode"
|
||||
msgstr "Einzelstückmodus"
|
||||
|
||||
#: mpdevil:3174
|
||||
#: mpdevil:3245
|
||||
msgid "Consume mode"
|
||||
msgstr "Wiedergabeliste verbrauchen"
|
||||
|
||||
#: mpdevil:3278 mpdevil:3286
|
||||
#: mpdevil:3346 mpdevil:3354
|
||||
msgid "Stats"
|
||||
msgstr "Statistik"
|
||||
|
||||
#: mpdevil:3337
|
||||
msgid "A small MPD client written in python"
|
||||
msgstr ""
|
||||
#: mpdevil:3403
|
||||
msgid "A simple music browser for MPD"
|
||||
msgstr "Ein einfacher Musikbrowser für MPD"
|
||||
|
||||
#: mpdevil:3427
|
||||
#: mpdevil:3415
|
||||
msgid "Select profile"
|
||||
msgstr "Profil auswählen"
|
||||
|
||||
#: mpdevil:3435
|
||||
#: mpdevil:3482
|
||||
#, python-format
|
||||
msgid "Connection to \"%(profile)s\" (%(host)s:%(port)s) failed"
|
||||
msgstr "Verbindung zu \"%(profile)s\" (%(host)s:%(port)s) fehlgeschlagen"
|
||||
|
||||
#: mpdevil:3551
|
||||
msgid "Help"
|
||||
msgstr "Hilfe"
|
||||
|
||||
#: mpdevil:3436
|
||||
#: mpdevil:3552
|
||||
msgid "About"
|
||||
msgstr "Über"
|
||||
|
||||
#: mpdevil:3437
|
||||
#: mpdevil:3553
|
||||
msgid "Quit"
|
||||
msgstr "Beenden"
|
||||
|
||||
#: mpdevil:3440
|
||||
msgid "Save window layout"
|
||||
msgstr "Fensterlayout speichern"
|
||||
|
||||
#: mpdevil:3441
|
||||
#: mpdevil:3556
|
||||
msgid "Update database"
|
||||
msgstr "Datenbank aktualisieren"
|
||||
|
||||
#: mpdevil:3442
|
||||
#: mpdevil:3557
|
||||
msgid "Server stats"
|
||||
msgstr "Serverstatistik"
|
||||
|
||||
#: mpdevil:3448
|
||||
#: mpdevil:3560
|
||||
msgid "Save window layout"
|
||||
msgstr "Fensterlayout speichern"
|
||||
|
||||
#: mpdevil:3564
|
||||
msgid "Menu"
|
||||
msgstr "Menü"
|
||||
|
||||
#: mpdevil:3537 mpdevil:3539
|
||||
msgid "not connected"
|
||||
msgstr "nicht verbunden"
|
||||
#~ msgid "not connected"
|
||||
#~ msgstr "nicht verbunden"
|
||||
|
||||
#, python-format
|
||||
#~ msgid "hits: %i"
|
||||
|
189
po/mpdevil.pot
189
po/mpdevil.pot
@@ -8,7 +8,7 @@ msgid ""
|
||||
msgstr ""
|
||||
"Project-Id-Version: PACKAGE VERSION\n"
|
||||
"Report-Msgid-Bugs-To: \n"
|
||||
"POT-Creation-Date: 2020-08-29 10:57+0200\n"
|
||||
"POT-Creation-Date: 2020-09-13 21:30+0200\n"
|
||||
"PO-Revision-Date: YEAR-MO-DA HO:MI+ZONE\n"
|
||||
"Last-Translator: FULL NAME <EMAIL@ADDRESS>\n"
|
||||
"Language-Team: LANGUAGE <LL@li.org>\n"
|
||||
@@ -17,349 +17,354 @@ msgstr ""
|
||||
"Content-Type: text/plain; charset=CHARSET\n"
|
||||
"Content-Transfer-Encoding: 8bit\n"
|
||||
|
||||
#: mpdevil:515
|
||||
#: mpdevil:518
|
||||
msgid "MPD-Tag"
|
||||
msgstr ""
|
||||
|
||||
#: mpdevil:519
|
||||
#: mpdevil:522
|
||||
msgid "Value"
|
||||
msgstr ""
|
||||
|
||||
#: mpdevil:601
|
||||
#: mpdevil:605
|
||||
msgid "Unknown Title"
|
||||
msgstr ""
|
||||
|
||||
#: mpdevil:601
|
||||
#: mpdevil:608
|
||||
msgid "Unknown Artist"
|
||||
msgstr ""
|
||||
|
||||
#: mpdevil:601
|
||||
#: mpdevil:609
|
||||
msgid "Unknown Album"
|
||||
msgstr ""
|
||||
|
||||
#: mpdevil:906 mpdevil:1209 mpdevil:2084 mpdevil:2771
|
||||
#: mpdevil:936 mpdevil:1240 mpdevil:2141 mpdevil:2846
|
||||
msgid "No"
|
||||
msgstr ""
|
||||
|
||||
#: mpdevil:911 mpdevil:1214 mpdevil:2086 mpdevil:2771
|
||||
#: mpdevil:941 mpdevil:1245 mpdevil:2143 mpdevil:2846
|
||||
msgid "Title"
|
||||
msgstr ""
|
||||
|
||||
#: mpdevil:917 mpdevil:1393 mpdevil:2087 mpdevil:2771
|
||||
#: mpdevil:947 mpdevil:1422 mpdevil:2144 mpdevil:2846
|
||||
msgid "Artist"
|
||||
msgstr ""
|
||||
|
||||
#: mpdevil:923 mpdevil:2088 mpdevil:2771
|
||||
#: mpdevil:953 mpdevil:2145 mpdevil:2846
|
||||
msgid "Album"
|
||||
msgstr ""
|
||||
|
||||
#: mpdevil:929 mpdevil:1220 mpdevil:2089 mpdevil:2771
|
||||
#: mpdevil:959 mpdevil:1251 mpdevil:2146 mpdevil:2846
|
||||
msgid "Length"
|
||||
msgstr ""
|
||||
|
||||
#: mpdevil:990
|
||||
#: mpdevil:1023
|
||||
#, python-format
|
||||
msgid "%i hits"
|
||||
msgstr ""
|
||||
|
||||
#: mpdevil:1092
|
||||
#: mpdevil:1124
|
||||
msgid "Append"
|
||||
msgstr ""
|
||||
|
||||
#: mpdevil:1093
|
||||
#: mpdevil:1125
|
||||
msgid "Add all titles to playlist"
|
||||
msgstr ""
|
||||
|
||||
#: mpdevil:1094
|
||||
#: mpdevil:1126
|
||||
msgid "Play"
|
||||
msgstr ""
|
||||
|
||||
#: mpdevil:1095
|
||||
#: mpdevil:1127
|
||||
msgid "Directly play all titles"
|
||||
msgstr ""
|
||||
|
||||
#: mpdevil:1096
|
||||
#: mpdevil:1128
|
||||
msgid "Enqueue"
|
||||
msgstr ""
|
||||
|
||||
#: mpdevil:1097
|
||||
#: mpdevil:1129
|
||||
msgid ""
|
||||
"Append all titles after the currently playing track and clear the playlist "
|
||||
"from all other songs"
|
||||
msgstr ""
|
||||
|
||||
#: mpdevil:1226
|
||||
#: mpdevil:1257
|
||||
msgid "Close"
|
||||
msgstr ""
|
||||
|
||||
#: mpdevil:1279
|
||||
#: mpdevil:1310
|
||||
msgid "all genres"
|
||||
msgstr ""
|
||||
|
||||
#: mpdevil:1391
|
||||
#: mpdevil:1420
|
||||
msgid "Album Artist"
|
||||
msgstr ""
|
||||
|
||||
#: mpdevil:1394
|
||||
#: mpdevil:1423
|
||||
msgid "all artists"
|
||||
msgstr ""
|
||||
|
||||
#: mpdevil:1571
|
||||
#: mpdevil:1611
|
||||
#, python-format
|
||||
msgid "%(total_tracks)i titles on %(discs)i discs (%(total_length)s)"
|
||||
msgstr ""
|
||||
|
||||
#: mpdevil:1573 mpdevil:2180
|
||||
#: mpdevil:1614 mpdevil:2235
|
||||
#, python-format
|
||||
msgid "%(total_tracks)i titles (%(total_length)s)"
|
||||
msgstr ""
|
||||
|
||||
#: mpdevil:1691
|
||||
#: mpdevil:1738
|
||||
msgid "Back to current album"
|
||||
msgstr ""
|
||||
|
||||
#: mpdevil:1693
|
||||
#: mpdevil:1739
|
||||
msgid "Search"
|
||||
msgstr ""
|
||||
|
||||
#: mpdevil:1853
|
||||
#: mpdevil:1899
|
||||
msgid "searching..."
|
||||
msgstr ""
|
||||
|
||||
#: mpdevil:1857
|
||||
#: mpdevil:1903
|
||||
msgid "lyrics not found"
|
||||
msgstr ""
|
||||
|
||||
#: mpdevil:1927
|
||||
#: mpdevil:1977
|
||||
#, python-format
|
||||
msgid ""
|
||||
"%(bitrate)s kb/s, %(frequency)s kHz, %(resolution)i bit, %(channels)i "
|
||||
"%(bitrate)s kb/s, %(frequency)s kHz, %(resolution)s bit, %(channels)s "
|
||||
"channels, %(file_type)s"
|
||||
msgstr ""
|
||||
|
||||
#: mpdevil:2055
|
||||
#: mpdevil:2110
|
||||
msgid "Scroll to current song"
|
||||
msgstr ""
|
||||
|
||||
#: mpdevil:2060
|
||||
#: mpdevil:2117
|
||||
msgid "Clear playlist"
|
||||
msgstr ""
|
||||
|
||||
#: mpdevil:2085 mpdevil:2771
|
||||
#: mpdevil:2142 mpdevil:2846
|
||||
msgid "Disc"
|
||||
msgstr ""
|
||||
|
||||
#: mpdevil:2090 mpdevil:2771
|
||||
#: mpdevil:2147 mpdevil:2846
|
||||
msgid "Year"
|
||||
msgstr ""
|
||||
|
||||
#: mpdevil:2091 mpdevil:2771
|
||||
#: mpdevil:2148 mpdevil:2846
|
||||
msgid "Genre"
|
||||
msgstr ""
|
||||
|
||||
#: mpdevil:2311
|
||||
#: mpdevil:2387
|
||||
msgid "Show lyrics"
|
||||
msgstr ""
|
||||
|
||||
#: mpdevil:2404
|
||||
#: mpdevil:2481
|
||||
msgid "Main cover size:"
|
||||
msgstr ""
|
||||
|
||||
#: mpdevil:2405
|
||||
#: mpdevil:2482
|
||||
msgid "Album view cover size:"
|
||||
msgstr ""
|
||||
|
||||
#: mpdevil:2406
|
||||
#: mpdevil:2483
|
||||
msgid "Action bar icon size:"
|
||||
msgstr ""
|
||||
|
||||
#: mpdevil:2407
|
||||
#: mpdevil:2484
|
||||
msgid "Secondary icon size:"
|
||||
msgstr ""
|
||||
|
||||
#: mpdevil:2418
|
||||
#: mpdevil:2497
|
||||
msgid "Sort albums by:"
|
||||
msgstr ""
|
||||
|
||||
#: mpdevil:2418
|
||||
#: mpdevil:2497
|
||||
msgid "name"
|
||||
msgstr ""
|
||||
|
||||
#: mpdevil:2418
|
||||
#: mpdevil:2497
|
||||
msgid "year"
|
||||
msgstr ""
|
||||
|
||||
#: mpdevil:2419
|
||||
#: mpdevil:2498
|
||||
msgid "Position of playlist:"
|
||||
msgstr ""
|
||||
|
||||
#: mpdevil:2419
|
||||
#: mpdevil:2498
|
||||
msgid "bottom"
|
||||
msgstr ""
|
||||
|
||||
#: mpdevil:2419
|
||||
#: mpdevil:2498
|
||||
msgid "right"
|
||||
msgstr ""
|
||||
|
||||
#: mpdevil:2436
|
||||
#: mpdevil:2516
|
||||
msgid "Use Client-side decoration"
|
||||
msgstr ""
|
||||
|
||||
#: mpdevil:2437
|
||||
#: mpdevil:2517
|
||||
msgid "Show stop button"
|
||||
msgstr ""
|
||||
|
||||
#: mpdevil:2438
|
||||
#: mpdevil:2518
|
||||
msgid "Show lyrics button"
|
||||
msgstr ""
|
||||
|
||||
#: mpdevil:2439
|
||||
#: mpdevil:2519
|
||||
msgid "Show initials in artist view"
|
||||
msgstr ""
|
||||
|
||||
#: mpdevil:2440
|
||||
#: mpdevil:2520
|
||||
msgid "Show tooltips in album view"
|
||||
msgstr ""
|
||||
|
||||
#: mpdevil:2441
|
||||
#: mpdevil:2521
|
||||
msgid "Use 'Album Artist' tag"
|
||||
msgstr ""
|
||||
|
||||
#: mpdevil:2442
|
||||
#: mpdevil:2522
|
||||
msgid "Send notification on title change"
|
||||
msgstr ""
|
||||
|
||||
#: mpdevil:2443
|
||||
#: mpdevil:2523
|
||||
msgid "Stop playback on quit"
|
||||
msgstr ""
|
||||
|
||||
#: mpdevil:2444
|
||||
#: mpdevil:2524
|
||||
msgid "Play selected albums and titles immediately"
|
||||
msgstr ""
|
||||
|
||||
#: mpdevil:2455
|
||||
#: mpdevil:2537
|
||||
msgid "<b>View</b>"
|
||||
msgstr ""
|
||||
|
||||
#: mpdevil:2458
|
||||
#: mpdevil:2538
|
||||
msgid "<b>Behavior</b>"
|
||||
msgstr ""
|
||||
|
||||
#: mpdevil:2491
|
||||
#: mpdevil:2570
|
||||
msgid "(restart required)"
|
||||
msgstr ""
|
||||
|
||||
#: mpdevil:2572
|
||||
#: mpdevil:2632 mpdevil:3461
|
||||
msgid "Connect"
|
||||
msgstr ""
|
||||
|
||||
#: mpdevil:2648
|
||||
msgid ""
|
||||
"The first image in the same directory as the song file matching this regex "
|
||||
"will be displayed. %AlbumArtist% and %Album% will be replaced by the "
|
||||
"corresponding tags of the song."
|
||||
msgstr ""
|
||||
|
||||
#: mpdevil:2574
|
||||
#: mpdevil:2653
|
||||
msgid "Profile:"
|
||||
msgstr ""
|
||||
|
||||
#: mpdevil:2576
|
||||
#: mpdevil:2654
|
||||
msgid "Name:"
|
||||
msgstr ""
|
||||
|
||||
#: mpdevil:2578
|
||||
#: mpdevil:2655
|
||||
msgid "Host:"
|
||||
msgstr ""
|
||||
|
||||
#: mpdevil:2580
|
||||
#: mpdevil:2656
|
||||
msgid "Password:"
|
||||
msgstr ""
|
||||
|
||||
#: mpdevil:2582
|
||||
#: mpdevil:2657
|
||||
msgid "Music lib:"
|
||||
msgstr ""
|
||||
|
||||
#: mpdevil:2584
|
||||
#: mpdevil:2658
|
||||
msgid "Cover regex:"
|
||||
msgstr ""
|
||||
|
||||
#: mpdevil:2709
|
||||
#: mpdevil:2789
|
||||
msgid "Choose directory"
|
||||
msgstr ""
|
||||
|
||||
#: mpdevil:2743
|
||||
#: mpdevil:2822
|
||||
msgid "Choose the order of information to appear in the playlist:"
|
||||
msgstr ""
|
||||
|
||||
#: mpdevil:2887 mpdevil:2895 mpdevil:3434
|
||||
#: mpdevil:2962 mpdevil:2970 mpdevil:3550
|
||||
msgid "Settings"
|
||||
msgstr ""
|
||||
|
||||
#: mpdevil:2906
|
||||
#: mpdevil:2981
|
||||
msgid "General"
|
||||
msgstr ""
|
||||
|
||||
#: mpdevil:2907
|
||||
#: mpdevil:2982
|
||||
msgid "Profiles"
|
||||
msgstr ""
|
||||
|
||||
#: mpdevil:2908
|
||||
#: mpdevil:2983
|
||||
msgid "Playlist"
|
||||
msgstr ""
|
||||
|
||||
#: mpdevil:3168
|
||||
#: mpdevil:3242
|
||||
msgid "Random mode"
|
||||
msgstr ""
|
||||
|
||||
#: mpdevil:3170
|
||||
#: mpdevil:3243
|
||||
msgid "Repeat mode"
|
||||
msgstr ""
|
||||
|
||||
#: mpdevil:3172
|
||||
#: mpdevil:3244
|
||||
msgid "Single mode"
|
||||
msgstr ""
|
||||
|
||||
#: mpdevil:3174
|
||||
#: mpdevil:3245
|
||||
msgid "Consume mode"
|
||||
msgstr ""
|
||||
|
||||
#: mpdevil:3278 mpdevil:3286
|
||||
#: mpdevil:3346 mpdevil:3354
|
||||
msgid "Stats"
|
||||
msgstr ""
|
||||
|
||||
#: mpdevil:3337
|
||||
msgid "A small MPD client written in python"
|
||||
#: mpdevil:3403
|
||||
msgid "A simple music browser for MPD"
|
||||
msgstr ""
|
||||
|
||||
#: mpdevil:3427
|
||||
#: mpdevil:3415
|
||||
msgid "Select profile"
|
||||
msgstr ""
|
||||
|
||||
#: mpdevil:3435
|
||||
#: mpdevil:3482
|
||||
#, python-format
|
||||
msgid "Connection to \"%(profile)s\" (%(host)s:%(port)s) failed"
|
||||
msgstr ""
|
||||
|
||||
#: mpdevil:3551
|
||||
msgid "Help"
|
||||
msgstr ""
|
||||
|
||||
#: mpdevil:3436
|
||||
#: mpdevil:3552
|
||||
msgid "About"
|
||||
msgstr ""
|
||||
|
||||
#: mpdevil:3437
|
||||
#: mpdevil:3553
|
||||
msgid "Quit"
|
||||
msgstr ""
|
||||
|
||||
#: mpdevil:3440
|
||||
msgid "Save window layout"
|
||||
msgstr ""
|
||||
|
||||
#: mpdevil:3441
|
||||
#: mpdevil:3556
|
||||
msgid "Update database"
|
||||
msgstr ""
|
||||
|
||||
#: mpdevil:3442
|
||||
#: mpdevil:3557
|
||||
msgid "Server stats"
|
||||
msgstr ""
|
||||
|
||||
#: mpdevil:3448
|
||||
msgid "Menu"
|
||||
#: mpdevil:3560
|
||||
msgid "Save window layout"
|
||||
msgstr ""
|
||||
|
||||
#: mpdevil:3537 mpdevil:3539
|
||||
msgid "not connected"
|
||||
#: mpdevil:3564
|
||||
msgid "Menu"
|
||||
msgstr ""
|
||||
|
4
setup.py
4
setup.py
@@ -4,10 +4,10 @@ import DistUtilsExtra.auto
|
||||
|
||||
DistUtilsExtra.auto.setup(
|
||||
name='mpdevil',
|
||||
version='0.9.0', # sync with bin/mpdevil
|
||||
version='0.9.1', # sync with bin/mpdevil
|
||||
author="Martin Wagner",
|
||||
author_email="martin.wagner.dev@gmail.com",
|
||||
description=('A small MPD client written in python'),
|
||||
description=('A simple music browser for MPD'),
|
||||
url="https://github.com/SoongNoonien/mpdevil",
|
||||
license='GPL-3.0',
|
||||
data_files=[
|
||||
|
Reference in New Issue
Block a user