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: except:
return False 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): class ArtistView(Gtk.ScrolledWindow):
def __init__(self, client): def __init__(self, client):
Gtk.ScrolledWindow.__init__(self) Gtk.ScrolledWindow.__init__(self)
@@ -113,7 +211,7 @@ class ArtistView(Gtk.ScrolledWindow):
#Old Name Column #Old Name Column
renderer_text = Gtk.CellRendererText() 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_sizing(Gtk.TreeViewColumnSizing.AUTOSIZE)
self.column_name.set_property("resizable", True) self.column_name.set_property("resizable", True)
self.column_name.set_sort_column_id(0) self.column_name.set_sort_column_id(0)
@@ -161,28 +259,19 @@ class AlbumView(Gtk.ScrolledWindow):
self.add(self.iconview) 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"): if self.settings.get_boolean("show-album-view-tooltips"):
songs=self.client.find("album", album, "date", year, "albumartist", artist) songs=self.client.find("album", album, "date", year, "albumartist", artist)
length=float(0) length=float(0)
title_list=""
for song in songs: for song in songs:
try: try:
title=song["title"] dura=float(song["duration"])
except: except:
title=_("Unknown Title") dura=0.0
try: length=length+dura
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+")"
length_human_readable=str(datetime.timedelta(seconds=int(length))) 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 tooltip=(_("%(total_tracks)i titles (%(total_length)s)") % {"total_tracks": len(songs), "total_length": length_human_readable})
return title_list.replace("&", "") #& must not be in tooltips return tooltip
else: else:
return None 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) 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) img=cover.get_pixbuf(size)
if album["year"] == "": 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: 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(): while Gtk.events_pending():
Gtk.main_iteration_do(True) Gtk.main_iteration_do(True)
@@ -227,7 +316,6 @@ class TrackView(Gtk.Box):
#TreeView #TreeView
self.treeview = Gtk.TreeView(model=self.store) self.treeview = Gtk.TreeView(model=self.store)
self.treeview.set_search_column(-1) self.treeview.set_search_column(-1)
self.treeview.set_tooltip_column(5)
self.treeview.columns_autosize() self.treeview.columns_autosize()
#selection #selection
@@ -302,14 +390,11 @@ class TrackView(Gtk.Box):
for song in songs: for song in songs:
self.client.add(song["file"]) self.client.add(song["file"])
else: 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) self.selection.handler_block(self.title_change)
status=self.client.status() status=self.client.status()
try: self.client.moveid(status["songid"], 0)
self.client.moveid(status["songid"], 0) #bad song index possible
self.song_to_delete=self.client.playlistinfo()[0]["file"] self.song_to_delete=self.client.playlistinfo()[0]["file"]
except:
pass
self.selection.handler_unblock(self.title_change) self.selection.handler_unblock(self.title_change)
try: try:
self.client.delete((1,)) # delete all songs, but the first. #bad song index possible 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"] album=song["album"]
except: except:
album=_("Unknown Album") 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.store.append([track, title, artist, album, duration, song["file"].replace("&", "")])
self.playlist=self.client.playlist() self.playlist=self.client.playlist()
else: else:
@@ -417,12 +506,13 @@ class TrackView(Gtk.Box):
self.client.play(selected_title) self.client.play(selected_title)
class Browser(Gtk.Box): 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) Gtk.Box.__init__(self, orientation=Gtk.Orientation.HORIZONTAL, spacing=3)
#adding vars #adding vars
self.client=client self.client=client
self.settings=settings self.settings=settings
self.window=window
#widgets #widgets
self.artist_list=ArtistView(self.client) self.artist_list=ArtistView(self.client)
@@ -502,14 +592,26 @@ class Browser(Gtk.Box):
def on_album_view_button_press_event(self, widget, event): def on_album_view_button_press_event(self, widget, event):
path = widget.get_path_at_pos(int(event.x), int(event.y)) path = widget.get_path_at_pos(int(event.x), int(event.y))
if event.button == 3:
if not path == None: if not path == None:
if not event.button == 1:
treeiter=self.album_list.store.get_iter(path) treeiter=self.album_list.store.get_iter(path)
selected_album=self.album_list.store.get_value(treeiter, 3) selected_album=self.album_list.store.get_value(treeiter, 3)
selected_album_year=self.album_list.store.get_value(treeiter, 4) selected_album_year=self.album_list.store.get_value(treeiter, 4)
treeiter=self.artist_list.selection.get_selected()[1] treeiter=self.artist_list.selection.get_selected()[1]
selected_artist=self.artist_list.store.get_value(treeiter, 0) 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) 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): def on_album_selection_change(self, widget):
paths=widget.get_selected_items() paths=widget.get_selected_items()
@@ -711,7 +813,7 @@ class GeneralSettings(Gtk.Grid):
show_stop=Gtk.CheckButton(label=_("Show stop button")) show_stop=Gtk.CheckButton(label=_("Show stop button"))
show_stop.set_active(self.settings.get_boolean("show-stop")) 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")) show_album_view_tooltips.set_active(self.settings.get_boolean("show-album-view-tooltips"))
send_notify=Gtk.CheckButton(label=_("Send notification on title change")) send_notify=Gtk.CheckButton(label=_("Send notification on title change"))
@@ -779,10 +881,10 @@ class ClientControl(Gtk.ButtonBox):
self.settings=settings self.settings=settings
#widgets #widgets
self.play_button = Gtk.Button(image=Gtk.Image.new_from_icon_name("media-playback-start", 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", 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", 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", Gtk.IconSize.DND)) self.next_button = Gtk.Button(image=Gtk.Image.new_from_icon_name("media-skip-forward-symbolic", Gtk.IconSize.DND))
#connect #connect
self.play_button.connect("clicked", self.on_play_clicked) self.play_button.connect("clicked", self.on_play_clicked)
@@ -805,15 +907,15 @@ class ClientControl(Gtk.ButtonBox):
if self.client.connected(): if self.client.connected():
status=self.client.status() status=self.client.status()
if status["state"] == "play": 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.prev_button.set_sensitive(True)
self.next_button.set_sensitive(True) self.next_button.set_sensitive(True)
elif status["state"] == "pause": 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.prev_button.set_sensitive(True)
self.next_button.set_sensitive(True) self.next_button.set_sensitive(True)
else: 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.prev_button.set_sensitive(False)
self.next_button.set_sensitive(False) self.next_button.set_sensitive(False)
return True return True
@@ -882,13 +984,10 @@ class SeekBar(Gtk.Box):
def seek(self, range, scroll, value): def seek(self, range, scroll, value):
status=self.client.status() status=self.client.status()
try:
duration=float(status["duration"]) duration=float(status["duration"])
factor=(value/100) factor=(value/100)
pos=(duration*factor) pos=(duration*factor)
self.client.seekcur(pos) self.client.seekcur(pos)
except:
pass
def update(self): def update(self):
try: try:
@@ -1168,7 +1267,7 @@ class ServerStats(Gtk.Dialog):
class Search(Gtk.Dialog): class Search(Gtk.Dialog):
def __init__(self, parent, client): def __init__(self, parent, client):
Gtk.Dialog.__init__(self, title=_("Search"), transient_for=parent) 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) self.set_default_size(800, 600)
#adding vars #adding vars
@@ -1180,7 +1279,6 @@ class Search(Gtk.Dialog):
#search entry #search entry
self.search_entry=Gtk.SearchEntry() self.search_entry=Gtk.SearchEntry()
self.search_entry.connect("search-changed", self.on_search_changed)
#label #label
self.label=Gtk.Label() self.label=Gtk.Label()
@@ -1193,7 +1291,6 @@ class Search(Gtk.Dialog):
#TreeView #TreeView
self.treeview = Gtk.TreeView(model=self.store) self.treeview = Gtk.TreeView(model=self.store)
self.treeview.set_search_column(-1) self.treeview.set_search_column(-1)
self.treeview.set_tooltip_column(5)
self.treeview.columns_autosize() self.treeview.columns_autosize()
self.selection = self.treeview.get_selection() self.selection = self.treeview.get_selection()
@@ -1230,6 +1327,7 @@ class Search(Gtk.Dialog):
#connect #connect
self.title_activated=self.treeview.connect("row-activated", self.on_row_activated) self.title_activated=self.treeview.connect("row-activated", self.on_row_activated)
self.title_change=self.selection.connect("changed", self.on_selection_change) self.title_change=self.selection.connect("changed", self.on_selection_change)
self.search_entry.connect("search-changed", self.on_search_changed)
#packing #packing
scroll.add(self.treeview) scroll.add(self.treeview)
@@ -1270,7 +1368,11 @@ class Search(Gtk.Dialog):
album=song["album"] album=song["album"]
except: except:
album=_("Unknown Album") 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.store.append([track, title, artist, album, duration, song["file"].replace("&", "")] )
self.label.set_text(_("Hits: %i") % (len(self.store))) self.label.set_text(_("Hits: %i") % (len(self.store)))
@@ -1407,16 +1509,16 @@ class MainWindow(Gtk.ApplicationWindow):
self.add_action(update_action) self.add_action(update_action)
#widgets #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=ProfileSelect(self.client, self.settings)
self.profiles.set_tooltip_text(_("Select profile")) self.profiles.set_tooltip_text(_("Select profile"))
self.control=ClientControl(self.client, self.settings) self.control=ClientControl(self.client, self.settings)
self.progress=SeekBar(self.client) 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.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.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.lyrics_button.set_tooltip_text(_("Show lyrics"))
self.play_opts=PlaybackOptions(self.client) self.play_opts=PlaybackOptions(self.client)
@@ -1561,6 +1663,7 @@ class mpdevil(Gtk.Application):
BASE_KEY = "org.mpdevil" BASE_KEY = "org.mpdevil"
def __init__(self, *args, **kwargs): def __init__(self, *args, **kwargs):
super().__init__(*args, application_id="org.mpdevil", flags=Gio.ApplicationFlags.FLAGS_NONE, **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.client=Client()
self.settings = Gio.Settings.new(self.BASE_KEY) self.settings = Gio.Settings.new(self.BASE_KEY)
self.window=None self.window=None
@@ -1592,6 +1695,7 @@ class mpdevil(Gtk.Application):
dialog.set_version(VERSION) dialog.set_version(VERSION)
dialog.set_comments(_("A small MPD client written in python")) dialog.set_comments(_("A small MPD client written in python"))
dialog.set_authors(["Martin Wagner"]) dialog.set_authors(["Martin Wagner"])
dialog.set_website("https://github.com/SoongNoonien/mpdevil")
dialog.set_logo_icon_name(PACKAGE) dialog.set_logo_icon_name(PACKAGE)
dialog.run() dialog.run()
dialog.destroy() dialog.destroy()

View File

@@ -1,7 +1,7 @@
dnl -*- Mode: autoconf -*- dnl -*- Mode: autoconf -*-
dnl Process this file with autoconf to produce a configure script. dnl Process this file with autoconf to produce a configure script.
AC_PREREQ([2.68]) AC_PREREQ([2.68])
AC_INIT([mpdevil], [0.3]) AC_INIT([mpdevil], [0.4.0])
AC_CONFIG_SRCDIR([bin/mpdevil.py]) AC_CONFIG_SRCDIR([bin/mpdevil.py])
AM_INIT_AUTOMAKE AM_INIT_AUTOMAKE
AC_CONFIG_MACRO_DIR([m4]) 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) AC_MSG_RESULT(found)
else else
AC_MSG_RESULT(not found) AC_MSG_RESULT(not found)
AC_MSG_ERROR(MPDClient not found) AC_MSG_ERROR(python module mpd not found)
fi fi
dnl Check for beautifulsoup 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) AC_MSG_RESULT(found)
else else
AC_MSG_RESULT(not found) 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 fi
AC_CONFIG_FILES([Makefile AC_CONFIG_FILES([Makefile

140
po/de.po
View File

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

View File

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

BIN
screenshots/mainwindow.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 1021 KiB