mirror of
https://github.com/SoongNoonien/mpdevil.git
synced 2023-08-10 21:12:44 +03:00
Compare commits
9 Commits
Author | SHA1 | Date | |
---|---|---|---|
![]() |
79b828511b | ||
![]() |
596bcec194 | ||
![]() |
d9e518c687 | ||
![]() |
2e5ce9bf2b | ||
![]() |
8f1678579f | ||
![]() |
6374fe1c28 | ||
![]() |
b833cb3ca2 | ||
![]() |
08ff73d797 | ||
![]() |
0c9635921d |
@@ -19,7 +19,8 @@ Features
|
|||||||
|
|
||||||
TODO
|
TODO
|
||||||
----
|
----
|
||||||
1. MPRIS interface
|
1. Support media keys
|
||||||
|
2. MPRIS interface
|
||||||
|
|
||||||
Building and installation
|
Building and installation
|
||||||
-------------------------
|
-------------------------
|
||||||
|
101
bin/mpdevil.py
101
bin/mpdevil.py
@@ -138,6 +138,8 @@ class Settings(Gio.Settings):
|
|||||||
BASE_KEY = "org.mpdevil"
|
BASE_KEY = "org.mpdevil"
|
||||||
def __init__(self):
|
def __init__(self):
|
||||||
super().__init__(schema=self.BASE_KEY)
|
super().__init__(schema=self.BASE_KEY)
|
||||||
|
if len(self.get_value("profiles")) < (self.get_int("active-profile")+1):
|
||||||
|
self.set_int("active-profile", 0)
|
||||||
|
|
||||||
def array_append(self, vtype, key, value): #append to Gio.Settings (self.settings) array
|
def array_append(self, vtype, key, value): #append to Gio.Settings (self.settings) array
|
||||||
array=self.get_value(key).unpack()
|
array=self.get_value(key).unpack()
|
||||||
@@ -406,10 +408,9 @@ class AlbumIconView(Gtk.IconView):
|
|||||||
else:
|
else:
|
||||||
break
|
break
|
||||||
|
|
||||||
def scroll_to_selected_album(self, first_run):
|
def scroll_to_selected_album(self):
|
||||||
songid=self.client.status()["songid"]
|
songid=self.client.status()["songid"]
|
||||||
song=self.client.playlistid(songid)[0]
|
song=self.client.playlistid(songid)[0]
|
||||||
if not self.settings.get_boolean("add-album") or first_run:
|
|
||||||
self.handler_block(self.album_change)
|
self.handler_block(self.album_change)
|
||||||
self.unselect_all()
|
self.unselect_all()
|
||||||
row_num=len(self.store)
|
row_num=len(self.store)
|
||||||
@@ -420,7 +421,6 @@ class AlbumIconView(Gtk.IconView):
|
|||||||
self.select_path(path)
|
self.select_path(path)
|
||||||
self.scroll_to_path(path, True, 0, 0)
|
self.scroll_to_path(path, True, 0, 0)
|
||||||
break
|
break
|
||||||
if not self.settings.get_boolean("add-album") or first_run:
|
|
||||||
self.handler_unblock(self.album_change)
|
self.handler_unblock(self.album_change)
|
||||||
|
|
||||||
def on_album_view_button_press_event(self, widget, event):
|
def on_album_view_button_press_event(self, widget, event):
|
||||||
@@ -489,16 +489,17 @@ class AlbumView(Gtk.ScrolledWindow):
|
|||||||
self.iconview.show_all()
|
self.iconview.show_all()
|
||||||
self.iconview.populate(artists)
|
self.iconview.populate(artists)
|
||||||
|
|
||||||
def scroll_to_selected_album(self, first_run):
|
def scroll_to_selected_album(self):
|
||||||
self.iconview.scroll_to_selected_album(first_run)
|
self.iconview.scroll_to_selected_album()
|
||||||
|
|
||||||
class TrackView(Gtk.Box):
|
class TrackView(Gtk.Box):
|
||||||
def __init__(self, client, settings):
|
def __init__(self, client, settings, window):
|
||||||
Gtk.Box.__init__(self, orientation=Gtk.Orientation.VERTICAL)
|
Gtk.Box.__init__(self, orientation=Gtk.Orientation.VERTICAL)
|
||||||
self.settings = settings
|
self.settings = settings
|
||||||
|
|
||||||
#adding vars
|
#adding vars
|
||||||
self.client=client
|
self.client=client
|
||||||
|
self.window=window
|
||||||
self.playlist=[]
|
self.playlist=[]
|
||||||
self.hovered_songpos=None
|
self.hovered_songpos=None
|
||||||
self.song_file=None
|
self.song_file=None
|
||||||
@@ -547,6 +548,8 @@ class TrackView(Gtk.Box):
|
|||||||
#cover
|
#cover
|
||||||
self.cover=Gtk.Image.new()
|
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
|
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 infos
|
||||||
audio=AudioType(self.client)
|
audio=AudioType(self.client)
|
||||||
@@ -558,8 +561,8 @@ class TrackView(Gtk.Box):
|
|||||||
|
|
||||||
#status bar
|
#status bar
|
||||||
status_bar=Gtk.Box(orientation=Gtk.Orientation.HORIZONTAL, spacing=10)
|
status_bar=Gtk.Box(orientation=Gtk.Orientation.HORIZONTAL, spacing=10)
|
||||||
status_bar.set_margin_left(4)
|
status_bar.set_margin_start(4)
|
||||||
status_bar.set_margin_right(4)
|
status_bar.set_margin_end(4)
|
||||||
status_bar.pack_start(self.playlist_info, True, True, 0)
|
status_bar.pack_start(self.playlist_info, True, True, 0)
|
||||||
status_bar.pack_end(audio, False, False, 0)
|
status_bar.pack_end(audio, False, False, 0)
|
||||||
|
|
||||||
@@ -572,9 +575,10 @@ class TrackView(Gtk.Box):
|
|||||||
self.treeview.connect("motion-notify-event", self.on_move_event)
|
self.treeview.connect("motion-notify-event", self.on_move_event)
|
||||||
self.treeview.connect("leave-notify-event", self.on_leave_event)
|
self.treeview.connect("leave-notify-event", self.on_leave_event)
|
||||||
self.key_press_event=self.treeview.connect("key-press-event", self.on_key_press_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)
|
||||||
|
|
||||||
#packing
|
#packing
|
||||||
self.pack_start(self.cover, False, False, 0)
|
self.pack_start(cover_event_box, False, False, 0)
|
||||||
self.pack_start(scroll, True, True, 0)
|
self.pack_start(scroll, True, True, 0)
|
||||||
self.pack_end(status_bar, False, False, 0)
|
self.pack_end(status_bar, False, False, 0)
|
||||||
|
|
||||||
@@ -712,6 +716,37 @@ class TrackView(Gtk.Box):
|
|||||||
selected_title=self.store.get_path(treeiter)
|
selected_title=self.store.get_path(treeiter)
|
||||||
self.client.play(selected_title)
|
self.client.play(selected_title)
|
||||||
|
|
||||||
|
def on_button_press_event(self, widget, event):
|
||||||
|
if self.client.connected():
|
||||||
|
song=self.client.currentsong()
|
||||||
|
if not song == {}:
|
||||||
|
try:
|
||||||
|
artist=song["albumartist"]
|
||||||
|
except:
|
||||||
|
artist=""
|
||||||
|
try:
|
||||||
|
album=song["album"]
|
||||||
|
except:
|
||||||
|
album=""
|
||||||
|
try:
|
||||||
|
album_year=song["date"]
|
||||||
|
except:
|
||||||
|
album_year=""
|
||||||
|
if event.button == 1:
|
||||||
|
self.client.album_to_playlist(album, artist, album_year, False)
|
||||||
|
elif event.button == 2:
|
||||||
|
self.client.album_to_playlist(album, artist, album_year, True)
|
||||||
|
elif event.button == 3:
|
||||||
|
album_dialog = AlbumDialog(self.window, self.client, album, artist, album_year)
|
||||||
|
response = album_dialog.run()
|
||||||
|
if response == Gtk.ResponseType.OK:
|
||||||
|
self.client.album_to_playlist(album, artist, album_year, False)
|
||||||
|
elif response == Gtk.ResponseType.ACCEPT:
|
||||||
|
self.client.album_to_playlist(album, artist, album_year, True)
|
||||||
|
elif response == Gtk.ResponseType.YES:
|
||||||
|
self.client.album_to_playlist(album, artist, album_year, False, True)
|
||||||
|
album_dialog.destroy()
|
||||||
|
|
||||||
class Browser(Gtk.Box):
|
class Browser(Gtk.Box):
|
||||||
def __init__(self, client, settings, window):
|
def __init__(self, client, settings, window):
|
||||||
Gtk.Box.__init__(self, orientation=Gtk.Orientation.HORIZONTAL, spacing=4)
|
Gtk.Box.__init__(self, orientation=Gtk.Orientation.HORIZONTAL, spacing=4)
|
||||||
@@ -724,7 +759,7 @@ class Browser(Gtk.Box):
|
|||||||
#widgets
|
#widgets
|
||||||
self.artist_list=ArtistView(self.client)
|
self.artist_list=ArtistView(self.client)
|
||||||
self.album_list=AlbumView(self.client, self.settings, self.window)
|
self.album_list=AlbumView(self.client, self.settings, self.window)
|
||||||
self.title_list=TrackView(self.client, self.settings)
|
self.title_list=TrackView(self.client, self.settings, self.window)
|
||||||
|
|
||||||
#connect
|
#connect
|
||||||
self.artist_change=self.artist_list.selection.connect("changed", self.on_artist_selection_change)
|
self.artist_change=self.artist_list.selection.connect("changed", self.on_artist_selection_change)
|
||||||
@@ -758,7 +793,7 @@ class Browser(Gtk.Box):
|
|||||||
return_val=self.artist_list.refresh()
|
return_val=self.artist_list.refresh()
|
||||||
self.artist_list.selection.handler_unblock(self.artist_change)
|
self.artist_list.selection.handler_unblock(self.artist_change)
|
||||||
if return_val:
|
if return_val:
|
||||||
self.go_home(self, first_run=True)
|
self.go_home(self)
|
||||||
else:
|
else:
|
||||||
self.artist_list.selection.handler_block(self.artist_change)
|
self.artist_list.selection.handler_block(self.artist_change)
|
||||||
self.artist_list.clear()
|
self.artist_list.clear()
|
||||||
@@ -766,7 +801,7 @@ class Browser(Gtk.Box):
|
|||||||
self.album_list.clear()
|
self.album_list.clear()
|
||||||
return True
|
return True
|
||||||
|
|
||||||
def go_home(self, widget, first_run=False): #TODO
|
def go_home(self, widget): #TODO
|
||||||
try:
|
try:
|
||||||
songid=self.client.status()["songid"]
|
songid=self.client.status()["songid"]
|
||||||
song=self.client.playlistid(songid)[0]
|
song=self.client.playlistid(songid)[0]
|
||||||
@@ -780,7 +815,7 @@ class Browser(Gtk.Box):
|
|||||||
self.artist_list.selection.select_iter(treeiter)
|
self.artist_list.selection.select_iter(treeiter)
|
||||||
self.artist_list.treeview.scroll_to_cell(path)
|
self.artist_list.treeview.scroll_to_cell(path)
|
||||||
break
|
break
|
||||||
self.album_list.scroll_to_selected_album(first_run)
|
self.album_list.scroll_to_selected_album()
|
||||||
except:
|
except:
|
||||||
pass
|
pass
|
||||||
self.title_list.scroll_to_selected_title()
|
self.title_list.scroll_to_selected_title()
|
||||||
@@ -1296,6 +1331,7 @@ class AudioType(Gtk.EventBox):
|
|||||||
self.label.set_xalign(1)
|
self.label.set_xalign(1)
|
||||||
self.label.set_ellipsize(Pango.EllipsizeMode.END)
|
self.label.set_ellipsize(Pango.EllipsizeMode.END)
|
||||||
self.popover=Gtk.Popover()
|
self.popover=Gtk.Popover()
|
||||||
|
self.popover.set_relative_to(self)
|
||||||
|
|
||||||
#Store
|
#Store
|
||||||
#(tag, value)
|
#(tag, value)
|
||||||
@@ -1311,19 +1347,21 @@ class AudioType(Gtk.EventBox):
|
|||||||
renderer_text = Gtk.CellRendererText()
|
renderer_text = Gtk.CellRendererText()
|
||||||
|
|
||||||
self.column_tag = Gtk.TreeViewColumn(_("MPD-Tag"), renderer_text, text=0)
|
self.column_tag = Gtk.TreeViewColumn(_("MPD-Tag"), renderer_text, text=0)
|
||||||
|
self.column_tag.set_property("resizable", False)
|
||||||
self.treeview.append_column(self.column_tag)
|
self.treeview.append_column(self.column_tag)
|
||||||
|
|
||||||
self.column_value = Gtk.TreeViewColumn(_("Value"), renderer_text, text=1)
|
self.column_value = Gtk.TreeViewColumn(_("Value"), renderer_text, text=1)
|
||||||
|
self.column_value.set_property("resizable", False)
|
||||||
self.treeview.append_column(self.column_value)
|
self.treeview.append_column(self.column_value)
|
||||||
|
|
||||||
self.popover.add(self.treeview)
|
|
||||||
|
|
||||||
#timeouts
|
#timeouts
|
||||||
GLib.timeout_add(1000, self.update)
|
GLib.timeout_add(1000, self.update)
|
||||||
|
|
||||||
#connect
|
#connect
|
||||||
self.connect("button-press-event", self.on_button_press_event)
|
self.connect("button-press-event", self.on_button_press_event)
|
||||||
|
|
||||||
|
#packing
|
||||||
|
self.popover.add(self.treeview)
|
||||||
self.add(self.label)
|
self.add(self.label)
|
||||||
|
|
||||||
def update(self):
|
def update(self):
|
||||||
@@ -1344,10 +1382,8 @@ class AudioType(Gtk.EventBox):
|
|||||||
|
|
||||||
def on_button_press_event(self, widget, event):
|
def on_button_press_event(self, widget, event):
|
||||||
if event.button == 1 or event.button == 2 or event.button == 3:
|
if event.button == 1 or event.button == 2 or event.button == 3:
|
||||||
self.popover.remove(self.treeview) #workaround
|
|
||||||
self.store.clear()
|
|
||||||
self.popover.add(self.treeview) #workaround
|
|
||||||
try:
|
try:
|
||||||
|
self.store.clear()
|
||||||
song=self.client.status()["song"]
|
song=self.client.status()["song"]
|
||||||
tags=self.client.playlistinfo(song)[0]
|
tags=self.client.playlistinfo(song)[0]
|
||||||
for key in tags:
|
for key in tags:
|
||||||
@@ -1355,9 +1391,8 @@ class AudioType(Gtk.EventBox):
|
|||||||
self.store.append([key, str(datetime.timedelta(seconds=int(tags[key])))])
|
self.store.append([key, str(datetime.timedelta(seconds=int(tags[key])))])
|
||||||
else:
|
else:
|
||||||
self.store.append([key, tags[key]])
|
self.store.append([key, tags[key]])
|
||||||
self.popover.set_relative_to(self)
|
|
||||||
self.popover.show_all()
|
self.popover.show_all()
|
||||||
self.popover.popup()
|
self.treeview.queue_resize()
|
||||||
except:
|
except:
|
||||||
pass
|
pass
|
||||||
|
|
||||||
@@ -1378,15 +1413,13 @@ class ProfileSelect(Gtk.ComboBoxText):
|
|||||||
self.settings.connect("changed::paths", self.on_settings_changed)
|
self.settings.connect("changed::paths", self.on_settings_changed)
|
||||||
|
|
||||||
self.reload()
|
self.reload()
|
||||||
self.handler_block(self.changed)
|
|
||||||
self.set_active(self.settings.get_int("active-profile"))
|
|
||||||
self.handler_unblock(self.changed)
|
|
||||||
|
|
||||||
def reload(self, *args):
|
def reload(self, *args):
|
||||||
self.handler_block(self.changed)
|
self.handler_block(self.changed)
|
||||||
self.remove_all()
|
self.remove_all()
|
||||||
for profile in self.settings.get_value("profiles"):
|
for profile in self.settings.get_value("profiles"):
|
||||||
self.append_text(profile)
|
self.append_text(profile)
|
||||||
|
self.set_active(self.settings.get_int("active-profile"))
|
||||||
self.handler_unblock(self.changed)
|
self.handler_unblock(self.changed)
|
||||||
|
|
||||||
def on_settings_changed(self, *args):
|
def on_settings_changed(self, *args):
|
||||||
@@ -1593,6 +1626,7 @@ class LyricsWindow(Gtk.Window): #Lyrics view with own client because MPDClient i
|
|||||||
while not self.stop:
|
while not self.stop:
|
||||||
if self.client.connected():
|
if self.client.connected():
|
||||||
cs=self.client.currentsong()
|
cs=self.client.currentsong()
|
||||||
|
if not cs == {}:
|
||||||
cs.pop("pos") #avoid unnecessary reloads caused by position change of current title
|
cs.pop("pos") #avoid unnecessary reloads caused by position change of current title
|
||||||
if cs != self.current_song:
|
if cs != self.current_song:
|
||||||
GLib.idle_add(update_label, _("searching..."))
|
GLib.idle_add(update_label, _("searching..."))
|
||||||
@@ -1717,6 +1751,7 @@ class MainWindow(Gtk.ApplicationWindow):
|
|||||||
self.search_button.connect("clicked", self.on_search_clicked)
|
self.search_button.connect("clicked", self.on_search_clicked)
|
||||||
self.lyrics_button.connect("toggled", self.on_lyrics_toggled)
|
self.lyrics_button.connect("toggled", self.on_lyrics_toggled)
|
||||||
self.info_bar.connect("response", self.on_info_bar_response)
|
self.info_bar.connect("response", self.on_info_bar_response)
|
||||||
|
self.settings.connect("changed::profiles", self.on_settings_changed)
|
||||||
#unmap space
|
#unmap space
|
||||||
binding_set=Gtk.binding_set_find('GtkTreeView')
|
binding_set=Gtk.binding_set_find('GtkTreeView')
|
||||||
Gtk.binding_entry_remove(binding_set, 32, Gdk.ModifierType.MOD2_MASK)
|
Gtk.binding_entry_remove(binding_set, 32, Gdk.ModifierType.MOD2_MASK)
|
||||||
@@ -1729,8 +1764,8 @@ class MainWindow(Gtk.ApplicationWindow):
|
|||||||
#packing
|
#packing
|
||||||
self.vbox=Gtk.Box(orientation=Gtk.Orientation.VERTICAL, spacing=4)
|
self.vbox=Gtk.Box(orientation=Gtk.Orientation.VERTICAL, spacing=4)
|
||||||
self.hbox=Gtk.Box(orientation=Gtk.Orientation.HORIZONTAL, spacing=4)
|
self.hbox=Gtk.Box(orientation=Gtk.Orientation.HORIZONTAL, spacing=4)
|
||||||
self.hbox.set_margin_left(2)
|
self.hbox.set_margin_start(2)
|
||||||
self.hbox.set_margin_right(2)
|
self.hbox.set_margin_end(2)
|
||||||
self.hbox.set_margin_bottom(2)
|
self.hbox.set_margin_bottom(2)
|
||||||
self.vbox.pack_start(self.info_bar, False, False, 0)
|
self.vbox.pack_start(self.info_bar, False, False, 0)
|
||||||
self.vbox.pack_start(self.browser, True, True, 0)
|
self.vbox.pack_start(self.browser, True, True, 0)
|
||||||
@@ -1740,6 +1775,7 @@ class MainWindow(Gtk.ApplicationWindow):
|
|||||||
self.hbox.pack_start(self.go_home_button, False, False, 0)
|
self.hbox.pack_start(self.go_home_button, False, False, 0)
|
||||||
self.hbox.pack_start(self.search_button, False, False, 0)
|
self.hbox.pack_start(self.search_button, False, False, 0)
|
||||||
self.hbox.pack_start(self.lyrics_button, False, False, 0)
|
self.hbox.pack_start(self.lyrics_button, False, False, 0)
|
||||||
|
if len(self.settings.get_value("profiles")) > 1:
|
||||||
self.hbox.pack_start(self.profiles, False, False, 0)
|
self.hbox.pack_start(self.profiles, False, False, 0)
|
||||||
self.hbox.pack_start(self.play_opts, False, False, 0)
|
self.hbox.pack_start(self.play_opts, False, False, 0)
|
||||||
self.hbox.pack_end(menu_button, False, False, 0)
|
self.hbox.pack_end(menu_button, False, False, 0)
|
||||||
@@ -1809,8 +1845,14 @@ class MainWindow(Gtk.ApplicationWindow):
|
|||||||
self.lyrics_win.destroy()
|
self.lyrics_win.destroy()
|
||||||
|
|
||||||
def on_key_press_event(self, widget, event):
|
def on_key_press_event(self, widget, event):
|
||||||
if event.keyval == 32:
|
if event.keyval == 32: #space
|
||||||
self.control.play_button.grab_focus()
|
self.control.play_button.grab_focus()
|
||||||
|
if event.keyval == 269025044: #AudioPlay
|
||||||
|
self.control.play_button.emit("clicked")
|
||||||
|
elif event.keyval == 269025047: #AudioNext
|
||||||
|
self.control.next_button.emit("clicked")
|
||||||
|
elif event.keyval == 269025046: #AudioPrev
|
||||||
|
self.control.prev_button.emit("clicked")
|
||||||
|
|
||||||
def on_save(self, action, param):
|
def on_save(self, action, param):
|
||||||
size=self.get_size()
|
size=self.get_size()
|
||||||
@@ -1833,6 +1875,13 @@ class MainWindow(Gtk.ApplicationWindow):
|
|||||||
if self.client.connected():
|
if self.client.connected():
|
||||||
self.client.update()
|
self.client.update()
|
||||||
|
|
||||||
|
def on_settings_changed(self, *args):
|
||||||
|
self.hbox.remove(self.profiles)
|
||||||
|
if len(self.settings.get_value("profiles")) > 1:
|
||||||
|
self.hbox.pack_start(self.profiles, False, False, 0)
|
||||||
|
self.hbox.reorder_child(self.profiles, 5)
|
||||||
|
self.profiles.show()
|
||||||
|
|
||||||
class mpdevil(Gtk.Application):
|
class mpdevil(Gtk.Application):
|
||||||
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)
|
||||||
|
@@ -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.4.4])
|
AC_INIT([mpdevil], [0.5.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])
|
||||||
|
Reference in New Issue
Block a user