15 Commits

Author SHA1 Message Date
Martin Wagner
f13884d059 preparations for 0.8.3 2020-06-21 20:19:11 +02:00
Martin Wagner
600e0d5c84 fixed default column sizes 2020-06-21 20:00:19 +02:00
Martin Wagner
57ace9ec32 adjusted defaults 2020-06-21 19:53:42 +02:00
Martin Wagner
38b2286f09 made button presses in AlbumIconView less aggressive 2020-06-17 19:21:07 +02:00
Martin Wagner
03ee15854c display total duration in AlbumDialog 2020-06-14 22:34:01 +02:00
Martin Wagner
8ab8e7aa29 fixed bug in SongsView 2020-06-14 22:25:40 +02:00
Martin Wagner
8a46bab4da disabled opening of multiple lyrics overlays 2020-06-13 00:03:53 +02:00
Martin Wagner
d198c3a9f1 made lyrics button always visible 2020-06-10 22:09:23 +02:00
Martin Wagner
7ad93a0943 added missing FocusFrame in LyricsWindow 2020-06-06 14:20:05 +02:00
Martin Wagner
dc6b802245 added search by tag 2020-06-05 17:43:34 +02:00
Martin Wagner
7afc76b4f8 extracted independent functions from 'Client' 2020-06-04 20:36:34 +02:00
Martin Wagner
3f400e18b0 fixed displaying of multitag songs in SongPopover 2020-06-04 20:13:43 +02:00
Martin Wagner
f9b632802f fixed bug in AlbumDialog 2020-06-04 20:00:51 +02:00
Martin Wagner
b3d96f3e9f improved displaying of compilation albums 2020-06-04 19:34:36 +02:00
Martin Wagner
5c2cc71fb3 fixed back_to_album 2020-06-01 11:13:11 +02:00
6 changed files with 218 additions and 172 deletions

View File

@@ -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.
![ScreenShot](screenshots/mainwindow_0.8.2.png)
![ScreenShot](screenshots/mainwindow_0.8.3.png)
Features
--------

View File

@@ -183,6 +183,37 @@ class MpdEventEmitter(GObject.Object):
def do_periodic_signal(self):
pass
class ClientHelper():
def song_to_str_dict(song): #converts tags with multiple values to comma separated strings
return_song=song
for tag, value in return_song.items():
if type(value) == list:
return_song[tag]=(', '.join(value))
return return_song
def song_to_first_str_dict(song): #extracts the first value of multiple value tags
return_song=song
for tag, value in return_song.items():
if type(value) == list:
return_song[tag]=value[0]
return return_song
def extend_song_for_display(song):
base_song={"title": _("Unknown Title"), "track": "0", "disc": "", "artist": _("Unknown Artist"), "album": _("Unknown Album"), "duration": "0.0", "date": "", "genre": ""}
base_song.update(song)
base_song["human_duration"]=str(datetime.timedelta(seconds=int(float(base_song["duration"])))).lstrip("0").lstrip(":")
return base_song
def calc_display_length(songs):
length=float(0)
for song in songs:
try:
dura=float(song["duration"])
except:
dura=0.0
length=length+dura
return str(datetime.timedelta(seconds=int(length))).lstrip("0").lstrip(":")
class Client(MPDClient):
def __init__(self, settings):
MPDClient.__init__(self)
@@ -242,36 +273,6 @@ class Client(MPDClient):
songs=self.find("album", album, "date", year, self.settings.get_artist_type(), artist)
self.files_to_playlist([song['file'] for song in songs], append, force)
def song_to_str_dict(self, song): #converts tags with multiple values to comma separated strings
return_song=song
for tag, value in return_song.items():
if type(value) == list:
return_song[tag]=(', '.join(value))
return return_song
def song_to_first_str_dict(self, song): #extracts the first value of multiple value tags
return_song=song
for tag, value in return_song.items():
if type(value) == list:
return_song[tag]=value[0]
return return_song
def extend_song_for_display(self, song):
base_song={"title": _("Unknown Title"), "track": "0", "disc": "", "artist": _("Unknown Artist"), "album": _("Unknown Album"), "duration": "0.0", "date": "", "genre": ""}
base_song.update(song)
base_song["human_duration"]=str(datetime.timedelta(seconds=int(float(base_song["duration"])))).lstrip("0").lstrip(":")
return base_song
def calc_display_length(self, songs):
length=float(0)
for song in songs:
try:
dura=float(song["duration"])
except:
dura=0.0
length=length+dura
return str(datetime.timedelta(seconds=int(length))).lstrip("0").lstrip(":")
def comp_list(self, *args): #simulates listing behavior of python-mpd2 1.0
if "group" in args:
raise ValueError("'group' is not supported")
@@ -937,6 +938,7 @@ class SongPopover(Gtk.Popover):
#packing
self.add(frame)
song=ClientHelper.song_to_str_dict(song)
for tag, value in song.items():
tooltip=value.replace("&", "&")
if tag == "time":
@@ -951,89 +953,47 @@ class SongPopover(Gtk.Popover):
# self.treeview.queue_resize()
class SongsView(Gtk.TreeView):
def __init__(self, client, show_album=True, sort_enable=True):
def __init__(self, client, store, file_column_id):
Gtk.TreeView.__init__(self)
self.set_model(store)
self.set_search_column(-1)
self.columns_autosize()
#add vars
self.client=client
self.songs=[]
#store
#(track, title, artist, album, duration, file)
self.store=Gtk.ListStore(int, str, str, str, str, str)
self.set_model(self.store)
self.store=store
self.file_column_id=file_column_id
#selection
self.selection=self.get_selection()
self.selection.set_mode(Gtk.SelectionMode.SINGLE)
#columns
renderer_text=Gtk.CellRendererText(ellipsize=Pango.EllipsizeMode.END, ellipsize_set=True)
renderer_text_ralign=Gtk.CellRendererText(xalign=1.0)
self.column_track=Gtk.TreeViewColumn(_("No"), renderer_text_ralign, text=0)
self.column_track.set_sizing(Gtk.TreeViewColumnSizing.AUTOSIZE)
self.column_track.set_property("resizable", False)
self.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.column_title.set_property("expand", True)
self.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.column_artist.set_property("expand", True)
self.append_column(self.column_artist)
self.column_album=Gtk.TreeViewColumn(_("Album"), renderer_text, text=3)
self.column_album.set_sizing(Gtk.TreeViewColumnSizing.AUTOSIZE)
self.column_album.set_property("resizable", False)
self.column_album.set_property("expand", True)
if show_album:
self.append_column(self.column_album)
self.column_time=Gtk.TreeViewColumn(_("Length"), renderer_text, text=4)
self.column_time.set_sizing(Gtk.TreeViewColumnSizing.AUTOSIZE)
self.column_time.set_property("resizable", False)
self.append_column(self.column_time)
if sort_enable:
self.column_track.set_sort_column_id(0)
self.column_title.set_sort_column_id(1)
self.column_artist.set_sort_column_id(2)
self.column_album.set_sort_column_id(3)
self.column_time.set_sort_column_id(4)
#connect
self.connect("row-activated", self.on_row_activated)
self.connect("button-press-event", self.on_button_press_event)
self.key_press_event=self.connect("key-press-event", self.on_key_press_event)
def on_row_activated(self, widget, path, view_column):
self.client.files_to_playlist([self.store[path][5]], False, True)
self.client.files_to_playlist([self.store[path][self.file_column_id]], False, True)
def on_button_press_event(self, widget, event):
if event.button == 1 and event.type == Gdk.EventType.BUTTON_PRESS:
try:
path=widget.get_path_at_pos(int(event.x), int(event.y))[0]
self.client.files_to_playlist([self.store[path][5]], False)
self.client.files_to_playlist([self.store[path][self.file_column_id]], False)
except:
pass
elif event.button == 2 and event.type == Gdk.EventType.BUTTON_PRESS:
try:
path=widget.get_path_at_pos(int(event.x), int(event.y))[0]
self.client.files_to_playlist([self.store[path][5]], True)
self.client.files_to_playlist([self.store[path][self.file_column_id]], True)
except:
pass
elif event.button == 3 and event.type == Gdk.EventType.BUTTON_PRESS:
try:
path=widget.get_path_at_pos(int(event.x), int(event.y))[0]
pop=SongPopover(self.songs[int(str(path))], widget, int(event.x), int(event.y))
file_name=self.store[path][self.file_column_id]
pop=SongPopover(self.client.lsinfo(file_name)[0], widget, int(event.x), int(event.y))
pop.popup()
pop.show_all()
except:
@@ -1044,22 +1004,15 @@ class SongsView(Gtk.TreeView):
if event.keyval == 112: #p
treeview, treeiter=self.selection.get_selected()
if not treeiter == None:
self.client.files_to_playlist([self.store.get_value(treeiter, 5)], False)
self.client.files_to_playlist([self.store.get_value(treeiter, self.file_column_id)], False)
elif event.keyval == 97: #a
treeview, treeiter=self.selection.get_selected()
if not treeiter == None:
self.client.files_to_playlist([self.store.get_value(treeiter, 5)], True)
self.client.files_to_playlist([self.store.get_value(treeiter, self.file_column_id)], True)
# elif event.keyval == 65383: #menu key
self.handler_unblock(self.key_press_event)
def populate(self, songs):
self.songs=songs
for s in songs:
song=self.client.extend_song_for_display(self.client.song_to_str_dict(s))
self.store.append([int(song["track"]), song["title"], song["artist"], song["album"], song["human_duration"], song["file"]])
def clear(self):
self.songs=[]
self.store.clear()
def count(self):
@@ -1068,7 +1021,7 @@ class SongsView(Gtk.TreeView):
def get_files(self):
return_list=[]
for row in self.store:
return_list.append(row[5])
return_list.append(row[self.file_column_id])
return return_list
class AlbumDialog(Gtk.Dialog):
@@ -1076,6 +1029,16 @@ class AlbumDialog(Gtk.Dialog):
Gtk.Dialog.__init__(self, transient_for=parent)
self.add_buttons(Gtk.STOCK_ADD, Gtk.ResponseType.ACCEPT, Gtk.STOCK_MEDIA_PLAY, Gtk.ResponseType.YES, Gtk.STOCK_OPEN, Gtk.ResponseType.OK, Gtk.STOCK_CLOSE, Gtk.ResponseType.CLOSE)
#metadata
self.album=album
self.artist=artist
self.year=year
#adding vars
self.client=client
self.settings=settings
songs=self.client.find("album", self.album, "date", self.year, self.settings.get_artist_type(), self.artist)
#determine size
size=parent.get_size()
diagonal=(size[0]**2+size[1]**2)**(0.5)
@@ -1084,23 +1047,58 @@ class AlbumDialog(Gtk.Dialog):
self.set_default_size(w, h)
#title
album_duration=ClientHelper.calc_display_length(songs)
if year == "":
self.set_title(artist+" - "+album)
self.set_title(artist+" - "+album+" ("+album_duration+")")
else:
self.set_title(artist+" - "+album+" ("+year+")")
self.set_title(artist+" - "+album+" ("+year+") ("+album_duration+")")
#adding vars
self.client=client
self.settings=settings
#metadata
self.album=album
self.artist=artist
self.year=year
#store
#(track, title (artist), duration, file)
self.store=Gtk.ListStore(int, str, str, str)
#songs view
self.songs_view=SongsView(self.client, False, False)
self.songs_view.populate(self.client.find("album", self.album, "date", self.year, self.settings.get_artist_type(), self.artist))
self.songs_view=SongsView(self.client, self.store, 3)
for s in songs:
song=ClientHelper.extend_song_for_display(s)
if type(song["title"]) == list: # could be impossible
title=(', '.join(song["title"]))
else:
title=song["title"]
if type(song["artist"]) == list:
try:
song["artist"].remove(self.artist)
except:
pass
artist=(', '.join(song["artist"]))
else:
artist=song["artist"]
if artist != self.artist:
title_artist="<b>"+title+"</b> - "+artist
else:
title_artist="<b>"+title+"</b>"
title_artist=title_artist.replace("&", "&amp;")
self.store.append([int(song["track"]), title_artist, song["human_duration"], song["file"]])
#columns
renderer_text=Gtk.CellRendererText(ellipsize=Pango.EllipsizeMode.END, ellipsize_set=True)
renderer_text_ralign=Gtk.CellRendererText(xalign=1.0)
self.column_track=Gtk.TreeViewColumn(_("No"), renderer_text_ralign, text=0)
self.column_track.set_sizing(Gtk.TreeViewColumnSizing.AUTOSIZE)
self.column_track.set_property("resizable", False)
self.songs_view.append_column(self.column_track)
self.column_title=Gtk.TreeViewColumn(_("Title"), renderer_text, markup=1)
self.column_title.set_sizing(Gtk.TreeViewColumnSizing.AUTOSIZE)
self.column_title.set_property("resizable", False)
self.column_title.set_property("expand", True)
self.songs_view.append_column(self.column_title)
self.column_time=Gtk.TreeViewColumn(_("Length"), renderer_text, text=2)
self.column_time.set_sizing(Gtk.TreeViewColumnSizing.AUTOSIZE)
self.column_time.set_property("resizable", False)
self.songs_view.append_column(self.column_time)
#scroll
scroll=Gtk.ScrolledWindow()
@@ -1282,6 +1280,7 @@ class AlbumIconView(Gtk.IconView):
self.genre_select=genre_select
self.window=window
self.stop_flag=True
self.button_event=(None, None)
#cover, display_label, display_label_artist, tooltip(titles), album, year, artist
self.store=Gtk.ListStore(GdkPixbuf.Pixbuf, str, str, str, str, str, str)
@@ -1296,6 +1295,7 @@ class AlbumIconView(Gtk.IconView):
#connect
self.connect("item-activated", self.on_item_activated)
self.connect("button-release-event", self.on_button_release_event)
self.connect("button-press-event", self.on_button_press_event)
self.key_press_event=self.connect("key-press-event", self.on_key_press_event)
self.settings.connect("changed::show-album-view-tooltips", self.tooltip_settings)
@@ -1366,7 +1366,7 @@ class AlbumIconView(Gtk.IconView):
if not self.stop_flag:
cover=Cover(lib_path=music_lib, song_file=album["songs"][0]["file"])
#tooltip
length_human_readable=self.client.calc_display_length(album["songs"])
length_human_readable=ClientHelper.calc_display_length(album["songs"])
try:
discs=int(album["songs"][-1]["disc"])
except:
@@ -1390,7 +1390,7 @@ class AlbumIconView(Gtk.IconView):
GLib.idle_add(self.emit, "done")
def scroll_to_selected_album(self):
song=self.client.song_to_first_str_dict(self.client.currentsong())
song=ClientHelper.song_to_first_str_dict(self.client.currentsong())
self.unselect_all()
row_num=len(self.store)
for i in range(0, row_num):
@@ -1418,13 +1418,19 @@ class AlbumIconView(Gtk.IconView):
album_dialog.destroy()
def on_button_press_event(self, widget, event):
path=widget.get_path_at_pos(int(event.x), int(event.y))
if event.type == Gdk.EventType.BUTTON_PRESS:
self.button_event=(event.button, path)
def on_button_release_event(self, widget, event):
path=widget.get_path_at_pos(int(event.x), int(event.y))
if not path == None:
if event.button == 1 and event.type == Gdk.EventType.BUTTON_PRESS:
if self.button_event == (event.button, path):
if event.button == 1 and event.type == Gdk.EventType.BUTTON_RELEASE:
self.path_to_playlist(path, False)
elif event.button == 2 and event.type == Gdk.EventType.BUTTON_PRESS:
elif event.button == 2 and event.type == Gdk.EventType.BUTTON_RELEASE:
self.path_to_playlist(path, True)
elif event.button == 3 and event.type == Gdk.EventType.BUTTON_PRESS:
elif event.button == 3 and event.type == Gdk.EventType.BUTTON_RELEASE:
self.open_album_dialog(path)
def on_key_press_event(self, widget, event):
@@ -1570,7 +1576,7 @@ class MainCover(Gtk.Frame):
def on_button_press_event(self, widget, event):
if self.client.connected():
song=self.client.song_to_first_str_dict(self.client.currentsong())
song=ClientHelper.song_to_first_str_dict(self.client.currentsong())
if not song == {}:
try:
artist=song[self.settings.get_artist_type()]
@@ -1729,7 +1735,7 @@ class PlaylistView(Gtk.Box):
def refresh_playlist_info(self):
songs=self.client.playlistinfo()
if not songs == []:
whole_length_human_readable=self.client.calc_display_length(songs)
whole_length_human_readable=ClientHelper.calc_display_length(songs)
self.playlist_info.set_text(_("%(total_tracks)i titles (%(total_length)s)") % {"total_tracks": len(songs), "total_length": whole_length_human_readable})
else:
self.playlist_info.set_text("")
@@ -1796,7 +1802,7 @@ class PlaylistView(Gtk.Box):
if not songs == []:
self.playlist_info.set_text("")
for s in songs:
song=self.client.extend_song_for_display(self.client.song_to_str_dict(s))
song=ClientHelper.extend_song_for_display(ClientHelper.song_to_str_dict(s))
try:
treeiter=self.store.get_iter(song["pos"])
self.store.set(treeiter, 0, song["track"], 1, song["disc"], 2, song["title"], 3, song["artist"], 4, song["album"], 5, song["human_duration"], 6, song["date"], 7, song["genre"], 8, song["file"], 9, Pango.Weight.BOOK)
@@ -1824,7 +1830,6 @@ class CoverLyricsOSD(Gtk.Overlay):
self.client=client
self.settings=settings
self.window=window
self.hide_timeout_id=None
#cover
self.cover=MainCover(self.client, self.settings, self.window)
@@ -1832,71 +1837,50 @@ class CoverLyricsOSD(Gtk.Overlay):
#lyrics button
self.lyrics_button=Gtk.Button(image=Gtk.Image.new_from_icon_name("media-view-subtitles-symbolic", Gtk.IconSize.BUTTON))
self.lyrics_button.set_label(_("Show lyrics"))
self.lyrics_button.set_margin_top(12)
self.lyrics_button.set_tooltip_text(_("Show lyrics"))
style_context=self.lyrics_button.get_style_context()
style_context.add_class("osd")
style_context.add_class("circular")
#revealer
self.revealer=Gtk.Revealer()
self.revealer.set_halign(3)
self.revealer.set_valign(1)
self.revealer.add(self.lyrics_button)
#workaround to get tooltips in overlay
revealer=Gtk.Revealer()
revealer.set_halign(2)
revealer.set_valign(1)
revealer.set_margin_top(6)
revealer.set_margin_end(6)
revealer.add(self.lyrics_button)
revealer.set_reveal_child(True)
#event box
self.event_box=Gtk.EventBox()
self.event_box.set_events(Gdk.EventMask.POINTER_MOTION_MASK)
self.event_box.add(self.cover)
#packing
self.add(self.event_box)
self.add_overlay(self.revealer)
self.add_overlay(revealer)
#connect
self.lyrics_button.connect("clicked", self.on_lyrics_clicked)
self.motion_notify_event=self.event_box.connect("motion-notify-event", self.on_motion_notify_event)
self.lyrics_button.connect("enter-notify-event", self.on_enter_notify_event)
self.lyrics_button.connect("leave-notify-event", self.on_leave_notify_event)
self.client.emitter.connect("disconnected", self.on_disconnected)
self.client.emitter.connect("reconnected", self.on_reconnected)
self.event_box.handler_block(self.motion_notify_event)
def on_reconnected(self, *args):
self.event_box.handler_unblock(self.motion_notify_event)
self.lyrics_button.set_sensitive(True)
def on_disconnected(self, *args):
self.lyrics_button.set_sensitive(False)
self.cover.clear()
self.event_box.handler_block(self.motion_notify_event)
self.hide_lyrics_button()
try:
self.lyrics_win.destroy()
except:
pass
def hide_lyrics_button(self, *args):
self.revealer.set_reveal_child(False)
self.hide_timeout_id=None
return False
def on_motion_notify_event(self, *args):
self.revealer.set_reveal_child(True)
if not self.hide_timeout_id == None:
GLib.source_remove(self.hide_timeout_id)
self.hide_timeout_id=GLib.timeout_add(1000, self.hide_lyrics_button)
def on_enter_notify_event(self, *args):
if not self.hide_timeout_id == None:
GLib.source_remove(self.hide_timeout_id)
self.hide_timeout_id=None
def on_leave_notify_event(self, *args):
if not self.hide_timeout_id == None:
GLib.source_remove(self.hide_timeout_id)
self.hide_timeout_id=GLib.timeout_add(1000, self.hide_lyrics_button)
def on_lyrics_clicked(self, widget):
self.hide_lyrics_button()
self.lyrics_button.set_sensitive(False)
self.lyrics_win=LyricsWindow(self.client, self.settings)
def on_destroy(*args):
self.lyrics_button.set_sensitive(True)
self.lyrics_win.connect("destroy", on_destroy)
self.add_overlay(self.lyrics_win)
class Browser(Gtk.Box):
@@ -1995,7 +1979,7 @@ class Browser(Gtk.Box):
def back_to_album(self, *args):
try: #since this can still be running when the connection is lost, various exceptions can occur
song=self.client.song_to_first_str_dict(self.client.currentsong())
song=ClientHelper.song_to_first_str_dict(self.client.currentsong())
try:
artist=song[self.settings.get_artist_type()]
except:
@@ -2021,6 +2005,7 @@ class Browser(Gtk.Box):
self.artist_view.highlight_selected()
break
else:
self.search_button.set_active(False)
self.artist_view.treeview.set_cursor(Gtk.TreePath(0), None, False) #set cursor to 'all artists'
self.album_view.scroll_to_selected_album()
except:
@@ -2953,18 +2938,61 @@ class SearchWindow(Gtk.Box):
#adding vars
self.client=client
#tag switcher
self.tags=Gtk.ComboBoxText()
#search entry
self.search_entry=Gtk.SearchEntry()
self.search_entry.set_margin_end(6)
self.search_entry.set_margin_start(6)
#label
self.label=Gtk.Label()
self.label.set_xalign(1)
self.label.set_margin_end(6)
#store
#(track, title, artist, album, duration, file)
self.store=Gtk.ListStore(int, str, str, str, str, str)
#songs view
self.songs_view=SongsView(self.client)
self.songs_view=SongsView(self.client, self.store, 5)
#columns
renderer_text=Gtk.CellRendererText(ellipsize=Pango.EllipsizeMode.END, ellipsize_set=True)
renderer_text_ralign=Gtk.CellRendererText(xalign=1.0)
self.column_track=Gtk.TreeViewColumn(_("No"), renderer_text_ralign, text=0)
self.column_track.set_sizing(Gtk.TreeViewColumnSizing.AUTOSIZE)
self.column_track.set_property("resizable", False)
self.songs_view.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.column_title.set_property("expand", True)
self.songs_view.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.column_artist.set_property("expand", True)
self.songs_view.append_column(self.column_artist)
self.column_album=Gtk.TreeViewColumn(_("Album"), renderer_text, text=3)
self.column_album.set_sizing(Gtk.TreeViewColumnSizing.AUTOSIZE)
self.column_album.set_property("resizable", False)
self.column_album.set_property("expand", True)
self.songs_view.append_column(self.column_album)
self.column_time=Gtk.TreeViewColumn(_("Length"), renderer_text, text=4)
self.column_time.set_sizing(Gtk.TreeViewColumnSizing.AUTOSIZE)
self.column_time.set_property("resizable", False)
self.songs_view.append_column(self.column_time)
self.column_track.set_sort_column_id(0)
self.column_title.set_sort_column_id(1)
self.column_artist.set_sort_column_id(2)
self.column_album.set_sort_column_id(3)
self.column_time.set_sort_column_id(4)
#scroll
scroll=Gtk.ScrolledWindow()
@@ -2984,11 +3012,17 @@ class SearchWindow(Gtk.Box):
#connect
self.search_entry.connect("search-changed", self.on_search_changed)
self.tags.connect("changed", self.on_search_changed)
self.add_button.connect("clicked", self.on_add_clicked)
self.play_button.connect("clicked", self.on_play_clicked)
self.open_button.connect("clicked", self.on_open_clicked)
self.client.emitter.connect("reconnected", self.on_reconnected)
#packing
vbox=Gtk.Box(spacing=6)
vbox.set_property("border-width", 6)
vbox.pack_start(self.search_entry, True, True, 0)
vbox.pack_end(self.tags, False, False, 0)
frame=FocusFrame()
frame.set_widget(self.songs_view)
frame.add(scroll)
@@ -3000,7 +3034,7 @@ class SearchWindow(Gtk.Box):
hbox=Gtk.Box(orientation=Gtk.Orientation.HORIZONTAL)
hbox.pack_start(ButtonBox, 0, False, False)
hbox.pack_end(self.label, 0, False, False)
self.pack_start(self.search_entry, False, False, 6)
self.pack_start(vbox, False, False, 0)
self.pack_start(Gtk.Separator.new(orientation=Gtk.Orientation.HORIZONTAL), False, False, 0)
self.pack_start(frame, True, True, 0)
self.pack_start(Gtk.Separator.new(orientation=Gtk.Orientation.HORIZONTAL), False, False, 0)
@@ -3015,12 +3049,23 @@ class SearchWindow(Gtk.Box):
def clear(self, *args):
self.songs_view.clear()
self.search_entry.set_text("")
self.tags.remove_all()
def on_reconnected(self, *args):
self.tags.append_text("any")
for tag in self.client.tagtypes():
if not tag.startswith("MUSICBRAINZ"):
self.tags.append_text(tag)
self.tags.set_active(0)
def on_search_changed(self, widget):
self.songs_view.clear()
self.label.set_text("")
if len(self.search_entry.get_text()) > 1:
self.songs_view.populate(self.client.search("any", self.search_entry.get_text()))
songs=self.client.search(self.tags.get_active_text(), self.search_entry.get_text())
for s in songs:
song=ClientHelper.extend_song_for_display(ClientHelper.song_to_str_dict(s))
self.store.append([int(song["track"]), song["title"], song["artist"], song["album"], song["human_duration"], song["file"]])
self.label.set_text(_("hits: %i") % (self.songs_view.count()))
if self.songs_view.count() == 0:
self.add_button.set_sensitive(False)
@@ -3064,7 +3109,8 @@ class LyricsWindow(Gtk.Overlay):
self.scroll.add(self.text_view)
#frame
frame=Gtk.Frame()
frame=FocusFrame()
frame.set_widget(self.text_view)
style_context=frame.get_style_context()
provider=Gtk.CssProvider()
css=b"""* {border: 0px; background-color: @theme_base_color; opacity: 0.9;}"""
@@ -3106,7 +3152,7 @@ class LyricsWindow(Gtk.Overlay):
GLib.idle_add(self.text_buffer.set_text, text, -1)
def refresh(self, *args):
update_thread=threading.Thread(target=self.display_lyrics, kwargs={"current_song": self.client.song_to_first_str_dict(self.client.currentsong())}, daemon=True)
update_thread=threading.Thread(target=self.display_lyrics, kwargs={"current_song": ClientHelper.song_to_first_str_dict(self.client.currentsong())}, daemon=True)
update_thread.start()
def getLyrics(self, singer, song): #partially copied from PyLyrics 1.1.0
@@ -3257,7 +3303,7 @@ class MainWindow(Gtk.ApplicationWindow):
song=self.client.currentsong()
if song == {}:
raise ValueError("Song out of range")
song=self.client.extend_song_for_display(self.client.song_to_str_dict(song))
song=ClientHelper.extend_song_for_display(ClientHelper.song_to_str_dict(song))
if song["date"] != "":
date=" ("+song["date"]+")"
else:

View File

@@ -1,7 +1,7 @@
dnl -*- Mode: autoconf -*-
dnl Process this file with autoconf to produce a configure script.
AC_PREREQ([2.68])
AC_INIT([mpdevil], [0.8.2])
AC_INIT([mpdevil], [0.8.3])
AC_CONFIG_SRCDIR([bin/mpdevil.py])
AM_INIT_AUTOMAKE
AC_CONFIG_MACRO_DIR([m4])

View File

@@ -7,17 +7,17 @@
<description></description>
</key>
<key type="i" name="width">
<default>1050</default>
<default>1000</default>
<summary>Default width of window</summary>
<description></description>
</key>
<key type="i" name="height">
<default>1020</default>
<default>990</default>
<summary>Default height of window</summary>
<description></description>
</key>
<key type="i" name="paned0">
<default>350</default>
<default>370</default>
<summary>Default position of cover/playlist separator</summary>
<description></description>
</key>
@@ -27,12 +27,12 @@
<description></description>
</key>
<key type="i" name="paned2">
<default>598</default>
<default>572</default>
<summary>Default position of paned1/paned0 separator</summary>
<description></description>
</key>
<key type="i" name="album-cover">
<default>140</default>
<default>130</default>
<summary>Size of covers in album view</summary>
<description></description>
</key>
@@ -52,7 +52,7 @@
<description></description>
</key>
<key type="b" name="show-stop">
<default>false</default>
<default>true</default>
<summary>Show stop button</summary>
<description></description>
</key>
@@ -67,7 +67,7 @@
<description></description>
</key>
<key type="b" name="sort-albums-by-year">
<default>false</default>
<default>true</default>
<summary>Sort albums by year</summary>
<description></description>
</key>
@@ -102,7 +102,7 @@
<description></description>
</key>
<key type="ai" name="column-sizes">
<default>[0, 0, 0, 0, 0, 0, 0, 0]</default>
<default>[33, 0, 203, 153, 174, 0, 0, 0]</default>
<summary>Sizes of columns in playlist</summary>
<description></description>
</key>

Binary file not shown.

Before

Width:  |  Height:  |  Size: 1.0 MiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 1003 KiB