mirror of
https://github.com/SoongNoonien/mpdevil.git
synced 2023-08-10 21:12:44 +03:00
Compare commits
24 Commits
Author | SHA1 | Date | |
---|---|---|---|
![]() |
eb8edecfda | ||
![]() |
d059a1c9eb | ||
![]() |
6196f83ffc | ||
![]() |
4f273a8a1f | ||
![]() |
67ec5ad695 | ||
![]() |
f5b911f2cf | ||
![]() |
6a673f2bab | ||
![]() |
f7e6c23696 | ||
![]() |
0fb67698cd | ||
![]() |
ae3ac76b3d | ||
![]() |
e9805bbe70 | ||
![]() |
2fdb9658dd | ||
![]() |
60173ade3a | ||
![]() |
b5ac0583ba | ||
![]() |
24f026ff61 | ||
![]() |
32157bb609 | ||
![]() |
3be9589b75 | ||
![]() |
36df7cf7dd | ||
![]() |
28e526777e | ||
![]() |
ac53fc2136 | ||
![]() |
d909f351d3 | ||
![]() |
8756e317d2 | ||
![]() |
db5fbef06e | ||
![]() |
da1bb25d1d |
@@ -2,7 +2,7 @@ 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.
|
||||
|
||||

|
||||

|
||||
|
||||
Features
|
||||
--------
|
||||
|
656
bin/mpdevil.py
656
bin/mpdevil.py
@@ -20,7 +20,8 @@
|
||||
|
||||
import gi #python-gobject dev-python/pygobject:3[${PYTHON_USEDEP}]
|
||||
gi.require_version('Gtk', '3.0')
|
||||
from gi.repository import Gtk, Gio, Gdk, GdkPixbuf, Pango, GObject, GLib
|
||||
gi.require_version('Notify', '0.7')
|
||||
from gi.repository import Gtk, Gio, Gdk, GdkPixbuf, Pango, GObject, GLib, Notify
|
||||
from mpd import MPDClient
|
||||
import requests #dev-python/requests
|
||||
from bs4 import BeautifulSoup, Comment #, NavigableString #dev-python/beautifulsoup
|
||||
@@ -49,9 +50,9 @@ except locale.Error:
|
||||
gettext.install(PACKAGE, localedir='@datadir@/locale')
|
||||
|
||||
class IntEntry(Gtk.SpinButton):
|
||||
def __init__(self, default, lower, upper):
|
||||
def __init__(self, default, lower, upper, step):
|
||||
Gtk.SpinButton.__init__(self)
|
||||
adj = Gtk.Adjustment(value=default, lower=lower, upper=upper, step_increment=1)
|
||||
adj = Gtk.Adjustment(value=default, lower=lower, upper=upper, step_increment=step)
|
||||
self.set_adjustment(adj)
|
||||
|
||||
def get_int(self):
|
||||
@@ -127,6 +128,7 @@ class Client(MPDClient):
|
||||
self.move(0, (len(self.playlist())-1))
|
||||
self.song_to_delete=""
|
||||
else:
|
||||
self.song_to_delete=""
|
||||
songs=self.find("album", album, "date", year, self.settings.get_artist_type(), artist)
|
||||
if not songs == []:
|
||||
self.stop()
|
||||
@@ -157,6 +159,7 @@ class MpdEventEmitter(GObject.Object):
|
||||
except:
|
||||
self.client.try_connect_default()
|
||||
if self.client.connected():
|
||||
self.emit("disconnected")
|
||||
self.emit("reconnected")
|
||||
self.connected=True
|
||||
elif self.connected:
|
||||
@@ -414,9 +417,8 @@ class ArtistView(Gtk.ScrolledWindow):
|
||||
self.genre_select=genre_select
|
||||
|
||||
#artistStore
|
||||
#(name)
|
||||
self.store = Gtk.ListStore(str)
|
||||
self.store.set_sort_column_id(0, Gtk.SortType.ASCENDING)
|
||||
#(name, initial-letter, weight, font-scale)
|
||||
self.store = Gtk.ListStore(str, str, Pango.Weight, float)
|
||||
|
||||
#TreeView
|
||||
self.treeview = Gtk.TreeView(model=self.store)
|
||||
@@ -427,17 +429,24 @@ class ArtistView(Gtk.ScrolledWindow):
|
||||
self.selection = self.treeview.get_selection()
|
||||
self.selection.set_mode(Gtk.SelectionMode.MULTIPLE)
|
||||
|
||||
#Old Name Column
|
||||
#Columns
|
||||
renderer_text_malign = Gtk.CellRendererText(xalign=0.5)
|
||||
self.column_initials = Gtk.TreeViewColumn("", renderer_text_malign, text=1, weight=2, scale=3)
|
||||
self.column_initials.set_sizing(Gtk.TreeViewColumnSizing.AUTOSIZE)
|
||||
self.column_initials.set_property("resizable", False)
|
||||
self.column_initials.set_visible(self.settings.get_boolean("show-initials"))
|
||||
self.treeview.append_column(self.column_initials)
|
||||
|
||||
renderer_text = Gtk.CellRendererText()
|
||||
self.column_name = Gtk.TreeViewColumn("", renderer_text, text=0)
|
||||
self.column_name.set_sizing(Gtk.TreeViewColumnSizing.AUTOSIZE)
|
||||
self.column_name.set_property("resizable", False)
|
||||
self.column_name.set_sort_column_id(0)
|
||||
self.treeview.append_column(self.column_name)
|
||||
|
||||
#connect
|
||||
self.treeview.connect("enter-notify-event", self.on_enter_event)
|
||||
self.settings.connect("changed::show-all-artists", self.refresh)
|
||||
self.settings.connect("changed::show-initials", self.on_show_initials_settings_changed)
|
||||
self.update_signal=self.emitter.connect("update", self.refresh)
|
||||
|
||||
self.add(self.treeview)
|
||||
@@ -457,8 +466,16 @@ class ArtistView(Gtk.ScrolledWindow):
|
||||
artists=self.client.list(self.settings.get_artist_type())
|
||||
else:
|
||||
artists=self.client.list(self.settings.get_artist_type(), "genre", genre)
|
||||
current_char=""
|
||||
for artist in artists:
|
||||
self.store.append([artist])
|
||||
try:
|
||||
if current_char != artist[0]:
|
||||
self.store.append([artist, artist[0], Pango.Weight.BOLD, 1])
|
||||
current_char=artist[0]
|
||||
else:
|
||||
self.store.append([artist, "", Pango.Weight.BOOK, 1])
|
||||
except:
|
||||
self.store.append([artist, "", Pango.Weight.BOOK, 1])
|
||||
self.selection.set_mode(Gtk.SelectionMode.MULTIPLE)
|
||||
|
||||
def get_selected_artists(self):
|
||||
@@ -474,6 +491,9 @@ class ArtistView(Gtk.ScrolledWindow):
|
||||
def on_enter_event(self, widget, event):
|
||||
self.treeview.grab_focus()
|
||||
|
||||
def on_show_initials_settings_changed(self, *args):
|
||||
self.column_initials.set_visible(self.settings.get_boolean("show-initials"))
|
||||
|
||||
class AlbumIconView(Gtk.IconView):
|
||||
def __init__(self, client, settings, genre_select, window):
|
||||
Gtk.IconView.__init__(self)
|
||||
@@ -642,6 +662,9 @@ class AlbumView(Gtk.ScrolledWindow):
|
||||
self.iconview=AlbumIconView(self.client, self.settings, self.genre_select, self.window)
|
||||
self.iconview.connect("stopped", self.update)
|
||||
|
||||
#connect
|
||||
self.settings.connect("changed::album-cover", self.on_settings_changed)
|
||||
|
||||
self.add(self.iconview)
|
||||
|
||||
def update(self, *args):
|
||||
@@ -667,105 +690,34 @@ class AlbumView(Gtk.ScrolledWindow):
|
||||
def scroll_to_selected_album(self):
|
||||
self.iconview.scroll_to_selected_album()
|
||||
|
||||
class TrackView(Gtk.Box):
|
||||
def on_settings_changed(self, *args):
|
||||
artists=self.artists
|
||||
self.artists=[]
|
||||
self.refresh(artists)
|
||||
|
||||
class MainCover(Gtk.EventBox):
|
||||
def __init__(self, client, settings, emitter, window):
|
||||
Gtk.Box.__init__(self, orientation=Gtk.Orientation.VERTICAL)
|
||||
Gtk.EventBox.__init__(self)
|
||||
|
||||
#adding vars
|
||||
self.client=client
|
||||
self.settings = settings
|
||||
self.settings=settings
|
||||
self.emitter=emitter
|
||||
self.window=window
|
||||
self.hovered_songpos=None
|
||||
self.song_file=None
|
||||
self.playlist_version=None
|
||||
|
||||
#Store
|
||||
#(track, title, artist, album, duration, file)
|
||||
self.store = Gtk.ListStore(str, str, str, str, str, str)
|
||||
|
||||
#TreeView
|
||||
self.treeview = Gtk.TreeView(model=self.store)
|
||||
self.treeview.set_search_column(-1)
|
||||
self.treeview.columns_autosize()
|
||||
self.treeview.set_property("activate-on-single-click", True)
|
||||
|
||||
#selection
|
||||
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", True)
|
||||
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", True)
|
||||
self.treeview.append_column(self.column_artist)
|
||||
|
||||
self.column_duration = Gtk.TreeViewColumn(_("Length"), renderer_text, text=4)
|
||||
self.column_duration.set_sizing(Gtk.TreeViewColumnSizing.AUTOSIZE)
|
||||
self.column_duration.set_property("resizable", False)
|
||||
self.treeview.append_column(self.column_duration)
|
||||
|
||||
#scroll
|
||||
scroll=Gtk.ScrolledWindow()
|
||||
scroll.set_policy(Gtk.PolicyType.AUTOMATIC, Gtk.PolicyType.AUTOMATIC)
|
||||
scroll.add(self.treeview)
|
||||
|
||||
#cover
|
||||
self.cover=Gtk.Image.new()
|
||||
self.cover.set_from_pixbuf(Cover(client=self.client, lib_path=self.settings.get_value("paths")[self.settings.get_int("active-profile")], song_file=None).get_pixbuf(self.settings.get_int("track-cover"))) #set to fallback cover
|
||||
cover_event_box=Gtk.EventBox()
|
||||
cover_event_box.add(self.cover)
|
||||
|
||||
#audio infos
|
||||
audio=AudioType(self.client)
|
||||
|
||||
#playlist info
|
||||
self.playlist_info=Gtk.Label()
|
||||
self.playlist_info.set_xalign(0)
|
||||
self.playlist_info.set_ellipsize(Pango.EllipsizeMode.END)
|
||||
|
||||
#status bar
|
||||
status_bar=Gtk.Box(orientation=Gtk.Orientation.HORIZONTAL, spacing=10)
|
||||
status_bar.set_margin_start(4)
|
||||
status_bar.set_margin_end(4)
|
||||
status_bar.pack_start(self.playlist_info, True, True, 0)
|
||||
status_bar.pack_end(audio, False, False, 0)
|
||||
|
||||
#connect
|
||||
self.treeview.connect("row-activated", self.on_row_activated)
|
||||
self.treeview.connect("motion-notify-event", self.on_move_event)
|
||||
self.treeview.connect("leave-notify-event", self.on_focus_out_event)
|
||||
self.treeview.connect("focus-out-event", self.on_focus_out_event)
|
||||
self.key_press_event=self.treeview.connect("key-press-event", self.on_key_press_event)
|
||||
cover_event_box.connect("button-press-event", self.on_button_press_event)
|
||||
self.connect("button-press-event", self.on_button_press_event)
|
||||
self.player_changed=self.emitter.connect("player", self.refresh)
|
||||
self.settings.connect("changed::track-cover", self.on_settings_changed)
|
||||
|
||||
self.playlist_changed=self.emitter.connect("playlist", self.on_playlist_changed)
|
||||
self.player_changed=self.emitter.connect("player", self.on_player_changed)
|
||||
self.add(self.cover)
|
||||
|
||||
#packing
|
||||
self.pack_start(cover_event_box, False, False, 0)
|
||||
self.pack_start(scroll, True, True, 0)
|
||||
self.pack_end(status_bar, False, False, 0)
|
||||
|
||||
def scroll_to_selected_title(self):
|
||||
treeview, treeiter=self.selection.get_selected()
|
||||
if not treeiter == None:
|
||||
path=treeview.get_path(treeiter)
|
||||
self.treeview.scroll_to_cell(path)
|
||||
|
||||
def refresh_cover(self):
|
||||
def refresh(self, *args):
|
||||
try:
|
||||
song_file=self.client.currentsong()["file"]
|
||||
except:
|
||||
@@ -773,70 +725,6 @@ class TrackView(Gtk.Box):
|
||||
if not song_file == self.song_file:
|
||||
self.cover.set_from_pixbuf(Cover(client=self.client, lib_path=self.settings.get_value("paths")[self.settings.get_int("active-profile")], song_file=song_file).get_pixbuf(self.settings.get_int("track-cover")))
|
||||
self.song_file=song_file
|
||||
return True
|
||||
|
||||
def refresh_playlist_info(self):
|
||||
songs=self.client.playlistinfo()
|
||||
if not songs == []:
|
||||
whole_length=float(0)
|
||||
for song in songs:
|
||||
try:
|
||||
dura=float(song["duration"])
|
||||
except:
|
||||
dura=0.0
|
||||
whole_length=whole_length+dura
|
||||
whole_length_human_readable=str(datetime.timedelta(seconds=int(whole_length)))
|
||||
self.playlist_info.set_text(_("%(total_tracks)i titles (%(total_length)s)") % {"total_tracks": len(songs), "total_length": whole_length_human_readable})
|
||||
else:
|
||||
self.playlist_info.set_text("")
|
||||
|
||||
def refresh_selection(self): #Gtk.TreePath(len(self.store) is used to generate an invalid TreePath (needed to unset cursor)
|
||||
self.treeview.set_cursor(Gtk.TreePath(len(self.store)), None, False)
|
||||
try:
|
||||
song=self.client.status()["song"]
|
||||
path = Gtk.TreePath(int(song))
|
||||
self.selection.select_path(path)
|
||||
except:
|
||||
self.selection.unselect_all()
|
||||
self.refresh_cover()
|
||||
|
||||
def clear(self, *args):
|
||||
self.playlist_info.set_text("")
|
||||
self.store.clear()
|
||||
self.playlist_version=None
|
||||
self.cover.set_from_pixbuf(Cover(client=self.client, lib_path=self.settings.get_value("paths")[self.settings.get_int("active-profile")], song_file=None).get_pixbuf(self.settings.get_int("track-cover")))
|
||||
self.song_file=None
|
||||
|
||||
def on_key_press_event(self, widget, event):
|
||||
self.treeview.handler_block(self.key_press_event)
|
||||
if event.keyval == 65535: #entf
|
||||
if not self.hovered_songpos == None:
|
||||
try:
|
||||
self.client.delete(self.hovered_songpos) #bad song index possible
|
||||
self.store.remove(self.store.get_iter(self.hovered_songpos))
|
||||
self.playlist_version=self.client.status()["playlist"]
|
||||
except:
|
||||
self.hovered_songpos == None
|
||||
self.treeview.handler_unblock(self.key_press_event)
|
||||
|
||||
def on_move_event(self, widget, event):
|
||||
treeiter=self.selection.get_selected()[1]
|
||||
if not treeiter == None:
|
||||
self.treeview.grab_focus()
|
||||
return_tuple = self.treeview.get_path_at_pos(int(event.x), int(event.y))
|
||||
if not return_tuple == None:
|
||||
self.hovered_songpos=return_tuple[0]
|
||||
else:
|
||||
self.hovered_songpos=None
|
||||
|
||||
def on_focus_out_event(self, widget, event):
|
||||
self.refresh_selection()
|
||||
self.hovered_songpos=None
|
||||
|
||||
def on_row_activated(self, widget, path, view_column): #TODO
|
||||
treeiter=self.store.get_iter(path)
|
||||
selected_title=self.store.get_path(treeiter)
|
||||
self.client.play(selected_title)
|
||||
|
||||
def on_button_press_event(self, widget, event):
|
||||
if self.client.connected():
|
||||
@@ -869,6 +757,202 @@ class TrackView(Gtk.Box):
|
||||
self.client.album_to_playlist(album, artist, album_year, False, True)
|
||||
album_dialog.destroy()
|
||||
|
||||
def on_settings_changed(self, *args):
|
||||
self.song_file=None
|
||||
self.refresh()
|
||||
|
||||
def clear(self, *args):
|
||||
self.cover.set_from_pixbuf(Cover(client=self.client, lib_path=self.settings.get_value("paths")[self.settings.get_int("active-profile")], song_file=None).get_pixbuf(self.settings.get_int("track-cover")))
|
||||
self.song_file=None
|
||||
|
||||
class TrackView(Gtk.Box):
|
||||
def __init__(self, client, settings, emitter):
|
||||
Gtk.Box.__init__(self, orientation=Gtk.Orientation.VERTICAL)
|
||||
|
||||
#adding vars
|
||||
self.client=client
|
||||
self.settings=settings
|
||||
self.emitter=emitter
|
||||
self.hovered_songpos=None
|
||||
self.playlist_version=None
|
||||
self.last_song_iter=None
|
||||
|
||||
#Store
|
||||
#(track, disc, title, artist, album, duration, date, genre, file, weight)
|
||||
self.store = Gtk.ListStore(str, str, str, str, str, str, str, str, str, Pango.Weight)
|
||||
|
||||
#TreeView
|
||||
self.treeview = Gtk.TreeView(model=self.store)
|
||||
self.treeview.set_search_column(-1)
|
||||
self.treeview.set_property("activate-on-single-click", True)
|
||||
|
||||
#selection
|
||||
self.selection = self.treeview.get_selection()
|
||||
self.selection.set_mode(Gtk.SelectionMode.SINGLE)
|
||||
|
||||
#Column
|
||||
renderer_text = Gtk.CellRendererText()
|
||||
renderer_text_ralign = Gtk.CellRendererText(xalign=1.0)
|
||||
self.columns=[None, None, None, None, None, None, None, None]
|
||||
|
||||
self.columns[0] = Gtk.TreeViewColumn(_("No"), renderer_text_ralign, text=0, weight=9)
|
||||
self.columns[0].set_property("resizable", True)
|
||||
|
||||
self.columns[1] = Gtk.TreeViewColumn(_("Disc"), renderer_text_ralign, text=1, weight=9)
|
||||
self.columns[1].set_property("resizable", True)
|
||||
|
||||
self.columns[2] = Gtk.TreeViewColumn(_("Title"), renderer_text, text=2, weight=9)
|
||||
self.columns[2].set_property("resizable", True)
|
||||
|
||||
self.columns[3] = Gtk.TreeViewColumn(_("Artist"), renderer_text, text=3, weight=9)
|
||||
self.columns[3].set_property("resizable", True)
|
||||
|
||||
self.columns[4] = Gtk.TreeViewColumn(_("Album"), renderer_text, text=4, weight=9)
|
||||
self.columns[4].set_property("resizable", True)
|
||||
|
||||
self.columns[5] = Gtk.TreeViewColumn(_("Length"), renderer_text, text=5, weight=9)
|
||||
self.columns[5].set_property("resizable", True)
|
||||
|
||||
self.columns[6] = Gtk.TreeViewColumn(_("Year"), renderer_text, text=6, weight=9)
|
||||
self.columns[6].set_property("resizable", True)
|
||||
|
||||
self.columns[7] = Gtk.TreeViewColumn(_("Genre"), renderer_text, text=7, weight=9)
|
||||
self.columns[7].set_property("resizable", True)
|
||||
|
||||
self.load_settings()
|
||||
|
||||
#scroll
|
||||
scroll=Gtk.ScrolledWindow()
|
||||
scroll.set_policy(Gtk.PolicyType.AUTOMATIC, Gtk.PolicyType.AUTOMATIC)
|
||||
scroll.add(self.treeview)
|
||||
|
||||
#audio infos
|
||||
audio=AudioType(self.client)
|
||||
|
||||
#playlist info
|
||||
self.playlist_info=Gtk.Label()
|
||||
self.playlist_info.set_xalign(0)
|
||||
self.playlist_info.set_ellipsize(Pango.EllipsizeMode.END)
|
||||
|
||||
#status bar
|
||||
status_bar=Gtk.Box(orientation=Gtk.Orientation.HORIZONTAL, spacing=10)
|
||||
status_bar.set_margin_start(4)
|
||||
status_bar.set_margin_end(4)
|
||||
status_bar.pack_start(self.playlist_info, True, True, 0)
|
||||
status_bar.pack_end(audio, False, False, 0)
|
||||
|
||||
#connect
|
||||
self.treeview.connect("row-activated", self.on_row_activated)
|
||||
self.treeview.connect("motion-notify-event", self.on_move_event)
|
||||
self.treeview.connect("leave-notify-event", self.on_focus_out_event)
|
||||
self.treeview.connect("focus-out-event", self.on_focus_out_event)
|
||||
self.key_press_event=self.treeview.connect("key-press-event", self.on_key_press_event)
|
||||
|
||||
self.playlist_changed=self.emitter.connect("playlist", self.on_playlist_changed)
|
||||
self.player_changed=self.emitter.connect("player", self.on_player_changed)
|
||||
self.disconnected_signal=self.emitter.connect("disconnected", self.on_disconnected)
|
||||
|
||||
self.settings.connect("changed::column-visibilities", self.load_settings)
|
||||
self.settings.connect("changed::column-permutation", self.load_settings)
|
||||
|
||||
#packing
|
||||
self.pack_start(scroll, True, True, 0)
|
||||
self.pack_end(status_bar, False, False, 0)
|
||||
|
||||
def save_settings(self): #only saves the column sizes
|
||||
columns=self.treeview.get_columns()
|
||||
permutation=self.settings.get_value("column-permutation").unpack()
|
||||
sizes=[0] * len(permutation)
|
||||
for i in range(len(permutation)):
|
||||
sizes[permutation[i]]=columns[i].get_width()
|
||||
self.settings.set_value("column-sizes", GLib.Variant("ai", sizes))
|
||||
|
||||
def load_settings(self, *args):
|
||||
columns=self.treeview.get_columns()
|
||||
for column in columns:
|
||||
self.treeview.remove_column(column)
|
||||
sizes=self.settings.get_value("column-sizes").unpack()
|
||||
visibilities=self.settings.get_value("column-visibilities").unpack()
|
||||
for i in self.settings.get_value("column-permutation"):
|
||||
if sizes[i] > 0:
|
||||
self.columns[i].set_fixed_width(sizes[i])
|
||||
self.columns[i].set_visible(visibilities[i])
|
||||
self.treeview.append_column(self.columns[i])
|
||||
|
||||
def scroll_to_selected_title(self):
|
||||
treeview, treeiter=self.selection.get_selected()
|
||||
if not treeiter == None:
|
||||
path=treeview.get_path(treeiter)
|
||||
self.treeview.scroll_to_cell(path)
|
||||
|
||||
def refresh_playlist_info(self):
|
||||
songs=self.client.playlistinfo()
|
||||
if not songs == []:
|
||||
whole_length=float(0)
|
||||
for song in songs:
|
||||
try:
|
||||
dura=float(song["duration"])
|
||||
except:
|
||||
dura=0.0
|
||||
whole_length=whole_length+dura
|
||||
whole_length_human_readable=str(datetime.timedelta(seconds=int(whole_length)))
|
||||
self.playlist_info.set_text(_("%(total_tracks)i titles (%(total_length)s)") % {"total_tracks": len(songs), "total_length": whole_length_human_readable})
|
||||
else:
|
||||
self.playlist_info.set_text("")
|
||||
|
||||
def refresh_selection(self): #Gtk.TreePath(len(self.store) is used to generate an invalid TreePath (needed to unset cursor)
|
||||
self.treeview.set_cursor(Gtk.TreePath(len(self.store)), None, False)
|
||||
try:
|
||||
song=self.client.status()["song"]
|
||||
path = Gtk.TreePath(int(song))
|
||||
self.selection.select_path(path)
|
||||
if self.last_song_iter != None and self.store.iter_is_valid(self.last_song_iter):
|
||||
self.store.set_value(self.last_song_iter, 9, Pango.Weight.BOOK)
|
||||
treeiter=self.store.get_iter(path)
|
||||
self.store.set_value(treeiter, 9, Pango.Weight.BOLD)
|
||||
self.last_song_iter=treeiter
|
||||
except:
|
||||
if self.last_song_iter != None:
|
||||
self.store.set_value(self.last_song_iter, 9, Pango.Weight.BOOK)
|
||||
self.last_song_iter=None
|
||||
self.selection.unselect_all()
|
||||
|
||||
def clear(self, *args):
|
||||
self.playlist_info.set_text("")
|
||||
self.store.clear()
|
||||
self.playlist_version=None
|
||||
|
||||
def on_key_press_event(self, widget, event):
|
||||
self.treeview.handler_block(self.key_press_event)
|
||||
if event.keyval == 65535: #entf
|
||||
if not self.hovered_songpos == None:
|
||||
try:
|
||||
self.client.delete(self.hovered_songpos) #bad song index possible
|
||||
self.store.remove(self.store.get_iter(self.hovered_songpos))
|
||||
self.playlist_version=self.client.status()["playlist"]
|
||||
except:
|
||||
self.hovered_songpos == None
|
||||
self.treeview.handler_unblock(self.key_press_event)
|
||||
|
||||
def on_move_event(self, widget, event):
|
||||
treeiter=self.selection.get_selected()[1]
|
||||
if not treeiter == None:
|
||||
self.treeview.grab_focus()
|
||||
return_tuple = self.treeview.get_path_at_pos(int(event.x), int(event.y))
|
||||
if not return_tuple == None:
|
||||
self.hovered_songpos=return_tuple[0]
|
||||
else:
|
||||
self.hovered_songpos=None
|
||||
|
||||
def on_focus_out_event(self, widget, event):
|
||||
self.refresh_selection()
|
||||
self.hovered_songpos=None
|
||||
|
||||
def on_row_activated(self, widget, path, view_column): #TODO
|
||||
treeiter=self.store.get_iter(path)
|
||||
selected_title=self.store.get_path(treeiter)
|
||||
self.client.play(selected_title)
|
||||
|
||||
def on_playlist_changed(self, *args):
|
||||
songs=[]
|
||||
if not self.playlist_version == None:
|
||||
@@ -883,9 +967,13 @@ class TrackView(Gtk.Box):
|
||||
except:
|
||||
title=_("Unknown Title")
|
||||
try:
|
||||
track=song["track"].zfill(2)
|
||||
track=song["track"]
|
||||
except:
|
||||
track="00"
|
||||
track="0"
|
||||
try:
|
||||
disc=song["disc"]
|
||||
except:
|
||||
disc=""
|
||||
try:
|
||||
artist=song["artist"]
|
||||
except:
|
||||
@@ -898,30 +986,42 @@ class TrackView(Gtk.Box):
|
||||
dura=float(song["duration"])
|
||||
except:
|
||||
dura=0.0
|
||||
try:
|
||||
year=song["date"]
|
||||
except:
|
||||
year=""
|
||||
try:
|
||||
genre=song["genre"]
|
||||
except:
|
||||
genre=""
|
||||
duration=str(datetime.timedelta(seconds=int(dura )))
|
||||
try:
|
||||
treeiter=self.store.get_iter(song["pos"])
|
||||
self.store.set(treeiter, 0, track, 1, title, 2, artist, 3, album, 4, duration, 5, song["file"])
|
||||
self.store.set(treeiter, 0, track, 1, disc, 2, title, 3, artist, 4, album, 5, duration, 6, year, 7, genre, 8, song["file"], 9, Pango.Weight.BOOK)
|
||||
except:
|
||||
self.store.append([track, title, artist, album, duration, song["file"]])
|
||||
for i in reversed(range(int(self.client.status()["playlistlength"]), len(self.store))):
|
||||
treeiter=self.store.get_iter(i)
|
||||
self.store.remove(treeiter)
|
||||
self.refresh_playlist_info()
|
||||
self.refresh_selection()
|
||||
self.store.append([track, disc, title, artist, album, duration, year, genre, song["file"], Pango.Weight.BOOK])
|
||||
for i in reversed(range(int(self.client.status()["playlistlength"]), len(self.store))):
|
||||
treeiter=self.store.get_iter(i)
|
||||
self.store.remove(treeiter)
|
||||
self.refresh_playlist_info()
|
||||
self.refresh_selection()
|
||||
self.playlist_version=self.client.status()["playlist"]
|
||||
|
||||
def on_player_changed(self, *args):
|
||||
if not self.client.song_to_delete == "": #TODO should be in Client class
|
||||
status=self.client.status()
|
||||
if not status["song"] == "0" and self.client.playlistinfo()[0]["file"] == self.client.song_to_delete:
|
||||
self.client.delete(0)
|
||||
if not status["song"] == "0":
|
||||
if self.client.playlistinfo()[0]["file"] == self.client.song_to_delete:
|
||||
self.client.delete(0)
|
||||
self.client.song_to_delete=""
|
||||
else:
|
||||
self.refresh_selection()
|
||||
self.client.song_to_delete=""
|
||||
else:
|
||||
self.refresh_selection()
|
||||
|
||||
def on_disconnected(self, *args):
|
||||
self.playlist_version=None
|
||||
|
||||
class Browser(Gtk.Box):
|
||||
def __init__(self, client, settings, emitter, window):
|
||||
Gtk.Box.__init__(self, orientation=Gtk.Orientation.VERTICAL, spacing=4)
|
||||
@@ -939,31 +1039,42 @@ class Browser(Gtk.Box):
|
||||
self.genre_select.set_margin_top(2)
|
||||
self.artist_list=ArtistView(self.client, self.settings, self.emitter, self.genre_select)
|
||||
self.album_list=AlbumView(self.client, self.settings, self.genre_select, self.window)
|
||||
self.title_list=TrackView(self.client, self.settings, self.emitter, self.window)
|
||||
self.main_cover=MainCover(self.client, self.settings, self.emitter, self.window)
|
||||
self.main_cover.set_property("border-width", 5)
|
||||
cover_frame=Gtk.Frame()
|
||||
cover_frame.add(self.main_cover)
|
||||
self.title_list=TrackView(self.client, self.settings, self.emitter)
|
||||
|
||||
#connect
|
||||
self.artist_change=self.artist_list.selection.connect("changed", self.on_artist_selection_change)
|
||||
self.settings.connect("changed::show-genre-filter", self.on_settings_changed)
|
||||
self.settings.connect("changed::show-genre-filter", self.on_show_genre_settings_changed)
|
||||
self.settings.connect("changed::alt-layout", self.on_layout_settings_changed)
|
||||
|
||||
#packing
|
||||
self.vbox=Gtk.Box(orientation=Gtk.Orientation.VERTICAL, spacing=4)
|
||||
self.box1=Gtk.Box(orientation=Gtk.Orientation.VERTICAL, spacing=4)
|
||||
if self.settings.get_boolean("show-genre-filter"):
|
||||
self.vbox.pack_start(self.genre_select, False, False, 0)
|
||||
self.vbox.pack_start(self.artist_list, True, True, 0)
|
||||
self.box1.pack_start(self.genre_select, False, False, 0)
|
||||
self.box1.pack_start(self.artist_list, True, True, 0)
|
||||
self.box2=Gtk.Box(orientation=Gtk.Orientation.VERTICAL, spacing=0)
|
||||
self.box2.pack_start(cover_frame, False, False, 0)
|
||||
self.box2.pack_start(self.title_list, True, True, 0)
|
||||
self.paned1=Gtk.Paned.new(Gtk.Orientation.HORIZONTAL)
|
||||
self.paned1.set_wide_handle(True)
|
||||
self.paned2=Gtk.Paned.new(Gtk.Orientation.HORIZONTAL)
|
||||
self.paned2.set_wide_handle(True)
|
||||
self.paned1.pack1(self.vbox, False, False)
|
||||
self.paned1.pack1(self.box1, False, False)
|
||||
self.paned1.pack2(self.album_list, True, False)
|
||||
self.paned2.pack1(self.paned1, True, False)
|
||||
self.paned2.pack2(self.title_list, False, False)
|
||||
self.paned2.pack2(self.box2, False, False)
|
||||
self.load_settings()
|
||||
self.pack_start(self.paned2, True, True, 0)
|
||||
|
||||
self.on_layout_settings_changed()
|
||||
|
||||
def save_settings(self):
|
||||
self.settings.set_int("paned1", self.paned1.get_position())
|
||||
self.settings.set_int("paned2", self.paned2.get_position())
|
||||
self.title_list.save_settings()
|
||||
|
||||
def load_settings(self):
|
||||
self.paned1.set_position(self.settings.get_int("paned1"))
|
||||
@@ -975,6 +1086,7 @@ class Browser(Gtk.Box):
|
||||
self.artist_list.selection.handler_unblock(self.artist_change)
|
||||
self.album_list.clear()
|
||||
self.title_list.clear()
|
||||
self.main_cover.clear()
|
||||
|
||||
def go_home(self, *args): #TODO
|
||||
try:
|
||||
@@ -1000,14 +1112,22 @@ class Browser(Gtk.Box):
|
||||
artists=self.artist_list.get_selected_artists()
|
||||
self.album_list.refresh(artists)
|
||||
|
||||
def on_settings_changed(self, *args):
|
||||
def on_show_genre_settings_changed(self, *args):
|
||||
if self.settings.get_boolean("show-genre-filter"):
|
||||
self.vbox.pack_start(self.genre_select, False, False, 0)
|
||||
self.vbox.reorder_child(self.genre_select, 0)
|
||||
self.box1.pack_start(self.genre_select, False, False, 0)
|
||||
self.box1.reorder_child(self.genre_select, 0)
|
||||
self.genre_select.show_all()
|
||||
else:
|
||||
self.genre_select.deactivate()
|
||||
self.vbox.remove(self.genre_select)
|
||||
self.box1.remove(self.genre_select)
|
||||
|
||||
def on_layout_settings_changed(self, *args):
|
||||
if self.settings.get_boolean("alt-layout"):
|
||||
self.box2.set_orientation(Gtk.Orientation.HORIZONTAL)
|
||||
self.paned2.set_orientation(Gtk.Orientation.VERTICAL)
|
||||
else:
|
||||
self.box2.set_orientation(Gtk.Orientation.VERTICAL)
|
||||
self.paned2.set_orientation(Gtk.Orientation.HORIZONTAL)
|
||||
|
||||
class ProfileSettings(Gtk.Grid):
|
||||
def __init__(self, parent, settings):
|
||||
@@ -1028,7 +1148,7 @@ class ProfileSettings(Gtk.Grid):
|
||||
|
||||
self.profile_entry=Gtk.Entry()
|
||||
self.host_entry=Gtk.Entry()
|
||||
self.port_entry=IntEntry(0, 0, 65535)
|
||||
self.port_entry=IntEntry(0, 0, 65535, 1)
|
||||
self.password_entry=Gtk.Entry()
|
||||
self.password_entry.set_visibility(False)
|
||||
self.path_select_button=Gtk.Button(label=_("Select"), image=Gtk.Image(stock=Gtk.STOCK_OPEN))
|
||||
@@ -1174,8 +1294,8 @@ class GeneralSettings(Gtk.Grid):
|
||||
album_cover_label=Gtk.Label(label=_("Album-view cover size:"))
|
||||
album_cover_label.set_xalign(1)
|
||||
|
||||
track_cover_size=IntEntry(self.settings.get_int("track-cover"), 100, 1200)
|
||||
album_cover_size=IntEntry(self.settings.get_int("album-cover"), 50, 600)
|
||||
track_cover_size=IntEntry(self.settings.get_int("track-cover"), 100, 1200, 10)
|
||||
album_cover_size=IntEntry(self.settings.get_int("album-cover"), 50, 600, 10)
|
||||
|
||||
icon_size_label=Gtk.Label(label=_("Button icon size (restart required):"))
|
||||
icon_size_label.set_xalign(1)
|
||||
@@ -1186,42 +1306,46 @@ class GeneralSettings(Gtk.Grid):
|
||||
icon_size_combo.append_text(str(i))
|
||||
icon_size_combo.set_active(sizes.index(self.settings.get_int("icon-size")))
|
||||
|
||||
show_stop=Gtk.CheckButton(label=_("Show stop button"))
|
||||
show_stop.set_active(self.settings.get_boolean("show-stop"))
|
||||
#Store
|
||||
#(toggle, display-text, key)
|
||||
self.store = Gtk.ListStore(bool, str, str)
|
||||
|
||||
show_genre_filter=Gtk.CheckButton(label=_("Show genre filter"))
|
||||
show_genre_filter.set_active(self.settings.get_boolean("show-genre-filter"))
|
||||
#TreeView
|
||||
self.treeview = Gtk.TreeView(model=self.store)
|
||||
self.treeview.set_search_column(-1)
|
||||
self.treeview.set_property("activate-on-single-click", True)
|
||||
self.treeview.set_headers_visible(False)
|
||||
|
||||
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"))
|
||||
#selection
|
||||
self.selection = self.treeview.get_selection()
|
||||
self.selection.set_mode(Gtk.SelectionMode.NONE)
|
||||
|
||||
sort_albums_by_year=Gtk.CheckButton(label=_("Sort albums by year"))
|
||||
sort_albums_by_year.set_active(self.settings.get_boolean("sort-albums-by-year"))
|
||||
#Column
|
||||
renderer_text = Gtk.CellRendererText()
|
||||
renderer_toggle = Gtk.CellRendererToggle()
|
||||
|
||||
show_all_artists=Gtk.CheckButton(label=_("Show all artists"))
|
||||
show_all_artists.set_active(self.settings.get_boolean("show-all-artists"))
|
||||
column_toggle=Gtk.TreeViewColumn("", renderer_toggle, active=0)
|
||||
self.treeview.append_column(column_toggle)
|
||||
|
||||
send_notify=Gtk.CheckButton(label=_("Send notification on title change"))
|
||||
send_notify.set_active(self.settings.get_boolean("send-notify"))
|
||||
column_text=Gtk.TreeViewColumn("", renderer_text, text=1)
|
||||
self.treeview.append_column(column_text)
|
||||
|
||||
stop_on_quit=Gtk.CheckButton(label=_("Stop playback on quit"))
|
||||
stop_on_quit.set_active(self.settings.get_boolean("stop-on-quit"))
|
||||
#fill store
|
||||
settings_list=[(_("Use alternative layout"), "alt-layout"), (_("Show stop button"), "show-stop"), \
|
||||
(_("Show genre filter"), "show-genre-filter"), (_("Show initials in artist view"), "show-initials"), \
|
||||
(_("Show tooltips in album view"), "show-album-view-tooltips"), \
|
||||
(_("Sort albums by year"), "sort-albums-by-year"), (_("Show all artists"), "show-all-artists"), \
|
||||
(_("Send notification on title change"), "send-notify"), (_("Stop playback on quit"), "stop-on-quit"), \
|
||||
(_("Play selected album after current title"), "add-album")]
|
||||
|
||||
add_album=Gtk.CheckButton(label=_("Play selected album after current title"))
|
||||
add_album.set_active(self.settings.get_boolean("add-album"))
|
||||
for data in settings_list:
|
||||
self.store.append([self.settings.get_boolean(data[1]), data[0], data[1]])
|
||||
|
||||
#connect
|
||||
track_cover_size.connect("value-changed", self.on_int_changed, "track-cover")
|
||||
album_cover_size.connect("value-changed", self.on_int_changed, "album-cover")
|
||||
icon_size_combo.connect("changed", self.on_icon_size_changed)
|
||||
show_stop.connect("toggled", self.on_toggled, "show-stop")
|
||||
show_genre_filter.connect("toggled", self.on_toggled, "show-genre-filter")
|
||||
show_album_view_tooltips.connect("toggled", self.on_toggled, "show-album-view-tooltips")
|
||||
sort_albums_by_year.connect("toggled", self.on_toggled, "sort-albums-by-year")
|
||||
show_all_artists.connect("toggled", self.on_toggled, "show-all-artists")
|
||||
send_notify.connect("toggled", self.on_toggled, "send-notify")
|
||||
stop_on_quit.connect("toggled", self.on_toggled, "stop-on-quit")
|
||||
add_album.connect("toggled", self.on_toggled, "add-album")
|
||||
self.treeview.connect("row-activated", self.on_row_activated)
|
||||
|
||||
#packing
|
||||
self.add(track_cover_label)
|
||||
@@ -1230,25 +1354,79 @@ class GeneralSettings(Gtk.Grid):
|
||||
self.attach_next_to(track_cover_size, track_cover_label, Gtk.PositionType.RIGHT, 1, 1)
|
||||
self.attach_next_to(album_cover_size, album_cover_label, Gtk.PositionType.RIGHT, 1, 1)
|
||||
self.attach_next_to(icon_size_combo, icon_size_label, Gtk.PositionType.RIGHT, 1, 1)
|
||||
self.attach_next_to(show_stop, icon_size_label, Gtk.PositionType.BOTTOM, 2, 1)
|
||||
self.attach_next_to(show_genre_filter, show_stop, Gtk.PositionType.BOTTOM, 2, 1)
|
||||
self.attach_next_to(show_album_view_tooltips, show_genre_filter, Gtk.PositionType.BOTTOM, 2, 1)
|
||||
self.attach_next_to(sort_albums_by_year, show_album_view_tooltips, Gtk.PositionType.BOTTOM, 2, 1)
|
||||
self.attach_next_to(show_all_artists, sort_albums_by_year, Gtk.PositionType.BOTTOM, 2, 1)
|
||||
self.attach_next_to(send_notify, show_all_artists, Gtk.PositionType.BOTTOM, 2, 1)
|
||||
self.attach_next_to(add_album, send_notify, Gtk.PositionType.BOTTOM, 2, 1)
|
||||
self.attach_next_to(stop_on_quit, add_album, Gtk.PositionType.BOTTOM, 2, 1)
|
||||
self.attach_next_to(self.treeview, icon_size_label, Gtk.PositionType.BOTTOM, 2, 2)
|
||||
|
||||
def on_int_changed(self, widget, key):
|
||||
self.settings.set_int(key, widget.get_int())
|
||||
|
||||
def on_toggled(self, widget, key):
|
||||
self.settings.set_boolean(key, widget.get_active())
|
||||
|
||||
def on_icon_size_changed(self, box):
|
||||
active_size=int(box.get_active_text())
|
||||
self.settings.set_int("icon-size", active_size)
|
||||
|
||||
def on_row_activated(self, widget, path, view_column): #TODO
|
||||
self.store[path][0] = not self.store[path][0]
|
||||
self.settings.set_boolean(self.store[path][2], self.store[path][0])
|
||||
|
||||
class PlaylistSettings(Gtk.Box):
|
||||
def __init__(self, settings):
|
||||
Gtk.Box.__init__(self, orientation=Gtk.Orientation.VERTICAL, spacing=4)
|
||||
self.set_property("border-width", 4)
|
||||
|
||||
#adding vars
|
||||
self.settings = settings
|
||||
|
||||
#label
|
||||
label=Gtk.Label(label=_("Drag & Drop to rearange"))
|
||||
label.set_line_wrap(True)
|
||||
|
||||
#Store
|
||||
#(toggle, header, index)
|
||||
self.store = Gtk.ListStore(bool, str, int)
|
||||
|
||||
#TreeView
|
||||
self.treeview = Gtk.TreeView(model=self.store)
|
||||
self.treeview.set_search_column(-1)
|
||||
self.treeview.set_reorderable(True)
|
||||
|
||||
#Column
|
||||
renderer_text = Gtk.CellRendererText()
|
||||
renderer_toggle = Gtk.CellRendererToggle()
|
||||
|
||||
column_toggle=Gtk.TreeViewColumn("", renderer_toggle, active=0)
|
||||
self.treeview.append_column(column_toggle)
|
||||
|
||||
column_text=Gtk.TreeViewColumn(_("Column"), renderer_text, text=1)
|
||||
self.treeview.append_column(column_text)
|
||||
|
||||
#fill store
|
||||
self.headers=[_("No"), _("Disc"), _("Title"), _("Artist"), _("Album"), _("Length"), _("Year"), _("Genre")]
|
||||
visibilities=self.settings.get_value("column-visibilities").unpack()
|
||||
|
||||
for index in self.settings.get_value("column-permutation"):
|
||||
self.store.append([visibilities[index], self.headers[index], index])
|
||||
|
||||
#connect
|
||||
self.store.connect("row-deleted", self.on_row_inserted)
|
||||
renderer_toggle.connect("toggled", self.on_cell_toggled)
|
||||
|
||||
#scroll
|
||||
scroll=Gtk.ScrolledWindow()
|
||||
scroll.set_policy(Gtk.PolicyType.AUTOMATIC, Gtk.PolicyType.AUTOMATIC)
|
||||
scroll.add(self.treeview)
|
||||
|
||||
self.pack_start(scroll, True, True, 0)
|
||||
self.pack_start(label, False, False, 0)
|
||||
|
||||
def on_cell_toggled(self, widget, path):
|
||||
self.store[path][0] = not self.store[path][0]
|
||||
self.settings.array_modify('ab', "column-visibilities", self.store[path][2], self.store[path][0])
|
||||
|
||||
def on_row_inserted(self, *args):
|
||||
permutation=[]
|
||||
for row in self.store:
|
||||
permutation.append(row[2])
|
||||
self.settings.set_value("column-permutation", GLib.Variant("ai", permutation))
|
||||
|
||||
class SettingsDialog(Gtk.Dialog):
|
||||
def __init__(self, parent, settings):
|
||||
Gtk.Dialog.__init__(self, title=_("Settings"), transient_for=parent)
|
||||
@@ -1261,11 +1439,13 @@ class SettingsDialog(Gtk.Dialog):
|
||||
#widgets
|
||||
general=GeneralSettings(self.settings)
|
||||
profiles=ProfileSettings(parent, self.settings)
|
||||
playlist=PlaylistSettings(self.settings)
|
||||
|
||||
#packing
|
||||
tabs = Gtk.Notebook()
|
||||
tabs.append_page(general, Gtk.Label(label=_("General")))
|
||||
tabs.append_page(profiles, Gtk.Label(label=_("Profiles")))
|
||||
tabs.append_page(playlist, Gtk.Label(label=_("Playlist")))
|
||||
self.vbox.pack_start(tabs, True, True, 0) #vbox default widget of dialogs
|
||||
self.vbox.set_spacing(6)
|
||||
|
||||
@@ -1407,17 +1587,23 @@ class SeekBar(Gtk.Box):
|
||||
pos=(duration*factor)
|
||||
self.client.seekcur(pos)
|
||||
|
||||
def seek_forward(self):
|
||||
self.client.seekcur("+"+self.seek_time)
|
||||
|
||||
def seek_backward(self):
|
||||
self.client.seekcur("-"+self.seek_time)
|
||||
|
||||
def on_elapsed_button_press_event(self, widget, event):
|
||||
if event.button == 1:
|
||||
self.client.seekcur("-"+self.seek_time)
|
||||
self.seek_backward()
|
||||
elif event.button == 3:
|
||||
self.client.seekcur("+"+self.seek_time)
|
||||
self.seek_forward()
|
||||
|
||||
def on_rest_button_press_event(self, widget, event):
|
||||
if event.button == 1:
|
||||
self.client.seekcur("+"+self.seek_time)
|
||||
self.seek_forward()
|
||||
elif event.button == 3:
|
||||
self.client.seekcur("-"+self.seek_time)
|
||||
self.seek_backward()
|
||||
|
||||
def update(self):
|
||||
try:
|
||||
@@ -1570,6 +1756,7 @@ class AudioType(Gtk.EventBox):
|
||||
|
||||
#TreeView
|
||||
self.treeview = Gtk.TreeView(model=self.store)
|
||||
self.treeview.set_can_focus(False)
|
||||
self.treeview.set_search_column(-1)
|
||||
sel = self.treeview.get_selection()
|
||||
sel.set_mode(Gtk.SelectionMode.NONE)
|
||||
@@ -1674,6 +1861,7 @@ class ServerStats(Gtk.Dialog):
|
||||
|
||||
#TreeView
|
||||
self.treeview = Gtk.TreeView(model=self.store)
|
||||
self.treeview.set_can_focus(False)
|
||||
self.treeview.set_search_column(-1)
|
||||
sel = self.treeview.get_selection()
|
||||
sel.set_mode(Gtk.SelectionMode.NONE)
|
||||
@@ -1909,6 +2097,7 @@ class LyricsWindow(Gtk.Window):
|
||||
class MainWindow(Gtk.ApplicationWindow):
|
||||
def __init__(self, app, client, settings, emitter):
|
||||
Gtk.ApplicationWindow.__init__(self, title=("mpdevil"), application=app)
|
||||
Notify.init("mpdevil")
|
||||
self.set_icon_name("mpdevil")
|
||||
self.settings = settings
|
||||
self.set_default_size(self.settings.get_int("width"), self.settings.get_int("height"))
|
||||
@@ -1918,6 +2107,7 @@ class MainWindow(Gtk.ApplicationWindow):
|
||||
self.client=client
|
||||
self.emitter=emitter
|
||||
self.icon_size=self.settings.get_gtk_icon_size("icon-size")
|
||||
self.song_file=None
|
||||
|
||||
#actions
|
||||
save_action = Gio.SimpleAction.new("save", None)
|
||||
@@ -1955,7 +2145,7 @@ class MainWindow(Gtk.ApplicationWindow):
|
||||
|
||||
#menu
|
||||
menu = Gio.Menu()
|
||||
menu.append(_("Save window size"), "win.save")
|
||||
menu.append(_("Save window layout"), "win.save")
|
||||
menu.append(_("Settings"), "win.settings")
|
||||
menu.append(_("Update database"), "win.update")
|
||||
menu.append(_("Server stats"), "win.stats")
|
||||
@@ -2010,12 +2200,16 @@ class MainWindow(Gtk.ApplicationWindow):
|
||||
if status["songid"] == None:
|
||||
self.set_title("mpdevil")
|
||||
else:
|
||||
song=self.client.playlistid(status["songid"])[0]
|
||||
self.set_title(song["artist"]+" - "+song["title"]+" - "+song["album"])
|
||||
if not self.is_active() and self.settings.get_boolean("send-notify") and status["state"] == "play":
|
||||
notify=Gio.Notification.new(title=song["title"])
|
||||
notify.set_body(song["artist"]+"\n"+song["album"])
|
||||
self.app.send_notification(None, notify)
|
||||
song=self.client.currentsong()
|
||||
if song["file"] != self.song_file:
|
||||
self.set_title(song["artist"]+" - "+song["title"]+" - "+song["album"])
|
||||
if self.settings.get_boolean("send-notify"):
|
||||
if not self.is_active() and status["state"] == "play":
|
||||
notify=Notify.Notification.new(song["title"], song["artist"]+"\n"+song["album"])
|
||||
pixbuf=Cover(client=self.client, lib_path=self.settings.get_value("paths")[self.settings.get_int("active-profile")], song_file=song["file"]).get_pixbuf(400)
|
||||
notify.set_image_from_pixbuf(pixbuf)
|
||||
notify.show()
|
||||
self.song_file=song["file"]
|
||||
except:
|
||||
self.set_title("mpdevil")
|
||||
|
||||
@@ -2078,6 +2272,10 @@ class MainWindow(Gtk.ApplicationWindow):
|
||||
self.control.prev_button.emit("clicked")
|
||||
elif event.keyval == 65307: #esc
|
||||
self.go_home_button.emit("clicked")
|
||||
elif event.keyval == 65450: #*
|
||||
self.progress.seek_forward()
|
||||
elif event.keyval == 65455: #/
|
||||
self.progress.seek_backward()
|
||||
|
||||
def on_save(self, action, param):
|
||||
size=self.get_size()
|
||||
|
@@ -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.6.0])
|
||||
AC_INIT([mpdevil], [0.7.0])
|
||||
AC_CONFIG_SRCDIR([bin/mpdevil.py])
|
||||
AM_INIT_AUTOMAKE
|
||||
AC_CONFIG_MACRO_DIR([m4])
|
||||
|
@@ -46,6 +46,11 @@
|
||||
<summary>Show genre filter</summary>
|
||||
<description></description>
|
||||
</key>
|
||||
<key type="b" name="show-initials">
|
||||
<default>true</default>
|
||||
<summary>Show initial letters in artist-view</summary>
|
||||
<description></description>
|
||||
</key>
|
||||
<key type="b" name="show-album-view-tooltips">
|
||||
<default>true</default>
|
||||
<summary>Show tooltips in album-view</summary>
|
||||
@@ -76,6 +81,26 @@
|
||||
<summary>Show all artists instead of albumartists</summary>
|
||||
<description></description>
|
||||
</key>
|
||||
<key type="ai" name="column-permutation">
|
||||
<default>[0, 1, 2, 3, 4, 5, 6, 7]</default>
|
||||
<summary>Column order in playlist</summary>
|
||||
<description></description>
|
||||
</key>
|
||||
<key type="ab" name="column-visibilities">
|
||||
<default>[true, false, true, true, false, true, false, false]</default>
|
||||
<summary>Visibility of columns in playlist</summary>
|
||||
<description></description>
|
||||
</key>
|
||||
<key type="ai" name="column-sizes">
|
||||
<default>[0, 0, 0, 0, 0, 0, 0, 0]</default>
|
||||
<summary>Sizes of columns in playlist</summary>
|
||||
<description></description>
|
||||
</key>
|
||||
<key type="b" name="alt-layout">
|
||||
<default>false</default>
|
||||
<summary>Use alternative layout</summary>
|
||||
<description></description>
|
||||
</key>
|
||||
<key type="i" name="active-profile">
|
||||
<default>0</default>
|
||||
<summary>Active profile</summary>
|
||||
|
164
po/de.po
164
po/de.po
@@ -7,8 +7,8 @@ msgid ""
|
||||
msgstr ""
|
||||
"Project-Id-Version: \n"
|
||||
"Report-Msgid-Bugs-To: \n"
|
||||
"POT-Creation-Date: 2020-02-28 23:22+0100\n"
|
||||
"PO-Revision-Date: 2020-02-28 23:23+0100\n"
|
||||
"POT-Creation-Date: 2020-03-12 17:05+0100\n"
|
||||
"PO-Revision-Date: 2020-03-12 17:06+0100\n"
|
||||
"Last-Translator: \n"
|
||||
"Language-Team: \n"
|
||||
"Language: de\n"
|
||||
@@ -18,164 +18,200 @@ msgstr ""
|
||||
"X-Generator: Poedit 2.2.4\n"
|
||||
"Plural-Forms: nplurals=2; plural=(n != 1);\n"
|
||||
|
||||
#: mpdevil.py:290 mpdevil.py:700 mpdevil.py:1735
|
||||
#: mpdevil.py:293 mpdevil.py:798 mpdevil.py:1402 mpdevil.py:1930
|
||||
msgid "No"
|
||||
msgstr "Nr."
|
||||
|
||||
#: mpdevil.py:295 mpdevil.py:705 mpdevil.py:1741
|
||||
#: mpdevil.py:298 mpdevil.py:804 mpdevil.py:1402 mpdevil.py:1936
|
||||
msgid "Title"
|
||||
msgstr "Titel"
|
||||
|
||||
#: mpdevil.py:300 mpdevil.py:454 mpdevil.py:710 mpdevil.py:1747
|
||||
#: mpdevil.py:303 mpdevil.py:463 mpdevil.py:807 mpdevil.py:1402 mpdevil.py:1942
|
||||
msgid "Artist"
|
||||
msgstr "Interpret"
|
||||
|
||||
#: mpdevil.py:305 mpdevil.py:715 mpdevil.py:1759
|
||||
#: mpdevil.py:308 mpdevil.py:813 mpdevil.py:1402 mpdevil.py:1954
|
||||
msgid "Length"
|
||||
msgstr "Länge"
|
||||
|
||||
#: mpdevil.py:345 mpdevil.py:886 mpdevil.py:1796
|
||||
#: mpdevil.py:348 mpdevil.py:968 mpdevil.py:1994
|
||||
msgid "Unknown Title"
|
||||
msgstr "Unbekannter Titel"
|
||||
|
||||
#: mpdevil.py:349 mpdevil.py:894 mpdevil.py:1804
|
||||
#: mpdevil.py:352 mpdevil.py:980 mpdevil.py:2002
|
||||
msgid "Unknown Artist"
|
||||
msgstr "Unbekannter Interpret"
|
||||
|
||||
#: mpdevil.py:390
|
||||
#: mpdevil.py:393
|
||||
msgid "all genres"
|
||||
msgstr "Alle Genres"
|
||||
|
||||
#: mpdevil.py:452
|
||||
#: mpdevil.py:461
|
||||
msgid "Album Artist"
|
||||
msgstr "Albuminterpret"
|
||||
|
||||
#: mpdevil.py:533 mpdevil.py:789
|
||||
#: mpdevil.py:553 mpdevil.py:899
|
||||
#, python-format
|
||||
msgid "%(total_tracks)i titles (%(total_length)s)"
|
||||
msgstr "%(total_tracks)i Titel (%(total_length)s)"
|
||||
|
||||
#: mpdevil.py:898 mpdevil.py:1808
|
||||
#: mpdevil.py:801 mpdevil.py:1402
|
||||
msgid "Disc"
|
||||
msgstr "CD"
|
||||
|
||||
#: mpdevil.py:810 mpdevil.py:1402 mpdevil.py:1948
|
||||
msgid "Album"
|
||||
msgstr "Album"
|
||||
|
||||
#: mpdevil.py:816 mpdevil.py:1402
|
||||
msgid "Year"
|
||||
msgstr "Jahr"
|
||||
|
||||
#: mpdevil.py:819 mpdevil.py:1402
|
||||
msgid "Genre"
|
||||
msgstr "Genre"
|
||||
|
||||
#: mpdevil.py:984 mpdevil.py:2006
|
||||
msgid "Unknown Album"
|
||||
msgstr "Unbekanntes Album"
|
||||
|
||||
#: mpdevil.py:1036
|
||||
#: mpdevil.py:1154
|
||||
msgid "Select"
|
||||
msgstr "Auswählen"
|
||||
|
||||
#: mpdevil.py:1038
|
||||
#: mpdevil.py:1156
|
||||
msgid "Profile:"
|
||||
msgstr "Profil:"
|
||||
|
||||
#: mpdevil.py:1040
|
||||
#: mpdevil.py:1158
|
||||
msgid "Name:"
|
||||
msgstr "Name:"
|
||||
|
||||
#: mpdevil.py:1042
|
||||
#: mpdevil.py:1160
|
||||
msgid "Host:"
|
||||
msgstr "Host:"
|
||||
|
||||
#: mpdevil.py:1044
|
||||
#: mpdevil.py:1162
|
||||
msgid "Port:"
|
||||
msgstr "Port:"
|
||||
|
||||
#: mpdevil.py:1046
|
||||
#: mpdevil.py:1164
|
||||
msgid "Password:"
|
||||
msgstr "Passwort:"
|
||||
|
||||
#: mpdevil.py:1048
|
||||
#: mpdevil.py:1166
|
||||
msgid "Music lib:"
|
||||
msgstr "Musikverzeichnis:"
|
||||
|
||||
#: mpdevil.py:1134
|
||||
#: mpdevil.py:1252
|
||||
msgid "Choose directory"
|
||||
msgstr "Verzeichnis Wählen"
|
||||
|
||||
#: mpdevil.py:1174
|
||||
#: mpdevil.py:1292
|
||||
msgid "Main cover size:"
|
||||
msgstr "Größe des Haupt-Covers:"
|
||||
|
||||
#: mpdevil.py:1176
|
||||
#: mpdevil.py:1294
|
||||
msgid "Album-view cover size:"
|
||||
msgstr "Covergröße in Albumansicht:"
|
||||
|
||||
#: mpdevil.py:1182
|
||||
#: mpdevil.py:1300
|
||||
msgid "Button icon size (restart required):"
|
||||
msgstr "Symbolgröße der Knöpfe (Neustart erforderlich):"
|
||||
|
||||
#: mpdevil.py:1191
|
||||
#: mpdevil.py:1334
|
||||
msgid "Use alternative layout"
|
||||
msgstr "Benutze alternatives Layout"
|
||||
|
||||
#: mpdevil.py:1334
|
||||
msgid "Show stop button"
|
||||
msgstr "Zeige Stopp-Knopf"
|
||||
|
||||
#: mpdevil.py:1194
|
||||
#: mpdevil.py:1335
|
||||
msgid "Show genre filter"
|
||||
msgstr "Zeige Genre Filter"
|
||||
|
||||
#: mpdevil.py:1197
|
||||
#: mpdevil.py:1335
|
||||
msgid "Show initials in artist view"
|
||||
msgstr "Zeige Anfangsbuchstaben in Interpretenspalte"
|
||||
|
||||
#: mpdevil.py:1336
|
||||
msgid "Show tooltips in album view"
|
||||
msgstr "Zeige Tooltips in Albumansicht"
|
||||
|
||||
#: mpdevil.py:1200
|
||||
#: mpdevil.py:1337
|
||||
msgid "Sort albums by year"
|
||||
msgstr "Sortiere Alben nach Erscheinungsjahr"
|
||||
|
||||
#: mpdevil.py:1203
|
||||
#: mpdevil.py:1337
|
||||
msgid "Show all artists"
|
||||
msgstr "Zeige alle Interpreten"
|
||||
|
||||
#: mpdevil.py:1206
|
||||
#: mpdevil.py:1338
|
||||
msgid "Send notification on title change"
|
||||
msgstr "Sende Benachrichtigung bei Titelwechsel"
|
||||
|
||||
#: mpdevil.py:1209
|
||||
#: mpdevil.py:1338
|
||||
msgid "Stop playback on quit"
|
||||
msgstr "Wiedergabe beim Beenden stoppen"
|
||||
|
||||
#: mpdevil.py:1212
|
||||
#: mpdevil.py:1339
|
||||
msgid "Play selected album after current title"
|
||||
msgstr "Ausgewähltes Album hinter aktuellem Titel einreihen"
|
||||
|
||||
#: mpdevil.py:1256 mpdevil.py:1948
|
||||
#: mpdevil.py:1379
|
||||
msgid "Drag & Drop to rearange"
|
||||
msgstr "Mit Drag & Drop sortieren"
|
||||
|
||||
#: mpdevil.py:1398
|
||||
msgid "Column"
|
||||
msgstr "Spalte"
|
||||
|
||||
#: mpdevil.py:1432 mpdevil.py:2149
|
||||
msgid "Settings"
|
||||
msgstr "Einstellungen"
|
||||
|
||||
#: mpdevil.py:1269
|
||||
#: mpdevil.py:1446
|
||||
msgid "General"
|
||||
msgstr "Allgemein"
|
||||
|
||||
#: mpdevil.py:1270
|
||||
#: mpdevil.py:1447
|
||||
msgid "Profiles"
|
||||
msgstr "Profile"
|
||||
|
||||
#: mpdevil.py:1454
|
||||
#: mpdevil.py:1448
|
||||
msgid "Playlist"
|
||||
msgstr "Wiedergabeliste"
|
||||
|
||||
#: mpdevil.py:1642
|
||||
msgid "Random mode"
|
||||
msgstr "Zufallsmodus"
|
||||
|
||||
#: mpdevil.py:1457
|
||||
#: mpdevil.py:1645
|
||||
msgid "Repeat mode"
|
||||
msgstr "Dauerschleife"
|
||||
|
||||
#: mpdevil.py:1460
|
||||
#: mpdevil.py:1648
|
||||
msgid "Single mode"
|
||||
msgstr "Einzelstückmodus"
|
||||
|
||||
#: mpdevil.py:1463
|
||||
#: mpdevil.py:1651
|
||||
msgid "Consume mode"
|
||||
msgstr "Playliste verbrauchen"
|
||||
|
||||
#: mpdevil.py:1553
|
||||
#: mpdevil.py:1741
|
||||
msgid "Click to show additional information"
|
||||
msgstr "Klicken für weitere Informationen"
|
||||
|
||||
#: mpdevil.py:1578
|
||||
#: mpdevil.py:1767
|
||||
msgid "MPD-Tag"
|
||||
msgstr "MPD-Tag"
|
||||
|
||||
#: mpdevil.py:1582 mpdevil.py:1685
|
||||
#: mpdevil.py:1771 mpdevil.py:1875
|
||||
msgid "Value"
|
||||
msgstr "Wert"
|
||||
|
||||
#: mpdevil.py:1604
|
||||
#: mpdevil.py:1793
|
||||
#, python-format
|
||||
msgid ""
|
||||
"%(bitrate)s kb/s, %(frequency)s kHz, %(resolution)s bit, %(channels)s "
|
||||
@@ -184,80 +220,76 @@ msgstr ""
|
||||
"%(bitrate)s kb/s, %(frequency)s kHz, %(resolution)s bit, %(channels)s "
|
||||
"Kanäle, %(file_type)s"
|
||||
|
||||
#: mpdevil.py:1664
|
||||
#: mpdevil.py:1853
|
||||
msgid "Stats"
|
||||
msgstr "Statistik"
|
||||
|
||||
#: mpdevil.py:1682
|
||||
#: mpdevil.py:1872
|
||||
msgid "Tag"
|
||||
msgstr "Tag"
|
||||
|
||||
#: mpdevil.py:1702
|
||||
#: mpdevil.py:1892
|
||||
msgid "Search"
|
||||
msgstr "Suche"
|
||||
|
||||
#: mpdevil.py:1753
|
||||
msgid "Album"
|
||||
msgstr "Album"
|
||||
|
||||
#: mpdevil.py:1815
|
||||
#: mpdevil.py:2013
|
||||
#, python-format
|
||||
msgid "Hits: %i"
|
||||
msgstr "Treffer: %i"
|
||||
|
||||
#: mpdevil.py:1819
|
||||
#: mpdevil.py:2017
|
||||
msgid "Lyrics"
|
||||
msgstr "Liedtext"
|
||||
|
||||
#: mpdevil.py:1852
|
||||
#: mpdevil.py:2051
|
||||
msgid "searching..."
|
||||
msgstr "suche..."
|
||||
|
||||
#: mpdevil.py:1856
|
||||
#: mpdevil.py:2055
|
||||
msgid "not found"
|
||||
msgstr "nicht gefunden"
|
||||
|
||||
#: mpdevil.py:1931
|
||||
#: mpdevil.py:2132
|
||||
msgid "Select profile"
|
||||
msgstr "Profil auswählen"
|
||||
|
||||
#: mpdevil.py:1936
|
||||
#: mpdevil.py:2137
|
||||
msgid "Return to album of current title"
|
||||
msgstr "Zu Album des aktuellen Titels zurückkehren"
|
||||
|
||||
#: mpdevil.py:1939
|
||||
#: mpdevil.py:2140
|
||||
msgid "Title search"
|
||||
msgstr "Titelsuche"
|
||||
|
||||
#: mpdevil.py:1942
|
||||
#: mpdevil.py:2143
|
||||
msgid "Show lyrics"
|
||||
msgstr "Zeige Liedtext"
|
||||
|
||||
#: mpdevil.py:1947
|
||||
msgid "Save window size"
|
||||
msgstr "Fenstergröße speichern"
|
||||
#: mpdevil.py:2148
|
||||
msgid "Save window layout"
|
||||
msgstr "Fensterlayout speichern"
|
||||
|
||||
#: mpdevil.py:1949
|
||||
#: mpdevil.py:2150
|
||||
msgid "Update database"
|
||||
msgstr "Datenbank aktualisieren"
|
||||
|
||||
#: mpdevil.py:1950
|
||||
#: mpdevil.py:2151
|
||||
msgid "Server stats"
|
||||
msgstr "Serverstatistik"
|
||||
|
||||
#: mpdevil.py:1951
|
||||
#: mpdevil.py:2152
|
||||
msgid "About"
|
||||
msgstr "Über"
|
||||
|
||||
#: mpdevil.py:1952
|
||||
#: mpdevil.py:2153
|
||||
msgid "Quit"
|
||||
msgstr "Beenden"
|
||||
|
||||
#: mpdevil.py:1958
|
||||
#: mpdevil.py:2159
|
||||
msgid "Main menu"
|
||||
msgstr "Hauptmenu"
|
||||
|
||||
#: mpdevil.py:2126
|
||||
#: mpdevil.py:2342
|
||||
msgid "A small MPD client written in python"
|
||||
msgstr ""
|
||||
|
||||
|
160
po/mpdevil.pot
160
po/mpdevil.pot
@@ -8,7 +8,7 @@ msgid ""
|
||||
msgstr ""
|
||||
"Project-Id-Version: PACKAGE VERSION\n"
|
||||
"Report-Msgid-Bugs-To: \n"
|
||||
"POT-Creation-Date: 2020-02-28 23:22+0100\n"
|
||||
"POT-Creation-Date: 2020-03-12 17:05+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,243 +17,275 @@ msgstr ""
|
||||
"Content-Type: text/plain; charset=CHARSET\n"
|
||||
"Content-Transfer-Encoding: 8bit\n"
|
||||
|
||||
#: mpdevil.py:290 mpdevil.py:700 mpdevil.py:1735
|
||||
#: mpdevil.py:293 mpdevil.py:798 mpdevil.py:1402 mpdevil.py:1930
|
||||
msgid "No"
|
||||
msgstr ""
|
||||
|
||||
#: mpdevil.py:295 mpdevil.py:705 mpdevil.py:1741
|
||||
#: mpdevil.py:298 mpdevil.py:804 mpdevil.py:1402 mpdevil.py:1936
|
||||
msgid "Title"
|
||||
msgstr ""
|
||||
|
||||
#: mpdevil.py:300 mpdevil.py:454 mpdevil.py:710 mpdevil.py:1747
|
||||
#: mpdevil.py:303 mpdevil.py:463 mpdevil.py:807 mpdevil.py:1402 mpdevil.py:1942
|
||||
msgid "Artist"
|
||||
msgstr ""
|
||||
|
||||
#: mpdevil.py:305 mpdevil.py:715 mpdevil.py:1759
|
||||
#: mpdevil.py:308 mpdevil.py:813 mpdevil.py:1402 mpdevil.py:1954
|
||||
msgid "Length"
|
||||
msgstr ""
|
||||
|
||||
#: mpdevil.py:345 mpdevil.py:886 mpdevil.py:1796
|
||||
#: mpdevil.py:348 mpdevil.py:968 mpdevil.py:1994
|
||||
msgid "Unknown Title"
|
||||
msgstr ""
|
||||
|
||||
#: mpdevil.py:349 mpdevil.py:894 mpdevil.py:1804
|
||||
#: mpdevil.py:352 mpdevil.py:980 mpdevil.py:2002
|
||||
msgid "Unknown Artist"
|
||||
msgstr ""
|
||||
|
||||
#: mpdevil.py:390
|
||||
#: mpdevil.py:393
|
||||
msgid "all genres"
|
||||
msgstr ""
|
||||
|
||||
#: mpdevil.py:452
|
||||
#: mpdevil.py:461
|
||||
msgid "Album Artist"
|
||||
msgstr ""
|
||||
|
||||
#: mpdevil.py:533 mpdevil.py:789
|
||||
#: mpdevil.py:553 mpdevil.py:899
|
||||
#, python-format
|
||||
msgid "%(total_tracks)i titles (%(total_length)s)"
|
||||
msgstr ""
|
||||
|
||||
#: mpdevil.py:898 mpdevil.py:1808
|
||||
#: mpdevil.py:801 mpdevil.py:1402
|
||||
msgid "Disc"
|
||||
msgstr ""
|
||||
|
||||
#: mpdevil.py:810 mpdevil.py:1402 mpdevil.py:1948
|
||||
msgid "Album"
|
||||
msgstr ""
|
||||
|
||||
#: mpdevil.py:816 mpdevil.py:1402
|
||||
msgid "Year"
|
||||
msgstr ""
|
||||
|
||||
#: mpdevil.py:819 mpdevil.py:1402
|
||||
msgid "Genre"
|
||||
msgstr ""
|
||||
|
||||
#: mpdevil.py:984 mpdevil.py:2006
|
||||
msgid "Unknown Album"
|
||||
msgstr ""
|
||||
|
||||
#: mpdevil.py:1036
|
||||
#: mpdevil.py:1154
|
||||
msgid "Select"
|
||||
msgstr ""
|
||||
|
||||
#: mpdevil.py:1038
|
||||
#: mpdevil.py:1156
|
||||
msgid "Profile:"
|
||||
msgstr ""
|
||||
|
||||
#: mpdevil.py:1040
|
||||
#: mpdevil.py:1158
|
||||
msgid "Name:"
|
||||
msgstr ""
|
||||
|
||||
#: mpdevil.py:1042
|
||||
#: mpdevil.py:1160
|
||||
msgid "Host:"
|
||||
msgstr ""
|
||||
|
||||
#: mpdevil.py:1044
|
||||
#: mpdevil.py:1162
|
||||
msgid "Port:"
|
||||
msgstr ""
|
||||
|
||||
#: mpdevil.py:1046
|
||||
#: mpdevil.py:1164
|
||||
msgid "Password:"
|
||||
msgstr ""
|
||||
|
||||
#: mpdevil.py:1048
|
||||
#: mpdevil.py:1166
|
||||
msgid "Music lib:"
|
||||
msgstr ""
|
||||
|
||||
#: mpdevil.py:1134
|
||||
#: mpdevil.py:1252
|
||||
msgid "Choose directory"
|
||||
msgstr ""
|
||||
|
||||
#: mpdevil.py:1174
|
||||
#: mpdevil.py:1292
|
||||
msgid "Main cover size:"
|
||||
msgstr ""
|
||||
|
||||
#: mpdevil.py:1176
|
||||
#: mpdevil.py:1294
|
||||
msgid "Album-view cover size:"
|
||||
msgstr ""
|
||||
|
||||
#: mpdevil.py:1182
|
||||
#: mpdevil.py:1300
|
||||
msgid "Button icon size (restart required):"
|
||||
msgstr ""
|
||||
|
||||
#: mpdevil.py:1191
|
||||
#: mpdevil.py:1334
|
||||
msgid "Use alternative layout"
|
||||
msgstr ""
|
||||
|
||||
#: mpdevil.py:1334
|
||||
msgid "Show stop button"
|
||||
msgstr ""
|
||||
|
||||
#: mpdevil.py:1194
|
||||
#: mpdevil.py:1335
|
||||
msgid "Show genre filter"
|
||||
msgstr ""
|
||||
|
||||
#: mpdevil.py:1197
|
||||
#: mpdevil.py:1335
|
||||
msgid "Show initials in artist view"
|
||||
msgstr ""
|
||||
|
||||
#: mpdevil.py:1336
|
||||
msgid "Show tooltips in album view"
|
||||
msgstr ""
|
||||
|
||||
#: mpdevil.py:1200
|
||||
#: mpdevil.py:1337
|
||||
msgid "Sort albums by year"
|
||||
msgstr ""
|
||||
|
||||
#: mpdevil.py:1203
|
||||
#: mpdevil.py:1337
|
||||
msgid "Show all artists"
|
||||
msgstr ""
|
||||
|
||||
#: mpdevil.py:1206
|
||||
#: mpdevil.py:1338
|
||||
msgid "Send notification on title change"
|
||||
msgstr ""
|
||||
|
||||
#: mpdevil.py:1209
|
||||
#: mpdevil.py:1338
|
||||
msgid "Stop playback on quit"
|
||||
msgstr ""
|
||||
|
||||
#: mpdevil.py:1212
|
||||
#: mpdevil.py:1339
|
||||
msgid "Play selected album after current title"
|
||||
msgstr ""
|
||||
|
||||
#: mpdevil.py:1256 mpdevil.py:1948
|
||||
#: mpdevil.py:1379
|
||||
msgid "Drag & Drop to rearange"
|
||||
msgstr ""
|
||||
|
||||
#: mpdevil.py:1398
|
||||
msgid "Column"
|
||||
msgstr ""
|
||||
|
||||
#: mpdevil.py:1432 mpdevil.py:2149
|
||||
msgid "Settings"
|
||||
msgstr ""
|
||||
|
||||
#: mpdevil.py:1269
|
||||
#: mpdevil.py:1446
|
||||
msgid "General"
|
||||
msgstr ""
|
||||
|
||||
#: mpdevil.py:1270
|
||||
#: mpdevil.py:1447
|
||||
msgid "Profiles"
|
||||
msgstr ""
|
||||
|
||||
#: mpdevil.py:1454
|
||||
#: mpdevil.py:1448
|
||||
msgid "Playlist"
|
||||
msgstr ""
|
||||
|
||||
#: mpdevil.py:1642
|
||||
msgid "Random mode"
|
||||
msgstr ""
|
||||
|
||||
#: mpdevil.py:1457
|
||||
#: mpdevil.py:1645
|
||||
msgid "Repeat mode"
|
||||
msgstr ""
|
||||
|
||||
#: mpdevil.py:1460
|
||||
#: mpdevil.py:1648
|
||||
msgid "Single mode"
|
||||
msgstr ""
|
||||
|
||||
#: mpdevil.py:1463
|
||||
#: mpdevil.py:1651
|
||||
msgid "Consume mode"
|
||||
msgstr ""
|
||||
|
||||
#: mpdevil.py:1553
|
||||
#: mpdevil.py:1741
|
||||
msgid "Click to show additional information"
|
||||
msgstr ""
|
||||
|
||||
#: mpdevil.py:1578
|
||||
#: mpdevil.py:1767
|
||||
msgid "MPD-Tag"
|
||||
msgstr ""
|
||||
|
||||
#: mpdevil.py:1582 mpdevil.py:1685
|
||||
#: mpdevil.py:1771 mpdevil.py:1875
|
||||
msgid "Value"
|
||||
msgstr ""
|
||||
|
||||
#: mpdevil.py:1604
|
||||
#: mpdevil.py:1793
|
||||
#, python-format
|
||||
msgid ""
|
||||
"%(bitrate)s kb/s, %(frequency)s kHz, %(resolution)s bit, %(channels)s "
|
||||
"channels, %(file_type)s"
|
||||
msgstr ""
|
||||
|
||||
#: mpdevil.py:1664
|
||||
#: mpdevil.py:1853
|
||||
msgid "Stats"
|
||||
msgstr ""
|
||||
|
||||
#: mpdevil.py:1682
|
||||
#: mpdevil.py:1872
|
||||
msgid "Tag"
|
||||
msgstr ""
|
||||
|
||||
#: mpdevil.py:1702
|
||||
#: mpdevil.py:1892
|
||||
msgid "Search"
|
||||
msgstr ""
|
||||
|
||||
#: mpdevil.py:1753
|
||||
msgid "Album"
|
||||
msgstr ""
|
||||
|
||||
#: mpdevil.py:1815
|
||||
#: mpdevil.py:2013
|
||||
#, python-format
|
||||
msgid "Hits: %i"
|
||||
msgstr ""
|
||||
|
||||
#: mpdevil.py:1819
|
||||
#: mpdevil.py:2017
|
||||
msgid "Lyrics"
|
||||
msgstr ""
|
||||
|
||||
#: mpdevil.py:1852
|
||||
#: mpdevil.py:2051
|
||||
msgid "searching..."
|
||||
msgstr ""
|
||||
|
||||
#: mpdevil.py:1856
|
||||
#: mpdevil.py:2055
|
||||
msgid "not found"
|
||||
msgstr ""
|
||||
|
||||
#: mpdevil.py:1931
|
||||
#: mpdevil.py:2132
|
||||
msgid "Select profile"
|
||||
msgstr ""
|
||||
|
||||
#: mpdevil.py:1936
|
||||
#: mpdevil.py:2137
|
||||
msgid "Return to album of current title"
|
||||
msgstr ""
|
||||
|
||||
#: mpdevil.py:1939
|
||||
#: mpdevil.py:2140
|
||||
msgid "Title search"
|
||||
msgstr ""
|
||||
|
||||
#: mpdevil.py:1942
|
||||
#: mpdevil.py:2143
|
||||
msgid "Show lyrics"
|
||||
msgstr ""
|
||||
|
||||
#: mpdevil.py:1947
|
||||
msgid "Save window size"
|
||||
#: mpdevil.py:2148
|
||||
msgid "Save window layout"
|
||||
msgstr ""
|
||||
|
||||
#: mpdevil.py:1949
|
||||
#: mpdevil.py:2150
|
||||
msgid "Update database"
|
||||
msgstr ""
|
||||
|
||||
#: mpdevil.py:1950
|
||||
#: mpdevil.py:2151
|
||||
msgid "Server stats"
|
||||
msgstr ""
|
||||
|
||||
#: mpdevil.py:1951
|
||||
#: mpdevil.py:2152
|
||||
msgid "About"
|
||||
msgstr ""
|
||||
|
||||
#: mpdevil.py:1952
|
||||
#: mpdevil.py:2153
|
||||
msgid "Quit"
|
||||
msgstr ""
|
||||
|
||||
#: mpdevil.py:1958
|
||||
#: mpdevil.py:2159
|
||||
msgid "Main menu"
|
||||
msgstr ""
|
||||
|
||||
#: mpdevil.py:2126
|
||||
#: mpdevil.py:2342
|
||||
msgid "A small MPD client written in python"
|
||||
msgstr ""
|
||||
|
Binary file not shown.
Before Width: | Height: | Size: 1012 KiB |
BIN
screenshots/mainwindow_0.7.0.png
Normal file
BIN
screenshots/mainwindow_0.7.0.png
Normal file
Binary file not shown.
After Width: | Height: | Size: 1020 KiB |
Reference in New Issue
Block a user