initial commit

Esse commit está contido em:
timo
2012-11-26 12:54:39 +01:00
commit 50214e6df3
3 arquivos alterados com 548 adições e 0 exclusões
+130
Ver Arquivo
@@ -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
+411
Ver Arquivo
@@ -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)