14 Commits
v0.3 ... v0.4.0

Author SHA1 Message Date
Martin Wagner
89ffc03cb2 Update configure.ac 2020-01-17 22:43:33 +01:00
Martin Wagner
d04c84e5d0 readme update 2020-01-17 22:39:56 +01:00
Martin Wagner
6990d59f72 translation update 2020-01-17 22:35:30 +01:00
Martin Wagner
421f685b58 search dialog fix 2020-01-17 22:18:50 +01:00
Martin Wagner
6238df4d21 added new album dialog / tooltip fixes 2020-01-17 22:13:58 +01:00
Martin Wagner
b8d1f9aafc fixed unintended behavior on stopped state 2020-01-14 20:24:28 +01:00
Martin Wagner
3414212173 converted to symbolic icons 2020-01-14 17:18:49 +01:00
Martin Wagner
ab7c9c6bd6 fixed duration display error and small translation update 2020-01-12 16:27:23 +01:00
Martin Wagner
4c7f953c98 Update README.md 2020-01-12 15:32:02 +01:00
Martin Wagner
8ba986bb4d Update configure.ac
added dependency tests
2020-01-12 13:57:18 +01:00
Martin Wagner
0230544df4 Update README.md 2020-01-11 22:29:19 +01:00
Martin Wagner
0b08bd80bf updated READMEs 2020-01-11 15:09:10 +01:00
Martin Wagner
b786b55644 added screenshot 2020-01-11 14:29:37 +01:00
Martin Wagner
6f608d923b Update README.rst 2020-01-11 14:02:45 +01:00
8 changed files with 347 additions and 220 deletions

2
README
View File

@@ -1 +1 @@
README.rst
README.md

33
README.md Normal file
View File

@@ -0,0 +1,33 @@
README for mpdevil
==================
mpdevil is focused on playing your local music directly instead of managing playlists or playing network streams. So it neither supports saving playlists nor restoring them. Therefore mpdevil is mainly a music browser which aims to be easy to use. mpdevil dosen't store any client side database of your music library. Instead all tags and covers get presented to you in real time. So you'll never see any outdated information in your browser. mpdevil strongly relies on tags especially on the AlbumArtist tag.
![ScreenShot](screenshots/mainwindow.png)
Features
--------
1. playing songs without doubleclicking
2. displaying covers
3. fetching lyrics form the web (based on PyLyrics 1.1.0)
4. searching songs in your music library
5. removing single tracks form playlist by hovering and pressing del
6. appending albums by middleclick
7. query albums by rightclick
8. sending notifications on title change
9. managing multiple mpd servers
TODO
----
1. MPRIS interface
2. connecting to mpd servers with password
Building and installation
-------------------------
To build from source, use::
./autogen.sh
make
make install

View File

@@ -1,30 +0,0 @@
README for mpdevil
==================
mpdevil is focused on playing your local music directly instead of managing playlists or playing network streams. So it neither supports saving playlists nor restoring them. Therefore mpdevil is mainly a music browser which aims to be easy to use. mpdevil dosen't store any client side database of your music library. Instead all tags and covers get presented to you in real time. So you'll never see any outdated information in your browser.
Features
--------
-playing songs without doubleclicking
-displaying covers
-fetching lyrics form the web (based on PyLyrics 1.1.0)
-searching songs in your music library
-removing single tracks form playlist by hovering and pressing del
-sending notifications on title change
-managing multiple mpd servers
Building and installation
-------------------------
To build from source, use::
./autogen.sh
make
make install

View File

@@ -89,6 +89,104 @@ class Client(MPDClient):
except:
return False
class AlbumDialog(Gtk.Dialog):
def __init__(self, parent, client, album, artist, year):
Gtk.Dialog.__init__(self, title=(artist+" - "+album+" ("+year+")"), transient_for=parent)
self.add_buttons(Gtk.STOCK_ADD, Gtk.ResponseType.ACCEPT, Gtk.STOCK_MEDIA_PLAY, Gtk.ResponseType.YES, Gtk.STOCK_OK, Gtk.ResponseType.OK, Gtk.STOCK_CLOSE, Gtk.ResponseType.CLOSE)
self.set_default_size(800, 600)
#adding vars
self.client=client
#scroll
scroll=Gtk.ScrolledWindow()
scroll.set_policy(Gtk.PolicyType.AUTOMATIC, Gtk.PolicyType.AUTOMATIC)
#Store
#(track, title, artist, duration, file)
self.store = Gtk.ListStore(str, str, str, str, str)
#TreeView
self.treeview = Gtk.TreeView(model=self.store)
self.treeview.set_search_column(-1)
self.treeview.columns_autosize()
self.selection = self.treeview.get_selection()
self.selection.set_mode(Gtk.SelectionMode.SINGLE)
#Column
renderer_text = Gtk.CellRendererText()
self.column_track = Gtk.TreeViewColumn(_("No"), renderer_text, text=0)
self.column_track.set_sizing(Gtk.TreeViewColumnSizing.AUTOSIZE)
self.column_track.set_property("resizable", False)
self.treeview.append_column(self.column_track)
self.column_title = Gtk.TreeViewColumn(_("Title"), renderer_text, text=1)
self.column_title.set_sizing(Gtk.TreeViewColumnSizing.AUTOSIZE)
self.column_title.set_property("resizable", False)
self.treeview.append_column(self.column_title)
self.column_artist = Gtk.TreeViewColumn(_("Artist"), renderer_text, text=2)
self.column_artist.set_sizing(Gtk.TreeViewColumnSizing.AUTOSIZE)
self.column_artist.set_property("resizable", False)
self.treeview.append_column(self.column_artist)
self.column_time = Gtk.TreeViewColumn(_("Length"), renderer_text, text=3)
self.column_time.set_sizing(Gtk.TreeViewColumnSizing.AUTOSIZE)
self.column_time.set_property("resizable", False)
self.treeview.append_column(self.column_time)
self.populate_treeview(album, artist, year)
#connect
self.title_activated=self.treeview.connect("row-activated", self.on_row_activated)
#packing
scroll.add(self.treeview)
self.vbox.pack_start(scroll, True, True, 0) #vbox default widget of dialogs
self.show_all()
#selection workaround
self.selection.unselect_all()
self.title_change=self.selection.connect("changed", self.on_selection_change)
def on_row_activated(self, widget, path, view_column):
treeiter=self.store.get_iter(path)
selected_title=self.store.get_value(treeiter, 4)
self.client.clear()
self.client.add(selected_title)
self.client.play(0)
def on_selection_change(self, widget):
treeiter=widget.get_selected()[1]
if not treeiter == None:
selected_title=self.store.get_value(treeiter, 4)
self.client.add(selected_title)
def populate_treeview(self, album, artist, year):
songs=self.client.find("album", album, "date", year, "albumartist", artist)
if not songs == []:
for song in songs:
try:
title=song["title"]
except:
title=_("Unknown Title")
try:
artist=song["artist"]
except:
artist=_("Unknown Artist")
try:
track=song["track"].zfill(2)
except:
track="00"
try:
dura=float(song["duration"])
except:
dura=0.0
duration=str(datetime.timedelta(seconds=int(dura)))
self.store.append([track, title, artist, duration, song["file"]] )
class ArtistView(Gtk.ScrolledWindow):
def __init__(self, client):
Gtk.ScrolledWindow.__init__(self)
@@ -113,7 +211,7 @@ class ArtistView(Gtk.ScrolledWindow):
#Old Name Column
renderer_text = Gtk.CellRendererText()
self.column_name = Gtk.TreeViewColumn(_("Artist"), renderer_text, text=0)
self.column_name = Gtk.TreeViewColumn(_("Album Artist"), renderer_text, text=0)
self.column_name.set_sizing(Gtk.TreeViewColumnSizing.AUTOSIZE)
self.column_name.set_property("resizable", True)
self.column_name.set_sort_column_id(0)
@@ -161,28 +259,19 @@ class AlbumView(Gtk.ScrolledWindow):
self.add(self.iconview)
def gen_title_list(self, album, artist, year): #needed for tooltips
def gen_tooltip(self, album, artist, year):
if self.settings.get_boolean("show-album-view-tooltips"):
songs=self.client.find("album", album, "date", year, "albumartist", artist)
length=float(0)
title_list=""
for song in songs:
try:
title=song["title"]
dura=float(song["duration"])
except:
title=_("Unknown Title")
try:
track=song["track"].zfill(2)
except:
track="00"
length=length+float(song["duration"])
duration=str(datetime.timedelta(seconds=int(float(song["duration"]))))
title_list=title_list+"\n"+(track+" - "+title+" ("+duration+")")
if not year == "":
year=" ("+year+")"
dura=0.0
length=length+dura
length_human_readable=str(datetime.timedelta(seconds=int(length)))
title_list=(_("%(album)s%(year)s (tracks: %(total_tracks)i) (%(total_length)s):") % {"album": album, "year": year, "total_tracks": len(songs), "total_length": length_human_readable})+title_list
return title_list.replace("&", "") #& must not be in tooltips
tooltip=(_("%(total_tracks)i titles (%(total_length)s)") % {"total_tracks": len(songs), "total_length": length_human_readable})
return tooltip
else:
return None
@@ -202,9 +291,9 @@ class AlbumView(Gtk.ScrolledWindow):
cover=Cover(client=self.client, lib_path=self.settings.get_value("paths")[self.settings.get_int("active-profile")], song_file=song_file)
img=cover.get_pixbuf(size)
if album["year"] == "":
self.store.append([img, album["album"], self.gen_title_list(album["album"], artist, album["year"]), album["album"], album["year"]])
self.store.append([img, album["album"], self.gen_tooltip(album["album"], artist, album["year"]), album["album"], album["year"]])
else:
self.store.append([img, album["album"]+" ("+album["year"]+")", self.gen_title_list(album["album"], artist, album["year"]), album["album"], album["year"]])
self.store.append([img, album["album"]+" ("+album["year"]+")", self.gen_tooltip(album["album"], artist, album["year"]), album["album"], album["year"]])
while Gtk.events_pending():
Gtk.main_iteration_do(True)
@@ -227,7 +316,6 @@ class TrackView(Gtk.Box):
#TreeView
self.treeview = Gtk.TreeView(model=self.store)
self.treeview.set_search_column(-1)
self.treeview.set_tooltip_column(5)
self.treeview.columns_autosize()
#selection
@@ -302,14 +390,11 @@ class TrackView(Gtk.Box):
for song in songs:
self.client.add(song["file"])
else:
if self.settings.get_boolean("add-album") and not force:
if self.settings.get_boolean("add-album") and not force and not self.client.status()["state"] == "stop":
self.selection.handler_block(self.title_change)
status=self.client.status()
try:
self.client.moveid(status["songid"], 0) #bad song index possible
self.client.moveid(status["songid"], 0)
self.song_to_delete=self.client.playlistinfo()[0]["file"]
except:
pass
self.selection.handler_unblock(self.title_change)
try:
self.client.delete((1,)) # delete all songs, but the first. #bad song index possible
@@ -356,7 +441,11 @@ class TrackView(Gtk.Box):
album=song["album"]
except:
album=_("Unknown Album")
duration=str(datetime.timedelta(seconds=int(float(song["duration"]))))
try:
dura=float(song["duration"])
except:
dura=0.0
duration=str(datetime.timedelta(seconds=int(dura )))
self.store.append([track, title, artist, album, duration, song["file"].replace("&", "")])
self.playlist=self.client.playlist()
else:
@@ -417,12 +506,13 @@ class TrackView(Gtk.Box):
self.client.play(selected_title)
class Browser(Gtk.Box):
def __init__(self, client, settings):
def __init__(self, client, settings, window):
Gtk.Box.__init__(self, orientation=Gtk.Orientation.HORIZONTAL, spacing=3)
#adding vars
self.client=client
self.settings=settings
self.window=window
#widgets
self.artist_list=ArtistView(self.client)
@@ -502,14 +592,26 @@ class Browser(Gtk.Box):
def on_album_view_button_press_event(self, widget, event):
path = widget.get_path_at_pos(int(event.x), int(event.y))
if event.button == 3:
if not path == None:
if not event.button == 1:
treeiter=self.album_list.store.get_iter(path)
selected_album=self.album_list.store.get_value(treeiter, 3)
selected_album_year=self.album_list.store.get_value(treeiter, 4)
treeiter=self.artist_list.selection.get_selected()[1]
selected_artist=self.artist_list.store.get_value(treeiter, 0)
if event.button == 2:
self.title_list.album_to_playlist(selected_album, selected_artist, selected_album_year, True)
elif event.button == 3:
if self.client.connected():
album = AlbumDialog(self.window, self.client, selected_album, selected_artist, selected_album_year)
response = album.run()
if response == Gtk.ResponseType.OK:
self.title_list.album_to_playlist(selected_album, selected_artist, selected_album_year, False)
elif response == Gtk.ResponseType.ACCEPT:
self.title_list.album_to_playlist(selected_album, selected_artist, selected_album_year, True)
elif response == Gtk.ResponseType.YES:
self.title_list.album_to_playlist(selected_album, selected_artist, selected_album_year, False, True)
album.destroy()
def on_album_selection_change(self, widget):
paths=widget.get_selected_items()
@@ -711,7 +813,7 @@ class GeneralSettings(Gtk.Grid):
show_stop=Gtk.CheckButton(label=_("Show stop button"))
show_stop.set_active(self.settings.get_boolean("show-stop"))
show_album_view_tooltips=Gtk.CheckButton(label=_("Show title list as tooltip in album view"))
show_album_view_tooltips=Gtk.CheckButton(label=_("Show tooltips in album view"))
show_album_view_tooltips.set_active(self.settings.get_boolean("show-album-view-tooltips"))
send_notify=Gtk.CheckButton(label=_("Send notification on title change"))
@@ -779,10 +881,10 @@ class ClientControl(Gtk.ButtonBox):
self.settings=settings
#widgets
self.play_button = Gtk.Button(image=Gtk.Image.new_from_icon_name("media-playback-start", Gtk.IconSize.DND))
self.stop_button = Gtk.Button(image=Gtk.Image.new_from_icon_name("media-playback-stop", Gtk.IconSize.DND))
self.prev_button = Gtk.Button(image=Gtk.Image.new_from_icon_name("media-skip-backward", Gtk.IconSize.DND))
self.next_button = Gtk.Button(image=Gtk.Image.new_from_icon_name("media-skip-forward", Gtk.IconSize.DND))
self.play_button = Gtk.Button(image=Gtk.Image.new_from_icon_name("media-playback-start-symbolic", Gtk.IconSize.DND))
self.stop_button = Gtk.Button(image=Gtk.Image.new_from_icon_name("media-playback-stop-symbolic", Gtk.IconSize.DND))
self.prev_button = Gtk.Button(image=Gtk.Image.new_from_icon_name("media-skip-backward-symbolic", Gtk.IconSize.DND))
self.next_button = Gtk.Button(image=Gtk.Image.new_from_icon_name("media-skip-forward-symbolic", Gtk.IconSize.DND))
#connect
self.play_button.connect("clicked", self.on_play_clicked)
@@ -805,15 +907,15 @@ class ClientControl(Gtk.ButtonBox):
if self.client.connected():
status=self.client.status()
if status["state"] == "play":
self.play_button.set_image(Gtk.Image.new_from_icon_name("media-playback-pause", Gtk.IconSize.DND))
self.play_button.set_image(Gtk.Image.new_from_icon_name("media-playback-pause-symbolic", Gtk.IconSize.DND))
self.prev_button.set_sensitive(True)
self.next_button.set_sensitive(True)
elif status["state"] == "pause":
self.play_button.set_image(Gtk.Image.new_from_icon_name("media-playback-start", Gtk.IconSize.DND))
self.play_button.set_image(Gtk.Image.new_from_icon_name("media-playback-start-symbolic", Gtk.IconSize.DND))
self.prev_button.set_sensitive(True)
self.next_button.set_sensitive(True)
else:
self.play_button.set_image(Gtk.Image.new_from_icon_name("media-playback-start", Gtk.IconSize.DND))
self.play_button.set_image(Gtk.Image.new_from_icon_name("media-playback-start-symbolic", Gtk.IconSize.DND))
self.prev_button.set_sensitive(False)
self.next_button.set_sensitive(False)
return True
@@ -882,13 +984,10 @@ class SeekBar(Gtk.Box):
def seek(self, range, scroll, value):
status=self.client.status()
try:
duration=float(status["duration"])
factor=(value/100)
pos=(duration*factor)
self.client.seekcur(pos)
except:
pass
def update(self):
try:
@@ -1168,7 +1267,7 @@ class ServerStats(Gtk.Dialog):
class Search(Gtk.Dialog):
def __init__(self, parent, client):
Gtk.Dialog.__init__(self, title=_("Search"), transient_for=parent)
self.add_button(Gtk.STOCK_OK, Gtk.ResponseType.OK)
self.add_button(Gtk.STOCK_CLOSE, Gtk.ResponseType.CLOSE)
self.set_default_size(800, 600)
#adding vars
@@ -1180,7 +1279,6 @@ class Search(Gtk.Dialog):
#search entry
self.search_entry=Gtk.SearchEntry()
self.search_entry.connect("search-changed", self.on_search_changed)
#label
self.label=Gtk.Label()
@@ -1193,7 +1291,6 @@ class Search(Gtk.Dialog):
#TreeView
self.treeview = Gtk.TreeView(model=self.store)
self.treeview.set_search_column(-1)
self.treeview.set_tooltip_column(5)
self.treeview.columns_autosize()
self.selection = self.treeview.get_selection()
@@ -1230,6 +1327,7 @@ class Search(Gtk.Dialog):
#connect
self.title_activated=self.treeview.connect("row-activated", self.on_row_activated)
self.title_change=self.selection.connect("changed", self.on_selection_change)
self.search_entry.connect("search-changed", self.on_search_changed)
#packing
scroll.add(self.treeview)
@@ -1270,7 +1368,11 @@ class Search(Gtk.Dialog):
album=song["album"]
except:
album=_("Unknown Album")
duration=str(datetime.timedelta(seconds=int(float(song["duration"]))))
try:
dura=float(song["duration"])
except:
dura=0.0
duration=str(datetime.timedelta(seconds=int(dura)))
self.store.append([track, title, artist, album, duration, song["file"].replace("&", "")] )
self.label.set_text(_("Hits: %i") % (len(self.store)))
@@ -1407,16 +1509,16 @@ class MainWindow(Gtk.ApplicationWindow):
self.add_action(update_action)
#widgets
self.browser=Browser(self.client, self.settings)
self.browser=Browser(self.client, self.settings, self)
self.profiles=ProfileSelect(self.client, self.settings)
self.profiles.set_tooltip_text(_("Select profile"))
self.control=ClientControl(self.client, self.settings)
self.progress=SeekBar(self.client)
self.go_home_button=Gtk.Button(image=Gtk.Image.new_from_icon_name("go-home", Gtk.IconSize.DND))
self.go_home_button=Gtk.Button(image=Gtk.Image.new_from_icon_name("go-home-symbolic", Gtk.IconSize.DND))
self.go_home_button.set_tooltip_text(_("Return to album of current title"))
self.search_button=Gtk.Button(image=Gtk.Image.new_from_icon_name("system-search", Gtk.IconSize.DND))
self.search_button=Gtk.Button(image=Gtk.Image.new_from_icon_name("system-search-symbolic", Gtk.IconSize.DND))
self.search_button.set_tooltip_text(_("Title search"))
self.lyrics_button=Gtk.ToggleButton(image=Gtk.Image.new_from_icon_name("media-view-subtitles", Gtk.IconSize.DND))
self.lyrics_button=Gtk.ToggleButton(image=Gtk.Image.new_from_icon_name("media-view-subtitles-symbolic", Gtk.IconSize.DND))
self.lyrics_button.set_tooltip_text(_("Show lyrics"))
self.play_opts=PlaybackOptions(self.client)
@@ -1561,6 +1663,7 @@ class mpdevil(Gtk.Application):
BASE_KEY = "org.mpdevil"
def __init__(self, *args, **kwargs):
super().__init__(*args, application_id="org.mpdevil", flags=Gio.ApplicationFlags.FLAGS_NONE, **kwargs)
#Gtk.window_set_default_icon_name("mpdevil")
self.client=Client()
self.settings = Gio.Settings.new(self.BASE_KEY)
self.window=None
@@ -1592,6 +1695,7 @@ class mpdevil(Gtk.Application):
dialog.set_version(VERSION)
dialog.set_comments(_("A small MPD client written in python"))
dialog.set_authors(["Martin Wagner"])
dialog.set_website("https://github.com/SoongNoonien/mpdevil")
dialog.set_logo_icon_name(PACKAGE)
dialog.run()
dialog.destroy()

View File

@@ -1,7 +1,7 @@
dnl -*- Mode: autoconf -*-
dnl Process this file with autoconf to produce a configure script.
AC_PREREQ([2.68])
AC_INIT([mpdevil], [0.3])
AC_INIT([mpdevil], [0.4.0])
AC_CONFIG_SRCDIR([bin/mpdevil.py])
AM_INIT_AUTOMAKE
AC_CONFIG_MACRO_DIR([m4])
@@ -50,7 +50,7 @@ if $PYTHON -c "$prog" 1>&AS_MESSAGE_LOG_FD 2>&AS_MESSAGE_LOG_FD; then
AC_MSG_RESULT(found)
else
AC_MSG_RESULT(not found)
AC_MSG_ERROR(MPDClient not found)
AC_MSG_ERROR(python module mpd not found)
fi
dnl Check for beautifulsoup
@@ -62,7 +62,19 @@ if $PYTHON -c "$prog" 1>&AS_MESSAGE_LOG_FD 2>&AS_MESSAGE_LOG_FD; then
AC_MSG_RESULT(found)
else
AC_MSG_RESULT(not found)
AC_MSG_ERROR(beautifulsoup not found)
AC_MSG_ERROR(python module bs4 not found)
fi
dnl Check for requests
AC_MSG_CHECKING(for requests installed)
prog="
import requests
"
if $PYTHON -c "$prog" 1>&AS_MESSAGE_LOG_FD 2>&AS_MESSAGE_LOG_FD; then
AC_MSG_RESULT(found)
else
AC_MSG_RESULT(not found)
AC_MSG_ERROR(python module requests not found)
fi
AC_CONFIG_FILES([Makefile

140
po/de.po
View File

@@ -7,8 +7,8 @@ msgid ""
msgstr ""
"Project-Id-Version: \n"
"Report-Msgid-Bugs-To: \n"
"POT-Creation-Date: 2020-01-06 00:53+0100\n"
"PO-Revision-Date: 2020-01-06 00:55+0100\n"
"POT-Creation-Date: 2020-01-17 22:33+0100\n"
"PO-Revision-Date: 2020-01-17 22:34+0100\n"
"Last-Translator: \n"
"Language-Team: \n"
"Language: de\n"
@@ -18,136 +18,140 @@ msgstr ""
"X-Generator: Poedit 2.2.4\n"
"Plural-Forms: nplurals=2; plural=(n != 1);\n"
#: mpdevil.py:116 mpdevil.py:250 mpdevil.py:1215
msgid "Artist"
msgstr "Künstler"
#: mpdevil.py:173 mpdevil.py:346 mpdevil.py:1260
msgid "Unknown Title"
msgstr "Unbekannter Titel"
#: mpdevil.py:184
#, python-format
msgid "%(album)s%(year)s (tracks: %(total_tracks)i) (%(total_length)s):"
msgstr "%(album)s%(year)s (Titel: %(total_tracks)i) (%(total_length)s):"
#: mpdevil.py:240 mpdevil.py:1205
#: mpdevil.py:120 mpdevil.py:328 mpdevil.py:1302
msgid "No"
msgstr "Nr."
#: mpdevil.py:245 mpdevil.py:1210
#: mpdevil.py:125 mpdevil.py:333 mpdevil.py:1307
msgid "Title"
msgstr "Titel"
#: mpdevil.py:255 mpdevil.py:1225
#: mpdevil.py:130 mpdevil.py:338 mpdevil.py:1312
msgid "Artist"
msgstr "Interpret"
#: mpdevil.py:135 mpdevil.py:343 mpdevil.py:1322
msgid "Length"
msgstr "Länge"
#: mpdevil.py:354 mpdevil.py:1268
#: mpdevil.py:174 mpdevil.py:431 mpdevil.py:1358
msgid "Unknown Title"
msgstr "Unbekannter Titel"
#: mpdevil.py:178 mpdevil.py:439 mpdevil.py:1366
msgid "Unknown Artist"
msgstr "Unbekannter Künstler"
#: mpdevil.py:358 mpdevil.py:1272
#: mpdevil.py:214
msgid "Album Artist"
msgstr "Albuminterpret"
#: mpdevil.py:273
#, python-format
msgid "%(total_tracks)i titles (%(total_length)s)"
msgstr "%(total_tracks)i Titel (%(total_length)s)"
#: mpdevil.py:443 mpdevil.py:1370
msgid "Unknown Album"
msgstr "Unbekanntes Album"
#: mpdevil.py:567
#: mpdevil.py:669
msgid "Select"
msgstr "Auswählen"
#: mpdevil.py:569
#: mpdevil.py:671
msgid "Profile:"
msgstr "Profil:"
#: mpdevil.py:571
#: mpdevil.py:673
msgid "Name:"
msgstr "Name:"
#: mpdevil.py:573
#: mpdevil.py:675
msgid "Host:"
msgstr "Host:"
#: mpdevil.py:575
#: mpdevil.py:677
msgid "Port:"
msgstr "Port:"
#: mpdevil.py:577
#: mpdevil.py:679
msgid "Music lib:"
msgstr "Musikverzeichnis:"
#: mpdevil.py:667
#: mpdevil.py:769
msgid "Choose directory"
msgstr "Verzeichnis Wählen"
#: mpdevil.py:703
#: mpdevil.py:805
msgid "Main cover size:"
msgstr "Größe des Haupt-Covers:"
#: mpdevil.py:705
#: mpdevil.py:807
msgid "Album-view cover size:"
msgstr "Covergröße in Albumansicht:"
#: mpdevil.py:711
#: mpdevil.py:813
msgid "Show stop button"
msgstr "Zeige Stopp-Knopf"
#: mpdevil.py:714
msgid "Show title list as tooltip in album view"
msgstr "Zeige Titellisten als Tooltips in Albumansicht"
#: mpdevil.py:816
msgid "Show tooltips in album view"
msgstr "Zeige Tooltips in Albumansicht"
#: mpdevil.py:717
#: mpdevil.py:819
msgid "Send notification on title change"
msgstr "Sende Benachrichtigung bei Titelwechsel"
#: mpdevil.py:720
#: mpdevil.py:822
msgid "Stop playback on quit"
msgstr "Wiedergabe beim Beenden stoppen"
#: mpdevil.py:723
#: mpdevil.py:825
msgid "Play selected album after current title"
msgstr "Ausgewähltes Album hinter aktuellem Titel einreihen"
#: mpdevil.py:754 mpdevil.py:1432
#: mpdevil.py:856 mpdevil.py:1534
msgid "Settings"
msgstr "Einstellungen"
#: mpdevil.py:767
#: mpdevil.py:869
msgid "General"
msgstr "Allgemein"
#: mpdevil.py:768
#: mpdevil.py:870
msgid "Profiles"
msgstr "Profile"
#: mpdevil.py:919
#: mpdevil.py:1018
msgid "Random mode"
msgstr "Zufallsmodus"
#: mpdevil.py:921
#: mpdevil.py:1020
msgid "Repeat mode"
msgstr "Dauerschleife"
#: mpdevil.py:923
#: mpdevil.py:1022
msgid "Single mode"
msgstr "Einzelstückmodus"
#: mpdevil.py:925
#: mpdevil.py:1024
msgid "Consume mode"
msgstr "Playliste verbrauchen"
#: mpdevil.py:1019
#: mpdevil.py:1118
msgid "Right click to show additional information"
msgstr "Rechtsclick für weitere Informationen"
#: mpdevil.py:1042
#: mpdevil.py:1141
msgid "MPD-Tag"
msgstr "MPD-Tag"
#: mpdevil.py:1045 mpdevil.py:1153
#: mpdevil.py:1144 mpdevil.py:1252
msgid "Value"
msgstr "Wert"
#: mpdevil.py:1066
#: mpdevil.py:1165
#, python-format
msgid ""
"%(bitrate)s kb/s, %(frequency)s kHz, %(resolution)s bit, %(channels)s "
@@ -156,88 +160,88 @@ msgstr ""
"%(bitrate)s kb/s, %(frequency)s kHz, %(resolution)s bit, %(channels)s "
"Kanäle, %(file_type)s"
#: mpdevil.py:1132
#: mpdevil.py:1231
msgid "Stats"
msgstr "Statistik"
#: mpdevil.py:1150
#: mpdevil.py:1249
msgid "Tag"
msgstr "Tag"
#: mpdevil.py:1170
#: mpdevil.py:1269
msgid "Search"
msgstr "Suche"
#: mpdevil.py:1220
#: mpdevil.py:1317
msgid "Album"
msgstr "Album"
#: mpdevil.py:1275
#: mpdevil.py:1377
#, python-format
msgid "Hits: %i"
msgstr "Treffer: %i"
#: mpdevil.py:1279
#: mpdevil.py:1381
msgid "Lyrics"
msgstr "Liedtext"
#: mpdevil.py:1323
#: mpdevil.py:1425
msgid "searching..."
msgstr "suche..."
#: mpdevil.py:1327
#: mpdevil.py:1429
msgid "not found"
msgstr "nicht gefunden"
#: mpdevil.py:1332
#: mpdevil.py:1434
msgid "not connected"
msgstr "nicht verbunden"
#: mpdevil.py:1412
#: mpdevil.py:1514
msgid "Select profile"
msgstr "Profil auswählen"
#: mpdevil.py:1416
#: mpdevil.py:1518
msgid "Return to album of current title"
msgstr "Zu Album des aktuellen Titels zurückkehren"
#: mpdevil.py:1418
#: mpdevil.py:1520
msgid "Title search"
msgstr "Titelsuche"
#: mpdevil.py:1420
#: mpdevil.py:1522
msgid "Show lyrics"
msgstr "Zeige Liedtext"
#: mpdevil.py:1427
#: mpdevil.py:1529
msgid "Not connected to MPD-server. Reconnect?"
msgstr "Nicht mit MPD-Server verbunden. Verbindung wiederherstellen?"
#: mpdevil.py:1431
#: mpdevil.py:1533
msgid "Save window size"
msgstr "Fenstergröße speichern"
#: mpdevil.py:1433
#: mpdevil.py:1535
msgid "Update database"
msgstr "Datenbank aktualisieren"
#: mpdevil.py:1434
#: mpdevil.py:1536
msgid "Server stats"
msgstr "Serverstatistik"
#: mpdevil.py:1435
#: mpdevil.py:1537
msgid "About"
msgstr "Über"
#: mpdevil.py:1436
#: mpdevil.py:1538
msgid "Quit"
msgstr "Beenden"
#: mpdevil.py:1441
#: mpdevil.py:1543
msgid "Main menu"
msgstr "Hauptmenu"
#: mpdevil.py:1593
#: mpdevil.py:1696
msgid "A small MPD client written in python"
msgstr ""

View File

@@ -8,7 +8,7 @@ msgid ""
msgstr ""
"Project-Id-Version: PACKAGE VERSION\n"
"Report-Msgid-Bugs-To: \n"
"POT-Creation-Date: 2020-01-06 00:53+0100\n"
"POT-Creation-Date: 2020-01-17 22:33+0100\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,223 +17,227 @@ msgstr ""
"Content-Type: text/plain; charset=CHARSET\n"
"Content-Transfer-Encoding: 8bit\n"
#: mpdevil.py:116 mpdevil.py:250 mpdevil.py:1215
msgid "Artist"
msgstr ""
#: mpdevil.py:173 mpdevil.py:346 mpdevil.py:1260
msgid "Unknown Title"
msgstr ""
#: mpdevil.py:184
#, python-format
msgid "%(album)s%(year)s (tracks: %(total_tracks)i) (%(total_length)s):"
msgstr ""
#: mpdevil.py:240 mpdevil.py:1205
#: mpdevil.py:120 mpdevil.py:328 mpdevil.py:1302
msgid "No"
msgstr ""
#: mpdevil.py:245 mpdevil.py:1210
#: mpdevil.py:125 mpdevil.py:333 mpdevil.py:1307
msgid "Title"
msgstr ""
#: mpdevil.py:255 mpdevil.py:1225
#: mpdevil.py:130 mpdevil.py:338 mpdevil.py:1312
msgid "Artist"
msgstr ""
#: mpdevil.py:135 mpdevil.py:343 mpdevil.py:1322
msgid "Length"
msgstr ""
#: mpdevil.py:354 mpdevil.py:1268
#: mpdevil.py:174 mpdevil.py:431 mpdevil.py:1358
msgid "Unknown Title"
msgstr ""
#: mpdevil.py:178 mpdevil.py:439 mpdevil.py:1366
msgid "Unknown Artist"
msgstr ""
#: mpdevil.py:358 mpdevil.py:1272
#: mpdevil.py:214
msgid "Album Artist"
msgstr ""
#: mpdevil.py:273
#, python-format
msgid "%(total_tracks)i titles (%(total_length)s)"
msgstr ""
#: mpdevil.py:443 mpdevil.py:1370
msgid "Unknown Album"
msgstr ""
#: mpdevil.py:567
#: mpdevil.py:669
msgid "Select"
msgstr ""
#: mpdevil.py:569
#: mpdevil.py:671
msgid "Profile:"
msgstr ""
#: mpdevil.py:571
#: mpdevil.py:673
msgid "Name:"
msgstr ""
#: mpdevil.py:573
#: mpdevil.py:675
msgid "Host:"
msgstr ""
#: mpdevil.py:575
#: mpdevil.py:677
msgid "Port:"
msgstr ""
#: mpdevil.py:577
#: mpdevil.py:679
msgid "Music lib:"
msgstr ""
#: mpdevil.py:667
#: mpdevil.py:769
msgid "Choose directory"
msgstr ""
#: mpdevil.py:703
#: mpdevil.py:805
msgid "Main cover size:"
msgstr ""
#: mpdevil.py:705
#: mpdevil.py:807
msgid "Album-view cover size:"
msgstr ""
#: mpdevil.py:711
#: mpdevil.py:813
msgid "Show stop button"
msgstr ""
#: mpdevil.py:714
msgid "Show title list as tooltip in album view"
#: mpdevil.py:816
msgid "Show tooltips in album view"
msgstr ""
#: mpdevil.py:717
#: mpdevil.py:819
msgid "Send notification on title change"
msgstr ""
#: mpdevil.py:720
#: mpdevil.py:822
msgid "Stop playback on quit"
msgstr ""
#: mpdevil.py:723
#: mpdevil.py:825
msgid "Play selected album after current title"
msgstr ""
#: mpdevil.py:754 mpdevil.py:1432
#: mpdevil.py:856 mpdevil.py:1534
msgid "Settings"
msgstr ""
#: mpdevil.py:767
#: mpdevil.py:869
msgid "General"
msgstr ""
#: mpdevil.py:768
#: mpdevil.py:870
msgid "Profiles"
msgstr ""
#: mpdevil.py:919
#: mpdevil.py:1018
msgid "Random mode"
msgstr ""
#: mpdevil.py:921
#: mpdevil.py:1020
msgid "Repeat mode"
msgstr ""
#: mpdevil.py:923
#: mpdevil.py:1022
msgid "Single mode"
msgstr ""
#: mpdevil.py:925
#: mpdevil.py:1024
msgid "Consume mode"
msgstr ""
#: mpdevil.py:1019
#: mpdevil.py:1118
msgid "Right click to show additional information"
msgstr ""
#: mpdevil.py:1042
#: mpdevil.py:1141
msgid "MPD-Tag"
msgstr ""
#: mpdevil.py:1045 mpdevil.py:1153
#: mpdevil.py:1144 mpdevil.py:1252
msgid "Value"
msgstr ""
#: mpdevil.py:1066
#: mpdevil.py:1165
#, python-format
msgid ""
"%(bitrate)s kb/s, %(frequency)s kHz, %(resolution)s bit, %(channels)s "
"channels, %(file_type)s"
msgstr ""
#: mpdevil.py:1132
#: mpdevil.py:1231
msgid "Stats"
msgstr ""
#: mpdevil.py:1150
#: mpdevil.py:1249
msgid "Tag"
msgstr ""
#: mpdevil.py:1170
#: mpdevil.py:1269
msgid "Search"
msgstr ""
#: mpdevil.py:1220
#: mpdevil.py:1317
msgid "Album"
msgstr ""
#: mpdevil.py:1275
#: mpdevil.py:1377
#, python-format
msgid "Hits: %i"
msgstr ""
#: mpdevil.py:1279
#: mpdevil.py:1381
msgid "Lyrics"
msgstr ""
#: mpdevil.py:1323
#: mpdevil.py:1425
msgid "searching..."
msgstr ""
#: mpdevil.py:1327
#: mpdevil.py:1429
msgid "not found"
msgstr ""
#: mpdevil.py:1332
#: mpdevil.py:1434
msgid "not connected"
msgstr ""
#: mpdevil.py:1412
#: mpdevil.py:1514
msgid "Select profile"
msgstr ""
#: mpdevil.py:1416
#: mpdevil.py:1518
msgid "Return to album of current title"
msgstr ""
#: mpdevil.py:1418
#: mpdevil.py:1520
msgid "Title search"
msgstr ""
#: mpdevil.py:1420
#: mpdevil.py:1522
msgid "Show lyrics"
msgstr ""
#: mpdevil.py:1427
#: mpdevil.py:1529
msgid "Not connected to MPD-server. Reconnect?"
msgstr ""
#: mpdevil.py:1431
#: mpdevil.py:1533
msgid "Save window size"
msgstr ""
#: mpdevil.py:1433
#: mpdevil.py:1535
msgid "Update database"
msgstr ""
#: mpdevil.py:1434
#: mpdevil.py:1536
msgid "Server stats"
msgstr ""
#: mpdevil.py:1435
#: mpdevil.py:1537
msgid "About"
msgstr ""
#: mpdevil.py:1436
#: mpdevil.py:1538
msgid "Quit"
msgstr ""
#: mpdevil.py:1441
#: mpdevil.py:1543
msgid "Main menu"
msgstr ""
#: mpdevil.py:1593
#: mpdevil.py:1696
msgid "A small MPD client written in python"
msgstr ""

BIN
screenshots/mainwindow.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 1021 KiB