mirror of
https://github.com/SoongNoonien/mpdevil.git
synced 2023-08-10 21:12:44 +03:00
use new mpd commands 'albumart' and 'readpicture' to load missing covers
This commit is contained in:
parent
c01360b298
commit
7113d9d5e4
150
bin/mpdevil
150
bin/mpdevil
@ -389,9 +389,9 @@ class MPRISInterface: # TODO emit Seeked if needed
|
||||
else:
|
||||
lib_path=self._settings.get_value("paths")[self._settings.get_int("active-profile")]
|
||||
self._metadata["xesam:url"]=GLib.Variant("s", "file://{}".format(os.path.join(lib_path, song_file)))
|
||||
cover=Cover(self._settings, mpd_meta)
|
||||
if cover.path is not None:
|
||||
self._metadata["mpris:artUrl"]=GLib.Variant("s", "file://{}".format(cover.path))
|
||||
cover_path=self._client.get_cover_path(mpd_meta)
|
||||
if cover_path is not None:
|
||||
self._metadata["mpris:artUrl"]=GLib.Variant("s", "file://{}".format(cover_path))
|
||||
|
||||
def _update_property(self, interface_name, prop):
|
||||
getter, setter=self._prop_mapping[interface_name][prop]
|
||||
@ -501,6 +501,18 @@ class ClientHelper():
|
||||
length=length+float(song.get("duration", 0.0))
|
||||
return ClientHelper.seconds_to_display_time(int(length))
|
||||
|
||||
def binary_to_pixbuf(binary, size):
|
||||
loader=GdkPixbuf.PixbufLoader.new()
|
||||
loader.write(binary)
|
||||
loader.close()
|
||||
raw_pixbuf=loader.get_pixbuf()
|
||||
ratio=raw_pixbuf.get_width()/raw_pixbuf.get_height()
|
||||
if ratio > 1:
|
||||
pixbuf=raw_pixbuf.scale_simple(size,size/ratio,GdkPixbuf.InterpType.BILINEAR)
|
||||
else:
|
||||
pixbuf=raw_pixbuf.scale_simple(size*ratio,size,GdkPixbuf.InterpType.BILINEAR)
|
||||
return pixbuf
|
||||
|
||||
class EventEmitter(GObject.Object):
|
||||
__gsignals__={
|
||||
"update": (GObject.SignalFlags.RUN_FIRST, None, ()),
|
||||
@ -532,6 +544,7 @@ class Client(MPDClient):
|
||||
self._last_status={}
|
||||
self._refresh_interval=self._settings.get_int("refresh-interval")
|
||||
self._main_timeout_id=None
|
||||
self.fallback_cover=Gtk.IconTheme.get_default().lookup_icon("media-optical", 128, Gtk.IconLookupFlags.FORCE_SVG).get_filename()
|
||||
|
||||
# connect
|
||||
self._settings.connect("changed::active-profile", self._on_active_profile_changed)
|
||||
@ -670,6 +683,63 @@ class Client(MPDClient):
|
||||
else:
|
||||
return([])
|
||||
|
||||
def get_cover_path(self, raw_song):
|
||||
path=None
|
||||
song=ClientHelper.song_to_first_str_dict(raw_song)
|
||||
song_file=song.get("file")
|
||||
active_profile=self._settings.get_int("active-profile")
|
||||
lib_path=self._settings.get_lib_path()
|
||||
if lib_path is not None:
|
||||
regex_str=self._settings.get_value("regex")[active_profile]
|
||||
if regex_str == "":
|
||||
regex=re.compile(COVER_REGEX, flags=re.IGNORECASE)
|
||||
else:
|
||||
regex_str=regex_str.replace("%AlbumArtist%", song.get("albumartist", ""))
|
||||
regex_str=regex_str.replace("%Album%", song.get("album", ""))
|
||||
try:
|
||||
regex=re.compile(regex_str, flags=re.IGNORECASE)
|
||||
except:
|
||||
print("illegal regex:", regex_str)
|
||||
return (None, None)
|
||||
if song_file is not None:
|
||||
song_dir=os.path.join(lib_path, os.path.dirname(song_file))
|
||||
if song_dir.endswith(".cue"):
|
||||
song_dir=os.path.dirname(song_dir) # get actual directory of .cue file
|
||||
if os.path.exists(song_dir):
|
||||
for f in os.listdir(song_dir):
|
||||
if regex.match(f):
|
||||
path=os.path.join(song_dir, f)
|
||||
break
|
||||
return path
|
||||
|
||||
def get_cover_binary(self, uri):
|
||||
if uri is None:
|
||||
binary=None
|
||||
else:
|
||||
try:
|
||||
binary=self.albumart(uri)["binary"]
|
||||
except:
|
||||
try:
|
||||
binary=self.readpicture(uri)["binary"]
|
||||
except:
|
||||
binary=None
|
||||
return binary
|
||||
|
||||
def get_cover(self, song, size):
|
||||
cover_path=self.get_cover_path(song)
|
||||
if cover_path is None:
|
||||
cover_binary=self.get_cover_binary(song.get("file"))
|
||||
if cover_binary is None:
|
||||
pixbuf=GdkPixbuf.Pixbuf.new_from_file_at_size(self.fallback_cover, size, size)
|
||||
else:
|
||||
pixbuf=ClientHelper.binary_to_pixbuf(cover_binary, size)
|
||||
else:
|
||||
try:
|
||||
pixbuf=GdkPixbuf.Pixbuf.new_from_file_at_size(cover_path, size, size)
|
||||
except: # load fallback if cover can't be loaded (GLib: Couldn’t recognize the image file format for file...)
|
||||
pixbuf=GdkPixbuf.Pixbuf.new_from_file_at_size(self.fallback_cover, size, size)
|
||||
return pixbuf
|
||||
|
||||
def get_metadata(self, uri):
|
||||
meta_base=self.lsinfo(uri)[0]
|
||||
try: # .cue files produce an error here
|
||||
@ -702,7 +772,15 @@ class Client(MPDClient):
|
||||
years=self.comp_list("date", "album", album, artist_type, artist)
|
||||
for year in years:
|
||||
songs=self.find("album", album, "date", year, artist_type, artist, *genre_filter)
|
||||
cover_path=self.get_cover_path(songs[0])
|
||||
if cover_path is None:
|
||||
cover_binary=self.get_cover_binary(songs[0].get("file"))
|
||||
if cover_binary is None:
|
||||
albums.append({"artist": artist, "album": album, "year": year, "songs": songs})
|
||||
else:
|
||||
albums.append({"artist":artist,"album":album,"year":year,"songs":songs,"cover_binary":cover_binary})
|
||||
else:
|
||||
albums.append({"artist": artist, "album": album, "year": year, "songs": songs, "cover_path": cover_path})
|
||||
return albums
|
||||
|
||||
def toggle_play(self):
|
||||
@ -1763,47 +1841,6 @@ class ArtistPopover(Gtk.Popover):
|
||||
self._client.artist_to_playlist(self._artist, self._genre, mode)
|
||||
self.popdown()
|
||||
|
||||
class Cover(object):
|
||||
def __init__(self, settings, raw_song):
|
||||
self.path=None
|
||||
song=ClientHelper.song_to_first_str_dict(raw_song)
|
||||
if song != {}:
|
||||
song_file=song["file"]
|
||||
active_profile=settings.get_int("active-profile")
|
||||
lib_path=settings.get_lib_path()
|
||||
if lib_path is not None:
|
||||
regex_str=settings.get_value("regex")[active_profile]
|
||||
if regex_str == "":
|
||||
regex=re.compile(COVER_REGEX, flags=re.IGNORECASE)
|
||||
else:
|
||||
regex_str=regex_str.replace("%AlbumArtist%", song.get("albumartist", ""))
|
||||
regex_str=regex_str.replace("%Album%", song.get("album", ""))
|
||||
try:
|
||||
regex=re.compile(regex_str, flags=re.IGNORECASE)
|
||||
except:
|
||||
print("illegal regex:", regex_str)
|
||||
return
|
||||
if song_file is not None:
|
||||
song_dir=os.path.join(lib_path, os.path.dirname(song_file))
|
||||
if song_dir.endswith(".cue"):
|
||||
song_dir=os.path.dirname(song_dir) # get actual directory of .cue file
|
||||
if os.path.exists(song_dir):
|
||||
for f in os.listdir(song_dir):
|
||||
if regex.match(f):
|
||||
self.path=os.path.join(song_dir, f)
|
||||
break
|
||||
|
||||
def get_pixbuf(self, size):
|
||||
if self.path is None: # fallback needed
|
||||
path=Gtk.IconTheme.get_default().lookup_icon("media-optical", size, Gtk.IconLookupFlags.FORCE_SVG).get_filename()
|
||||
return GdkPixbuf.Pixbuf.new_from_file_at_size(path, size, size)
|
||||
else:
|
||||
try:
|
||||
return GdkPixbuf.Pixbuf.new_from_file_at_size(self.path, size, size)
|
||||
except: # load fallback if cover can't be loaded (GLib: Couldn’t recognize the image file format for file...)
|
||||
path=Gtk.IconTheme.get_default().lookup_icon("media-optical", size, Gtk.IconLookupFlags.FORCE_SVG).get_filename()
|
||||
return GdkPixbuf.Pixbuf.new_from_file_at_size(path, size, size)
|
||||
|
||||
###########
|
||||
# browser #
|
||||
###########
|
||||
@ -2288,10 +2325,6 @@ class AlbumWindow(FocusFrame):
|
||||
else:
|
||||
self._store.set_sort_column_id(1, Gtk.SortType.ASCENDING)
|
||||
|
||||
def _add_row(self, row): # needed for GLib.idle
|
||||
self._store.append(row)
|
||||
return False # stop after one run
|
||||
|
||||
def _refresh(self, *args):
|
||||
if self._done:
|
||||
self._done=False
|
||||
@ -2362,20 +2395,29 @@ class AlbumWindow(FocusFrame):
|
||||
self._done_callback()
|
||||
return False
|
||||
|
||||
def load_covers():
|
||||
def render_covers():
|
||||
size=self._settings.get_int("album-cover")
|
||||
total_albums=len(albums)
|
||||
for i, album in enumerate(albums):
|
||||
if self._stop_flag:
|
||||
break
|
||||
album["cover"]=Cover(self._settings, album["songs"][0]).get_pixbuf(size)
|
||||
if "cover_path" in album:
|
||||
try:
|
||||
album["cover"]=GdkPixbuf.Pixbuf.new_from_file_at_size(album["cover_path"], size, size)
|
||||
except: # load fallback if cover can't be loaded
|
||||
album["cover"]=GdkPixbuf.Pixbuf.new_from_file_at_size(self._client.fallback_cover, size, size)
|
||||
else:
|
||||
if "cover_binary" in album:
|
||||
album["cover"]=ClientHelper.binary_to_pixbuf(album["cover_binary"], size)
|
||||
else:
|
||||
album["cover"]=GdkPixbuf.Pixbuf.new_from_file_at_size(self._client.fallback_cover, size, size)
|
||||
GLib.idle_add(self._progress_bar.set_fraction, (i+1)/total_albums)
|
||||
if self._stop_flag:
|
||||
GLib.idle_add(self._done_callback)
|
||||
else:
|
||||
GLib.idle_add(display_albums)
|
||||
|
||||
cover_thread=threading.Thread(target=load_covers, daemon=True)
|
||||
cover_thread=threading.Thread(target=render_covers, daemon=True)
|
||||
cover_thread.start()
|
||||
elif not self._refresh in self._pending:
|
||||
self._stop_flag=True
|
||||
@ -2777,11 +2819,11 @@ class MainCover(Gtk.Image):
|
||||
|
||||
def _refresh(self, *args):
|
||||
current_song=self._client.currentsong()
|
||||
self.set_from_pixbuf(Cover(self._settings, current_song).get_pixbuf(self._settings.get_int("track-cover")))
|
||||
self.set_from_pixbuf(self._client.get_cover(current_song, self._settings.get_int("track-cover")))
|
||||
|
||||
def _on_disconnected(self, *args):
|
||||
size=self._settings.get_int("track-cover")
|
||||
self.set_from_pixbuf(Cover(self._settings, {}).get_pixbuf(size))
|
||||
self.set_from_pixbuf(GdkPixbuf.Pixbuf.new_from_file_at_size(self._client.fallback_cover, size, size))
|
||||
self.set_sensitive(False)
|
||||
|
||||
def _on_reconnected(self, *args):
|
||||
@ -3940,7 +3982,7 @@ class MainWindow(Gtk.ApplicationWindow):
|
||||
if self._settings.get_boolean("send-notify"):
|
||||
if not self.is_active() and self._client.status()["state"] == "play":
|
||||
notify=Notify.Notification.new(song["title"], song["artist"]+"\n"+song["album"]+date)
|
||||
pixbuf=Cover(self._settings, song).get_pixbuf(400)
|
||||
pixbuf=self._client.get_cover(song, 400)
|
||||
notify.set_image_from_pixbuf(pixbuf)
|
||||
notify.show()
|
||||
|
||||
|
Loading…
Reference in New Issue
Block a user