initial commit
Esse commit está contido em:
@@ -0,0 +1,130 @@
|
||||
[Plugin]
|
||||
Loader=python
|
||||
Module=ArtDisplay
|
||||
IAge=2
|
||||
Depends=rb;artsearch
|
||||
Name=Cover art
|
||||
Name[af]=Omslagkuns
|
||||
Name[ar]=صورة الغلاف
|
||||
Name[as]=ক'ভাৰ আৰ্ট
|
||||
Name[be]=Аздоба вокладкі
|
||||
Name[be@latin]=Azdoba vokładki
|
||||
Name[bg]=Обложка
|
||||
Name[br]=Godellig
|
||||
Name[ca]=Art de la coberta
|
||||
Name[ca@valencia]=Art de la coberta
|
||||
Name[cs]=Přebal
|
||||
Name[da]=Omslag
|
||||
Name[de]=Cover-Anzeige
|
||||
Name[dz]=ཁེབས་ཀྱི་རི་མོ།
|
||||
Name[el]=Εξώφυλλο
|
||||
Name[en_CA]=Cover art
|
||||
Name[en_GB]=Cover art
|
||||
Name[eo]=Kovrilo
|
||||
Name[es]=Arte de portada
|
||||
Name[et]=Plaadiümbrised
|
||||
Name[eu]=Azaleko diseinua
|
||||
Name[fi]=Kansikuvat
|
||||
Name[fr]=Pochette
|
||||
Name[gl]=Portada
|
||||
Name[gu]=કલાને આવરો
|
||||
Name[hi]=कवर आर्ट
|
||||
Name[hu]=Lemezborító
|
||||
Name[it]=Copertina
|
||||
Name[ja]=ジャケットのアート
|
||||
Name[kn]=ಹೊದಿಕೆ ವಿನ್ಯಾಸ
|
||||
Name[ko]=앨범 표지
|
||||
Name[lt]=Albumų viršeliai
|
||||
Name[lv]=Vāciņa attēls
|
||||
Name[mk]=Слика на омот
|
||||
Name[mr]=कवर कला
|
||||
Name[nb]=Omslag
|
||||
Name[ne]=आवरण कला
|
||||
Name[nl]=Albumhoezen
|
||||
Name[nn]=Plateomslag
|
||||
Name[pa]=ਕਵਰ ਕਲਾਕਾਰ
|
||||
Name[pl]=Okładki
|
||||
Name[pt]=Imagem da capa
|
||||
Name[pt_BR]=Arte de capa
|
||||
Name[ro]=Copertă
|
||||
Name[ru]=Обложки альбомов
|
||||
Name[sk]=Obal
|
||||
Name[sl]=Ovitki
|
||||
Name[sr]=Омот албума
|
||||
Name[sr@latin]=Omot albuma
|
||||
Name[sv]=Omslagsgrafik
|
||||
Name[ta]=கவர் ஆர்ட்
|
||||
Name[te]=ముఖచిత్రం
|
||||
Name[th]=ภาพปก
|
||||
Name[tr]=Albüm kapağı
|
||||
Name[uk]=Обкладинки альбомів
|
||||
Name[vi]=Ảnh bìa
|
||||
Name[zh_CN]=封面艺人
|
||||
Name[zh_HK]=專輯封面
|
||||
Name[zh_TW]=專輯封面
|
||||
Description=Fetch album covers from the Internet
|
||||
Description[af]=Kry albumomslae van die Internet af
|
||||
Description[ar]=لجلب أغلفة الألبومات من الإنترنت
|
||||
Description[as]=ইন্টাৰ্নে'টৰ পৰা এল্বামৰ ক'ভাৰ পাওক
|
||||
Description[be]=Сцягваць вокладкі альбомаў з Інтэрнэту
|
||||
Description[be@latin]=Zahružaj vokładki albomaŭ z Internetu
|
||||
Description[bg]=Изтегляне на обложки на албуми от Интернет
|
||||
Description[bn_IN]=ইন্টারনেট থেকে সংকলনের প্রচ্ছদের ছবি আহরণ করা হবে
|
||||
Description[br]=Pellgargañ godelligoù albom adalek ar Genrouedad
|
||||
Description[ca]=Aconsegueix les cobertes dels àlbums d'Internet
|
||||
Description[ca@valencia]=Aconsegueix les cobertes dels àlbums d'Internet
|
||||
Description[cs]=Načítat přebaly alb z Internetu
|
||||
Description[da]=Hent albumomslag fra internettet
|
||||
Description[de]=Album-Cover aus dem Internet nachladen
|
||||
Description[dz]=ཨིན་ཊར་ནེཊི་ལས་གླུ་མཛོད་ཁེབས་ཚུ་ལེན།
|
||||
Description[el]=Εύρεση εξώφυλλων άλμπουμ από Διαδίκτυο
|
||||
Description[en_CA]=Fetch album covers from the Internet
|
||||
Description[en_GB]=Fetch album covers from the Internet
|
||||
Description[eo]=Obteni kovrilon el interreto
|
||||
Description[es]=Buscar portadas de álbum de Internet
|
||||
Description[et]=Plaadiümbriste tõmbamine internetist
|
||||
Description[eu]=Eskuratu albumen azalak Internetetik
|
||||
Description[fi]=Hae levyjen kansikuvia Internetistä
|
||||
Description[fr]=Télécharge les pochettes d'album depuis Internet
|
||||
Description[gl]=Busque as portadas do álbum na Internet
|
||||
Description[gu]=ઇન્ટરનેટ માંથી આલ્બમ કવરોને પ્રાપ્ત કરો
|
||||
Description[hi]=इंटरनेट से एल्बम कवर लाएँ
|
||||
Description[hu]=Lemezborítók letöltése az internetről
|
||||
Description[it]=Recupera le copertine degli album da Internet
|
||||
Description[ja]=アルバムのジャケットをインターネットから取得します
|
||||
Description[kn]=ಅಂತರಜಾಲದಿಂದ ಆಲ್ಬಮ್ನ ಹೊದಿಕೆಗಳನ್ನು ಪಡೆದುಕೊಳ್ಳಿ
|
||||
Description[ko]=인터넷에서 앨범 표지를 가져옵니다
|
||||
Description[lt]=Atsiųsti albumų viršelius iš interneto
|
||||
Description[lv]=Ielādē albuma vāciņus no interneta
|
||||
Description[mk]=Собирај ги омотите за албумите од интернет
|
||||
Description[mr]=आंतरजाल पासून अल्बम कवर प्राप्त करा
|
||||
Description[nb]=Hent omslag fra internett
|
||||
Description[ne]=इन्टरनेटबाट एल्बम आवरणहरू तान्नुहोस्
|
||||
Description[nl]=Albumhoezen van het internet halen
|
||||
Description[nn]=Hent plateomslag frå Internett
|
||||
Description[pa]=ਇੰਟਰਨੈੱਟ ਤੋਂ ਐਲਬਮ ਢੱਕਣ ਲਵੋ
|
||||
Description[pl]=Pobiera okładki albumów z Internetu
|
||||
Description[pt]=Obter capa de álbuns da Internet
|
||||
Description[pt_BR]=Buscar capas dos álbuns na internet
|
||||
Description[ro]=Preia coperțile albumelor de pe Internet
|
||||
Description[ru]=Загрузка обложек альбомов из Интернета
|
||||
Description[sk]=Získať obaly albumov z Internetu
|
||||
Description[sl]=Pridobi naslovnice albumov z medmrežja
|
||||
Description[sr]=Преузмите омоте албума са Интернета
|
||||
Description[sr@latin]=Preuzmite omote albuma sa Interneta
|
||||
Description[sv]=Hämta omslagsgrafik från Internet
|
||||
Description[ta]=இணையத்திலிருந்து ஆல்பம் கவர்களை எடு
|
||||
Description[te]=ఆల్బమ్ కవర్లను అంతర్జాలం నుండి తీసుకొనిరమ్ము
|
||||
Description[th]=ดึงภาพปกอัลบั้มจากอินเทอร์เน็ต
|
||||
Description[tr]=Albüm kapaklarını internetten al
|
||||
Description[uk]=Звантаження обкладинок альбомів з інтернету
|
||||
Description[vi]=Lấy ảnh bìa tập nhạc từ Internet
|
||||
Description[zh_CN]=从互联网上获取专辑封面
|
||||
Description[zh_HK]=從網絡擷取專輯封面
|
||||
Description[zh_TW]=從網路擷取專輯封面
|
||||
Authors=James Livingston <doclivingston@gmail.com>
|
||||
Copyright=Copyright © 2006 James Livingston
|
||||
Website=http://www.rhythmbox.org/
|
||||
|
||||
[RB]
|
||||
InitiallyEnabled=true
|
||||
@@ -0,0 +1,411 @@
|
||||
# -*- Mode: python; coding: utf-8; tab-width: 8; indent-tabs-mode: t; -*-
|
||||
#
|
||||
# Copyright (C) 2006 - James Livingston
|
||||
#
|
||||
# This program is free software; you can redistribute it and/or modify
|
||||
# it under the terms of the GNU General Public License as published by
|
||||
# the Free Software Foundation; either version 2, or (at your option)
|
||||
# any later version.
|
||||
#
|
||||
# The Rhythmbox authors hereby grant permission for non-GPL compatible
|
||||
# GStreamer plugins to be used and distributed together with GStreamer
|
||||
# and Rhythmbox. This permission is above and beyond the permissions granted
|
||||
# by the GPL license by which Rhythmbox is covered. If you modify this code
|
||||
# you may extend this exception to your version of the code, but you are not
|
||||
# obligated to do so. If you do not wish to do so, delete this exception
|
||||
# statement from your version.
|
||||
#
|
||||
# This program is distributed in the hope that it will be useful,
|
||||
# but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
# GNU General Public License for more details.
|
||||
#
|
||||
# You should have received a copy of the GNU General Public License
|
||||
# along with this program; if not, write to the Free Software
|
||||
# Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
|
||||
|
||||
import gi
|
||||
|
||||
from warnings import warn
|
||||
|
||||
import rb
|
||||
from gi.repository import GObject, Gtk, Gdk, GdkPixbuf, Gio, Peas
|
||||
from gi.repository import RB
|
||||
|
||||
import gettext
|
||||
gettext.install('rhythmbox', RB.locale_dir())
|
||||
|
||||
import urllib
|
||||
|
||||
FADE_STEPS = 10
|
||||
FADE_TOTAL_TIME = 1000
|
||||
ART_MISSING_ICON = 'rhythmbox-missing-artwork'
|
||||
WORKING_DELAY = 500
|
||||
THROBBER_RATE = 10
|
||||
THROBBER = 'process-working'
|
||||
ASPECT_RATIO_MIN = 0.9
|
||||
ASPECT_RATIO_MAX = 1.1
|
||||
|
||||
def merge_pixbufs (old_pb, new_pb, reserve_pb, step, width, height, mode=GdkPixbuf.InterpType.BILINEAR):
|
||||
if width <= 1 and height <= 1:
|
||||
return None
|
||||
if old_pb is None:
|
||||
if new_pb is None:
|
||||
return reserve_pb
|
||||
else:
|
||||
return new_pb.scale_simple (width, height, mode)
|
||||
elif step == 0.0:
|
||||
return old_pb.scale_simple (width, height, mode)
|
||||
elif new_pb is None:
|
||||
if reserve_pb is None:
|
||||
return None
|
||||
new_pb = reserve_pb
|
||||
sw, sh = (float (width)) / new_pb.props.width, (float (height)) / new_pb.props.height
|
||||
alpha = int (step * 255)
|
||||
ret = old_pb.scale_simple (width, height, mode)
|
||||
new_pb.composite (ret, 0, 0, width, height, 0, 0, sw, sh, mode, alpha)
|
||||
return ret
|
||||
|
||||
def merge_with_background (pixbuf, bgcolor, pad_if_not_near_square):
|
||||
|
||||
if pixbuf is None:
|
||||
return pixbuf
|
||||
has_alpha = pixbuf.get_has_alpha ()
|
||||
width, height = pixbuf.props.width, pixbuf.props.height
|
||||
if pad_if_not_near_square and (height < width * ASPECT_RATIO_MIN or
|
||||
height > width * ASPECT_RATIO_MAX):
|
||||
rw, rh = max (width, height), max (width, height)
|
||||
left, top = (rw - width) // 2, (rh - height) // 2
|
||||
else:
|
||||
if not has_alpha:
|
||||
return pixbuf
|
||||
rw, rh, left, top = width, height, 0, 0
|
||||
ret = GdkPixbuf.Pixbuf.new (GdkPixbuf.Colorspace.RGB, False, 8, rw, rh)
|
||||
ret.fill ((int(bgcolor.red * 255) << 24) | (int(bgcolor.green * 255) << 16) | (int(bgcolor.blue * 255) << 8) | int(bgcolor.alpha * 255))
|
||||
if has_alpha:
|
||||
pixbuf.composite (ret, left, top, width, height, left, top, 1.0, 1.0, GdkPixbuf.InterpType.NEAREST, 255)
|
||||
else:
|
||||
pixbuf.copy_area (0, 0, width, height, ret, left, top)
|
||||
return ret
|
||||
|
||||
class FadingImage (Gtk.Misc):
|
||||
__gsignals__ = {
|
||||
'get-max-size' : (GObject.SIGNAL_RUN_LAST, GObject.TYPE_INT, ())
|
||||
}
|
||||
def __init__ (self, missing_image):
|
||||
Gtk.Misc.__init__(self)
|
||||
self.sc_id = self.connect('screen-changed', self.screen_changed)
|
||||
self.sa_id = self.connect('size-allocate', self.size_allocate_cb)
|
||||
self.resize_id, self.fade_id, self.anim_id = 0, 0, 0
|
||||
self.missing_image = missing_image
|
||||
self.size = 100
|
||||
self.screen_changed (self, None)
|
||||
self.old_pixbuf, self.new_pixbuf = None, None
|
||||
self.merged_pixbuf, self.missing_pixbuf = None, None
|
||||
self.fade_step = 0.0
|
||||
self.anim, self.anim_frames, self.anim_size = None, None, 0
|
||||
|
||||
def disconnect_handlers (self):
|
||||
self.disconnect(self.sc_id)
|
||||
self.disconnect(self.sa_id)
|
||||
self.icon_theme.disconnect(self.tc_id)
|
||||
for id in self.resize_id, self.fade_id, self.anim_id:
|
||||
if id != 0:
|
||||
GObject.source_remove (id)
|
||||
|
||||
def screen_changed (self, widget, old_screen):
|
||||
if old_screen:
|
||||
self.icon_theme.disconnect (self.tc_id)
|
||||
self.icon_theme = Gtk.IconTheme.get_for_screen (self.get_screen ())
|
||||
self.tc_id = self.icon_theme.connect ('changed', self.theme_changed)
|
||||
self.theme_changed (self.icon_theme)
|
||||
|
||||
def reload_anim_frames (self):
|
||||
icon_info = self.icon_theme.lookup_icon (THROBBER, -1, 0)
|
||||
size = icon_info.get_base_size ()
|
||||
icon = GdkPixbuf.Pixbuf.new_from_file (icon_info.get_filename ())
|
||||
self.anim_frames = [ # along, then down
|
||||
icon.new_subpixbuf (x * size, y * size, size, size)
|
||||
for y in range (int (icon.props.height / size))
|
||||
for x in range (int (icon.props.width / size))]
|
||||
self.anim_size = size
|
||||
|
||||
def theme_changed (self, icon_theme):
|
||||
try:
|
||||
self.reload_anim_frames ()
|
||||
except Exception, e:
|
||||
warn ("Throbber animation not loaded: %s" % e, Warning)
|
||||
self.reload_util_pixbufs ()
|
||||
|
||||
def reload_util_pixbufs (self):
|
||||
if self.size <= 1:
|
||||
return
|
||||
try:
|
||||
missing_pixbuf = self.icon_theme.load_icon (ART_MISSING_ICON, self.size, 0)
|
||||
except:
|
||||
try:
|
||||
missing_pixbuf = GdkPixbuf.Pixbuf.new_from_file_at_size (self.missing_image, self.size, self.size)
|
||||
except Exception, e:
|
||||
warn ("Missing artwork icon not found: %s" % e, Warning)
|
||||
return
|
||||
|
||||
bgcolor = self.get_style_context().get_background_color(Gtk.StateType.NORMAL)
|
||||
self.missing_pixbuf = merge_with_background (missing_pixbuf, bgcolor, False)
|
||||
|
||||
def size_allocate_cb (self, widget, allocation):
|
||||
if self.resize_id == 0:
|
||||
self.resize_id = GObject.idle_add (self.after_resize)
|
||||
|
||||
max_size = self.emit ('get-max-size')
|
||||
self.size = min (self.get_allocated_width (), max_size)
|
||||
|
||||
def after_resize (self):
|
||||
self.reload_util_pixbufs ()
|
||||
self.merged_pixbuf = None
|
||||
self.resize_id = 0
|
||||
self.queue_draw ()
|
||||
return False
|
||||
|
||||
def do_get_request_mode(self):
|
||||
return Gtk.SizeRequestMode.HEIGHT_FOR_WIDTH
|
||||
|
||||
def do_get_preferred_width(self):
|
||||
# maybe set minimum width here?
|
||||
return (0, 0)
|
||||
|
||||
def do_get_preferred_height_for_width(self, width):
|
||||
max_size = self.emit ('get-max-size')
|
||||
size = min(self.get_allocated_width(), max_size)
|
||||
return (size, size)
|
||||
|
||||
def do_draw (self, cr):
|
||||
if not self.ensure_merged_pixbuf ():
|
||||
return False
|
||||
|
||||
if self.merged_pixbuf.props.width != self.size:
|
||||
draw_pb = self.merged_pixbuf.scale_simple (self.size, self.size, GdkPixbuf.InterpType.NEAREST)
|
||||
else:
|
||||
draw_pb = self.merged_pixbuf
|
||||
|
||||
# center the image if we're wider than we are tall
|
||||
pad = (self.get_allocation().width - self.size) / 2
|
||||
|
||||
left = pad
|
||||
right = pad + self.size
|
||||
top = 0
|
||||
bottom = self.size
|
||||
if right > left and bottom > top:
|
||||
Gdk.cairo_set_source_pixbuf(cr, draw_pb, pad, 0)
|
||||
cr.rectangle(left, top, right - left, bottom - top)
|
||||
cr.fill()
|
||||
|
||||
if self.anim:
|
||||
x, y, w, h = self.anim_rect ()
|
||||
Gdk.cairo_set_source_pixbuf(cr, self.anim, max(0, x), max(0, y))
|
||||
cr.rectangle(max(0, x), max(0, y), w, h)
|
||||
cr.fill()
|
||||
|
||||
return False
|
||||
|
||||
def anim_rect (self):
|
||||
alloc_width = self.get_allocated_width()
|
||||
alloc_height = self.get_allocated_height()
|
||||
return ((alloc_width - self.anim_size) / 2,
|
||||
(alloc_height - self.anim_size) / 2,
|
||||
min (self.anim_size, alloc_width),
|
||||
min (self.anim_size, alloc_height))
|
||||
|
||||
def ensure_merged_pixbuf (self):
|
||||
if self.merged_pixbuf is None:
|
||||
alloc_width = self.get_allocated_width()
|
||||
alloc_height = self.get_allocated_height()
|
||||
self.merged_pixbuf = merge_pixbufs (self.old_pixbuf, self.new_pixbuf, self.missing_pixbuf, self.fade_step, alloc_width, alloc_height)
|
||||
return self.merged_pixbuf
|
||||
|
||||
def render_overlay (self):
|
||||
ret = self.ensure_merged_pixbuf ()
|
||||
if ret and self.anim:
|
||||
if ret is self.missing_pixbuf: ret = ret.copy ()
|
||||
x, y, w, h = self.anim_rect ()
|
||||
self.anim.composite (ret, max (x, 0), max (y, 0), w, h, x, y, 1, 1, GdkPixbuf.InterpType.BILINEAR, 255)
|
||||
return ret
|
||||
|
||||
def fade_art (self, first_time):
|
||||
self.fade_step += 1.0 / FADE_STEPS
|
||||
if self.fade_step > 0.999:
|
||||
self.old_pixbuf = None
|
||||
self.fade_id = 0
|
||||
self.merged_pixbuf = None
|
||||
if first_time:
|
||||
self.fade_id = GObject.timeout_add ((FADE_TOTAL_TIME / FADE_STEPS), self.fade_art, False)
|
||||
return False
|
||||
self.queue_resize ()
|
||||
return (self.fade_step <= 0.999)
|
||||
|
||||
def animation_advance (self, counter, first_time):
|
||||
self.anim = self.anim_frames[counter[0]]
|
||||
counter[0] = (counter[0] + 1) % len(self.anim_frames)
|
||||
x, y, w, h = self.anim_rect ()
|
||||
self.queue_draw_area (max (x, 0), max (y, 0), w, h)
|
||||
if first_time:
|
||||
self.anim_id = GObject.timeout_add (int (1000 / THROBBER_RATE), self.animation_advance, counter, False)
|
||||
return False
|
||||
return True
|
||||
|
||||
def set_current_art (self, pixbuf, working):
|
||||
if self.props.visible and self.get_allocated_width() > 1:
|
||||
self.old_pixbuf = self.render_overlay ()
|
||||
else:
|
||||
self.old_pixbuf = None # don't fade
|
||||
|
||||
bgcolor = self.get_style_context().get_background_color(Gtk.StateType.NORMAL)
|
||||
self.new_pixbuf = merge_with_background (pixbuf, bgcolor, True)
|
||||
self.merged_pixbuf = None
|
||||
self.fade_step = 0.0
|
||||
self.anim = None
|
||||
if self.fade_id != 0:
|
||||
GObject.source_remove (self.fade_id)
|
||||
self.fade_id = 0
|
||||
if self.old_pixbuf is not None:
|
||||
self.fade_id = GObject.timeout_add (working and WORKING_DELAY or (FADE_TOTAL_TIME / FADE_STEPS), self.fade_art, working)
|
||||
if working and self.anim_id == 0 and self.anim_frames:
|
||||
self.anim_id = GObject.timeout_add (WORKING_DELAY, self.animation_advance, [0], True)
|
||||
if not working and self.anim_id != 0:
|
||||
GObject.source_remove (self.anim_id)
|
||||
self.anim_id = 0
|
||||
self.queue_resize ()
|
||||
|
||||
GObject.type_register (FadingImage)
|
||||
|
||||
|
||||
class ArtDisplayWidget (FadingImage):
|
||||
|
||||
def __init__ (self, missing_image):
|
||||
super (ArtDisplayWidget, self).__init__ (missing_image)
|
||||
self.set_padding (0, 5)
|
||||
self.qt_id = self.connect ('query-tooltip', self.query_tooltip)
|
||||
self.props.has_tooltip = True
|
||||
self.current_entry, self.working = None, False
|
||||
self.current_pixbuf, self.current_uri = None, None
|
||||
|
||||
def disconnect_handlers (self):
|
||||
super (ArtDisplayWidget, self).disconnect_handlers ()
|
||||
|
||||
def query_tooltip (self, widget, x, y, keyboard_mode, tooltip):
|
||||
if (self.tooltip_image, self.tooltip_text) != (None, None):
|
||||
tooltip.set_text(self.tooltip_text)
|
||||
tooltip.set_icon(self.tooltip_image)
|
||||
return True
|
||||
else:
|
||||
return False
|
||||
|
||||
def set (self, entry, pixbuf, uri, tooltip_image, tooltip_text, working):
|
||||
self.current_entry = entry
|
||||
self.current_pixbuf = pixbuf
|
||||
self.current_uri = uri
|
||||
self.set_current_art (pixbuf, working)
|
||||
|
||||
self.tooltip_image = None
|
||||
if not self.current_entry:
|
||||
self.tooltip_text = None
|
||||
elif working:
|
||||
self.tooltip_text = _("Searching...")
|
||||
elif (tooltip_image, tooltip_text) != (None, None):
|
||||
self.tooltip_image = tooltip_image
|
||||
self.tooltip_text = tooltip_text
|
||||
else:
|
||||
self.tooltip_text = None
|
||||
|
||||
|
||||
GObject.type_register (ArtDisplayWidget)
|
||||
|
||||
|
||||
class ArtDisplayPlugin (GObject.GObject, Peas.Activatable):
|
||||
__gtype_name__ = 'ArtDisplayPlugin'
|
||||
object = GObject.property(type=GObject.GObject)
|
||||
|
||||
def __init__ (self):
|
||||
GObject.GObject.__init__ (self)
|
||||
|
||||
def do_activate (self):
|
||||
shell = self.object
|
||||
sp = shell.props.shell_player
|
||||
self.player_cb_ids = (
|
||||
sp.connect ('playing-song-changed', self.playing_entry_changed),
|
||||
sp.connect ('playing-changed', self.playing_changed)
|
||||
)
|
||||
self.art_store = RB.ExtDB(name="album-art")
|
||||
self.art_widget = ArtDisplayWidget (rb.find_plugin_file (self, ART_MISSING_ICON + ".svg"))
|
||||
self.art_widget.connect ('get-max-size', self.get_max_art_size)
|
||||
self.art_widget.connect ('button-press-event', self.on_button_press)
|
||||
self.art_container = Gtk.VBox ()
|
||||
self.art_container.pack_start (self.art_widget, True, True, 6)
|
||||
shell.add_widget (self.art_container, RB.ShellUILocation.SIDEBAR, False, True)
|
||||
self.current_entry, self.current_pixbuf = None, None
|
||||
self.playing_entry_changed (sp, sp.get_playing_entry ())
|
||||
|
||||
def do_deactivate (self):
|
||||
|
||||
shell = self.object
|
||||
sp = shell.props.shell_player
|
||||
for id in self.player_cb_ids:
|
||||
sp.disconnect (id)
|
||||
self.player_cb_ids = ()
|
||||
|
||||
shell.remove_widget (self.art_container, RB.ShellUILocation.SIDEBAR)
|
||||
self.art_widget.disconnect_handlers ()
|
||||
self.art_widget = None
|
||||
self.art_container = None
|
||||
|
||||
def playing_changed (self, sp, playing):
|
||||
self.set_entry(sp.get_playing_entry ())
|
||||
|
||||
def playing_entry_changed (self, sp, entry):
|
||||
self.set_entry(entry)
|
||||
|
||||
def set_entry (self, entry):
|
||||
if rb.entry_equal(entry, self.current_entry):
|
||||
return
|
||||
|
||||
self.art_widget.set (entry, None, None, None, None, True)
|
||||
self.art_container.show_all ()
|
||||
self.current_entry = entry
|
||||
self.current_pixbuf = None
|
||||
|
||||
if entry is not None:
|
||||
key = entry.create_ext_db_key (RB.RhythmDBPropType.ALBUM)
|
||||
self.art_store.request(key, self.art_store_request_cb, entry)
|
||||
|
||||
def art_store_request_cb(self, key, filename, data, entry):
|
||||
if rb.entry_equal(entry, self.current_entry) is False:
|
||||
# track changed while we were searching
|
||||
return
|
||||
|
||||
if isinstance(data, GdkPixbuf.Pixbuf):
|
||||
self.current_pixbuf = data
|
||||
uri = "file://" + urllib.pathname2url(filename)
|
||||
self.art_widget.set (entry, self.current_pixbuf, uri, None, None, False)
|
||||
else:
|
||||
self.art_widget.set (entry, None, None, None, None, False)
|
||||
|
||||
def get_max_art_size (self, widget):
|
||||
# limit the art image to a third of the window height to prevent it from
|
||||
# forcing the window to resize, obscuring everything else, and so on.
|
||||
shell = self.object
|
||||
(width, height) = shell.props.window.get_size()
|
||||
return height / 3
|
||||
|
||||
def on_button_press (self, widget, event):
|
||||
# on double clicks, open the cover image (if there is one) in the default
|
||||
# image viewer
|
||||
|
||||
doubleclick = Gdk.EventType._2BUTTON_PRESS
|
||||
if event.type != doubleclick or event.button != 1:
|
||||
return
|
||||
|
||||
if self.art_widget.current_uri is None:
|
||||
return
|
||||
|
||||
f = Gio.file_new_for_uri(self.art_widget.current_uri)
|
||||
shell = self.object
|
||||
Gtk.show_uri(shell.props.window.get_screen(), f.get_uri(), event.time)
|
||||
@@ -0,0 +1,7 @@
|
||||
This is simply the old artdisplay plugin from Rhythmbox <2.96.
|
||||
|
||||
It was removed from newer Rhythmbox versions in favor of the small cover display in the song title bar, but it still works. So if you prefer the old style, just get it.
|
||||
|
||||
Installation:
|
||||
1.) Copy the folder 'ArtDisplay' to '~/.local/share/Rhythmbox/plugins'.
|
||||
2.) Activate the plugin in Rhythmbox.
|
||||
Referência em uma Nova Issue
Bloquear um usuário