PEP8 cleanup

Esse commit está contido em:
fossfreedom
2015-10-04 23:20:55 +01:00
commit 00dee49e58
14 arquivos alterados com 249 adições e 260 exclusões
+3 -4
Ver Arquivo
@@ -1,4 +1,4 @@
coverart-search-providers v1.2.1
coverart-search-providers v1.2.2-testing
=========================
Drop in Rhythmbox replacement for the default CoverArt Search plugin to provide new and updated coverart search providers both local and by internet image hosts
@@ -52,12 +52,11 @@ v1.1
- fix bug to carry on search after binning poor MusicBrainz image download
- restructure rate-limits to ensure faster downloads whilst keeping to providers rate-limits
v1.2
v1.2.x
- support song-info dialog for Rhythmbox 3.2
- use RB's own embedded art search method as well as mutagen for wider embedded-art coverage
v1.2.1
- bug fix - for locales not found, exit the language installer gracefully
- PEP8 cleanup; remove odd embedded provider duplicate
Recommended order for Search Providers
+10 -15
Ver Arquivo
@@ -42,7 +42,6 @@ import discogs_client as discogs
import rb
from coverart_search_tracks import mutagen_library
ITEMS_PER_NOTIFICATION = 10
IGNORED_SCHEMES = ('http', 'cdda', 'daap', 'mms')
REPEAT_SEARCH_PERIOD = 86400 * 7
@@ -73,7 +72,7 @@ class BaseSearch(object):
print("rate_limit")
diff = time.time() - self.current_time
if diff < (1.0 / per_second_rate):
#Gdk.threads_add_timeout(GLib.PRIORITY_DEFAULT_IDLE,
# Gdk.threads_add_timeout(GLib.PRIORITY_DEFAULT_IDLE,
# int((1.0 / per_second_rate) *100), delay, None)
time.sleep((1.0 / per_second_rate) - diff)
print("sleeping")
@@ -91,14 +90,14 @@ class CoverSearch(object):
self.searches = searches
def next_search(self, continue_search):
'''
"""
main routine that calls the search routine for each search provider
unless one of the searches has found something
outputs - return False means that nothing found
inputs - True means continue with searching
- False means a search routine recommends no more searching
'''
"""
print("next search")
print(continue_search)
@@ -107,7 +106,7 @@ class CoverSearch(object):
album = self.key.get_field("album")
if not album:
return False
key = RB.ExtDBKey.create_storage("album", album)
key.add_field("artist", self.key.get_field("artist"))
self.store.store(key, RB.ExtDBSourceType.NONE, None)
@@ -151,7 +150,7 @@ class CoverAlbumSearch:
try:
files = fileenum.next_files_finish(result)
if files is None or len(files) == 0:
#print "okay, done; got %d files" % len(results)
# print "okay, done; got %d files" % len(results)
self.finished(results)
return
@@ -163,7 +162,7 @@ class CoverAlbumSearch:
readable = f.get_attribute_boolean("access::can-read")
if ct is not None and ct.startswith("audio/") and readable:
#print "_enum_dir_cb %s " % f.get_name()
# print "_enum_dir_cb %s " % f.get_name()
results.append(f.get_name())
fileenum.next_files_async(ITEMS_PER_NOTIFICATION, GLib.PRIORITY_DEFAULT, None, self._enum_dir_cb, results)
@@ -174,7 +173,6 @@ class CoverAlbumSearch:
sys.excepthook(*sys.exc_info())
self.finished(results)
def _enum_children_cb(self, parent, result, data):
try:
enumfiles = parent.enumerate_children_finish(result)
@@ -186,7 +184,6 @@ class CoverAlbumSearch:
sys.excepthook(*sys.exc_info())
self.callback(True)
def search(self, key, last_time, store, callback, args):
# ignore last_time
print("calling search")
@@ -220,7 +217,7 @@ class CoverAlbumSearch:
if not self.album:
return False
key = RB.ExtDBKey.create_storage("album", self.album)
key.add_field("artist", self.artists[0])
parent = self.file.get_parent()
@@ -241,7 +238,7 @@ class CoverAlbumSearch:
print("possible flac")
try:
#flac
# flac
module = mutagen_library('')
music = module.File(search)
imagefilename.write(music.pictures[0].data)
@@ -344,7 +341,7 @@ class DiscogsSearch(object):
if album in ("", _("Unknown")):
album = None
if album == None or len(artists) == 0:
if album is None or len(artists) == 0:
callback(True)
return
@@ -406,7 +403,6 @@ class SpotifySearch(BaseSearch):
def search_url(self, artist, album):
# Remove variants of Disc/CD [1-9] from album title before search
orig_album = album
for exp in DISC_NUMBER_REGEXS:
p = re.compile(exp, re.IGNORECASE)
album = p.sub('', album)
@@ -422,7 +418,6 @@ class SpotifySearch(BaseSearch):
print("spotify query url = %s" % url)
return url
def album_info_cb(self, data, album_name):
if data is None:
print("spotify query returned nothing")
@@ -474,7 +469,7 @@ class SpotifySearch(BaseSearch):
if album in ("", _("Unknown")):
album = None
if album == None or len(artists) == 0:
if album is None or len(artists) == 0:
print("can't search: no useful details")
callback(True)
return
+8 -8
Ver Arquivo
@@ -35,7 +35,6 @@ import chardet
import rb
import rb3compat
gettext.install('rhythmbox', RB.locale_dir())
if rb3compat.PYVER >= 3:
@@ -51,6 +50,7 @@ REPEAT_SEARCH_PERIOD = 86400 * 7
def file_root(f_name):
return os.path.splitext(f_name)[0].lower()
# this API key belongs to foss.freedom@gmail.com
# and was generated specifically for this use
API_KEY = '844353bce568b93accd9ca47674d6c3e'
@@ -79,14 +79,14 @@ class ArtistCoverSearch(object):
self.searches = searches
def next_search(self, continue_search):
'''
"""
main routine that calls the search routine for each search provider
unless one of the searches has found something
outputs - return False means that nothing found
inputs - True means continue with searching
- False means a search routine recommends no more searching
'''
"""
if len(self.searches) == 0 and continue_search:
key = RB.ExtDBKey.create_storage("artist", self.key.get_field("artist"))
@@ -110,7 +110,7 @@ class LastFMArtistSearch(object):
def search_url(self, artist):
print(("searching for (%s)" % (artist)))
print("searching for (%s)" % (artist))
url = API_URL + "?method=artist.getinfo&"
url = url + "artist=%s&" % (rb3compat.quote_plus(artist))
url = url + "format=json&"
@@ -153,7 +153,7 @@ class LastFMArtistSearch(object):
# images tags appear in order of increasing size, and we want the largest. probably.
url = image_urls.pop()
#last check - ensure the size is relatively large to hide false positives
# last check - ensure the size is relatively large to hide false positives
site = rb3compat.urlopen(url)
meta = site.info()
@@ -180,12 +180,12 @@ class LastFMArtistSearch(object):
l.get_url(url, self.artist_info_cb)
def search(self, key, last_time, store, callback, args):
#if last_time > (time.time() - REPEAT_SEARCH_PERIOD):
# if last_time > (time.time() - REPEAT_SEARCH_PERIOD):
# print("we already tried this one")
# callback (True)
# return
if user_has_account() == False:
if not user_has_account():
print("can't search: no last.fm account details")
callback(True)
return
@@ -193,7 +193,7 @@ class LastFMArtistSearch(object):
artist = key.get_field("artist")
self.key = key
if artist == None:
if artist is None:
print("can't search: no useful details")
callback(True)
return
+14 -21
Ver Arquivo
@@ -18,24 +18,19 @@
# Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
import time
from gi.repository import RB
from gi.repository import GObject
from gi.repository import GdkPixbuf
from gi.repository import Gio
import os
import json
import rb3compat
if rb3compat.PYVER >= 3:
import dbm.gnu as gdbm
else:
import gdbm
import os
import json
class Queue:
def __init__(self):
self.items = []
@@ -54,7 +49,7 @@ class Queue:
class CoverArtExtDB:
'''
"""
This is a simplified version of the RB.ExtDB capability. This
resolves the bugs in the extant capability, primarily around using
signals for none "album-art" databases.
@@ -67,7 +62,7 @@ class CoverArtExtDB:
ported to python3 - this uses the analagous gdbm format.
:param name: `str` name of the external database.
'''
"""
# storage for the instance references
__instances = {}
@@ -84,7 +79,7 @@ class CoverArtExtDB:
}
# added (ExtDB self, ExtDBKey object, String path, Value pixbuf)
#request (ExtDB self, ExtDBKey object, guint64 last_time)
# request (ExtDB self, ExtDBKey object, guint64 last_time)
_callback = {}
@@ -138,11 +133,11 @@ class CoverArtExtDB:
return keyval
def store(self, key, source_type, data):
'''
"""
:param key: `ExtDBKey`
:param source_type: `ExtDBSourceType`
:param data: `GdkPixbuf.Pixbuf`
'''
"""
print("store")
self.store_uri(key, source_type, data)
@@ -201,23 +196,23 @@ class CoverArtExtDB:
return False
def store_uri(self, key, source_type, data):
'''
"""
:param key: `ExtDBKey`
:param source_type: `ExtDBSourceType`
:param data: `str` which is a uri
'''
"""
print("store_uri")
self.queue.enqueue((key, source_type, data))
#Gio.io_scheduler_push_job(self.do_store_request, None,
# Gio.io_scheduler_push_job(self.do_store_request, None,
# GLib.PRIORITY_DEFAULT, None)
self.do_store_request()
def lookup(self, key):
'''
"""
:param key: `ExtDBKey`
'''
"""
lookup = self._construct_key(key)
filename = ''
if lookup in self.db:
@@ -227,16 +222,15 @@ class CoverArtExtDB:
return str(filename)
def request(self, key, callback, user_data):
'''
"""
:param key: `ExtDBKey`
:param callback: `Function` callback
:param user_data: `Value`
where callback is
Function (ExtDBKey key, String filename, GdkPixbuf.Pixbuf data, void* user_data) boolean
'''
"""
lookup = self._construct_key(key)
@@ -276,4 +270,3 @@ class CoverArtExtDB:
def __setattr__(self, attr, value):
""" Delegate access to implementation """
return setattr(self.__dict__['_CoverArtExtDB__instance'], attr, value)
+12 -13
Ver Arquivo
@@ -44,16 +44,16 @@ import rb3compat
def lastfm_connected():
'''
"""
returns True/False if connected to lastfm
'''
"""
return user_has_account()
def get_search_providers():
'''
"""
returns an array of search providers
'''
"""
gs = GSetting()
setting = gs.get_setting(gs.Path.PLUGIN)
current_providers = setting[gs.PluginKey.PROVIDERS]
@@ -62,27 +62,27 @@ def get_search_providers():
class CoverArtAlbumSearchPlugin(GObject.Object, Peas.Activatable):
'''
"""
Main class of the plugin. Manages the activation and deactivation of the
plugin.
'''
"""
__gtype_name = 'CoverArtAlbumSearchPlugin'
object = GObject.property(type=GObject.Object)
def __init__(self):
'''
"""
Initialises the plugin object.
'''
"""
GObject.Object.__init__(self)
if not rb3compat.compare_pygobject_version('3.9'):
GObject.threads_init()
def do_activate(self):
'''
"""
Called by Rhythmbox when the plugin is activated. It creates the
plugin's source and connects signals to manage the plugin's
preferences.
'''
"""
cl = CoverLocale()
cl.switch_locale(cl.Locale.LOCALE_DOMAIN)
@@ -128,12 +128,11 @@ class CoverArtAlbumSearchPlugin(GObject.Object, Peas.Activatable):
dialog.run()
dialog.destroy()
def do_deactivate(self):
'''
"""
Called by Rhythmbox when the plugin is deactivated. It makes sure to
free all the resources used by the plugin.
'''
"""
print("CoverArtBrowser DEBUG - do_deactivate")
self.shell.disconnect(self.csi_id)
+35 -34
Ver Arquivo
@@ -33,9 +33,9 @@ import rb
class CoverLocale:
'''
"""
This class manages the locale
'''
"""
# storage for the instance reference
__instance = None
@@ -43,18 +43,18 @@ class CoverLocale:
""" Implementation of the singleton interface """
# below public variables and methods that can be called for CoverLocale
def __init__(self):
'''
"""
Initializes the singleton interface, assigning all the constants
used to access the plugin's settings.
'''
"""
self.Locale = self._enum(
RB='rhythmbox',
LOCALE_DOMAIN='coverart_search_providers')
def switch_locale(self, locale_type):
'''
"""
Change the locale
'''
"""
locale.setlocale(locale.LC_ALL, '')
locale.bindtextdomain(locale_type, RB.locale_dir())
locale.textdomain(locale_type)
@@ -63,17 +63,17 @@ class CoverLocale:
gettext.install(locale_type)
def get_locale(self):
'''
"""
return the string representation of the users locale
for example
en_US
'''
"""
return locale.getdefaultlocale()[0]
def _enum(self, **enums):
'''
"""
Create an enumn.
'''
"""
return type('Enum', (), enums)
def __init__(self):
@@ -96,10 +96,10 @@ class CoverLocale:
class GSetting:
'''
"""
This class manages the differentes settings that the plugins haves to
access to read or write.
'''
"""
# storage for the instance reference
__instance = None
@@ -107,10 +107,10 @@ class GSetting:
""" Implementation of the singleton interface """
# below public variables and methods that can be called for GSetting
def __init__(self):
'''
"""
Initializes the singleton interface, asigning all the constants
used to access the plugin's settings.
'''
"""
self.Path = self._enum(
PLUGIN='org.gnome.rhythmbox.plugins.coverart_search_providers')
@@ -120,9 +120,9 @@ class GSetting:
self.setting = {}
def get_setting(self, path):
'''
"""
Return an instance of Gio.Settings pointing at the selected path.
'''
"""
try:
setting = self.setting[path]
except:
@@ -132,21 +132,21 @@ class GSetting:
return setting
def get_value(self, path, key):
'''
"""
Return the value saved on key from the settings path.
'''
"""
return self.get_setting(path)[key]
def set_value(self, path, key, value):
'''
"""
Set the passed value to key in the settings path.
'''
"""
self.get_setting(path)[key] = value
def _enum(self, **enums):
'''
"""
Create an enumn.
'''
"""
return type('Enum', (), enums)
def __init__(self):
@@ -169,10 +169,10 @@ class GSetting:
class SearchPreferences(GObject.Object, PeasGtk.Configurable):
'''
"""
Preferences for the CoverArt Browser Plugins. It holds the settings for
the plugin and also is the responsible of creating the preferences dialog.
'''
"""
__gtype_name__ = 'CoverArtSearchProvidersPreferences'
object = GObject.property(type=GObject.Object)
@@ -186,17 +186,17 @@ class SearchPreferences(GObject.Object, PeasGtk.Configurable):
MUSICBRAINZ_SEARCH = 'musicbrainz-search'
def __init__(self):
'''
"""
Initialises the preferences, getting an instance of the settings saved
by Gio.
'''
"""
GObject.Object.__init__(self)
self._first_run = True
def do_create_configure_widget(self):
'''
"""
Creates the plugin's preferences dialog
'''
"""
return self._create_display_contents(self)
def display_preferences_dialog(self, plugin):
@@ -255,7 +255,9 @@ class SearchPreferences(GObject.Object, PeasGtk.Configurable):
current_providers = copy.deepcopy(self.provider)
current = self.settings[self.gs.PluginKey.PROVIDERS]
print (current)
current_list = current.split(',')
print (current_list)
# create the ui
builder = Gtk.Builder()
@@ -283,8 +285,8 @@ class SearchPreferences(GObject.Object, PeasGtk.Configurable):
for key, value in list(current_providers.items()):
self.provider_liststore.append([value, key])
if len(self.provider_liststore) == 0:
self.provider_liststore.append([self.provider[self.EMBEDDED_SEARCH], self.EMBEDDED_SEARCH])
#if len(self.provider_liststore) == 0:
# self.provider_liststore.append([self.provider[self.EMBEDDED_SEARCH], self.EMBEDDED_SEARCH])
# return the dialog
return builder.get_object('maingrid')
@@ -317,7 +319,7 @@ class SearchPreferences(GObject.Object, PeasGtk.Configurable):
item = self.search_liststore.get_iter_first()
current_providers = []
while ( item != None ):
while (item is not None):
current_providers.append(self.search_liststore.get_value(item, 1))
item = self.search_liststore.iter_next(item)
@@ -326,17 +328,16 @@ class SearchPreferences(GObject.Object, PeasGtk.Configurable):
def on_up_button_clicked(self, *args):
selection = self.search_list.get_selection()
sel = selection.get_selected()
if not sel[1] == None:
if not sel[1] is None:
previous = self.search_liststore.iter_previous(sel[1])
if previous:
self.search_liststore.swap(sel[1], previous)
self._store_search_providers()
def on_down_button_clicked(self, *args):
selection = self.search_list.get_selection()
sel = selection.get_selected()
if not sel[1] == None:
if not sel[1] is None:
next = self.search_liststore.iter_next(sel[1])
if next:
self.search_liststore.swap(sel[1], next)
+14 -14
Ver Arquivo
@@ -49,9 +49,9 @@ IGNORED_SCHEMES = ('http', 'cdda', 'daap', 'mms')
def anyTrue(pred, seq):
'''Returns True if a True predicate is found, False
"""Returns True if a True predicate is found, False
otherwise. Quits as soon as the first True is found
'''
"""
return True in map(pred, seq)
@@ -65,11 +65,11 @@ class CoverArtTracks(object):
return mimetype[0]
def embed_ogg(self, art_location, search, mimetypestr):
'''
"""
:art_location: file path to the picture to embed
:search: file path to the music track file
:mimetypestr: mimetype of the picture to embed
'''
"""
try:
module = mutagen_library('oggvorbis')
o = module.OggVorbis(search)
@@ -91,7 +91,7 @@ class CoverArtTracks(object):
image.mime = mimetypestr
image.desc = 'cover description'
tags.setdefault("METADATA_BLOCK_PICTURE",
[]).append(base64.b64encode(image.write()))
[]).append(base64.b64encode(image.write()))
o.tags.update(tags)
o.save()
@@ -99,11 +99,11 @@ class CoverArtTracks(object):
pass
def embed_flac(self, art_location, search, mimetypestr):
'''
"""
:art_location: file path to the picture to embed
:search: file path to the music track file
:mimetypestr: mimetype of the picture to embed
'''
"""
try:
module = mutagen_library('')
music = module.File(search)
@@ -122,11 +122,11 @@ class CoverArtTracks(object):
pass
def embed_mp4(self, art_location, search, mimetypestr):
'''
"""
:art_location: file path to the picture to embed
:search: file path to the music track file
:mimetypestr: mimetype of the picture to embed
'''
"""
try:
module = mutagen_library('mp4')
music = module.MP4(search)
@@ -145,11 +145,11 @@ class CoverArtTracks(object):
pass
def embed_mp3(self, art_location, search, mimetypestr):
'''
"""
:art_location: file path to the picture to embed
:search: file path to the music track file
:mimetypestr: mimetype of the picture to embed
'''
"""
try:
module = mutagen_library('id3')
music = module.ID3(search)
@@ -165,7 +165,7 @@ class CoverArtTracks(object):
pass
def embed(self, track_uri, key, resize=-1):
'''
"""
embed tracks with the coverart
:track_uri: nominally RB.RhythmDBPropType.LOCATION
@@ -173,7 +173,7 @@ class CoverArtTracks(object):
:resize: int this is the size of the embedded image to resize to
returns True or False depending if the routine completed successfully
'''
"""
the = anyTrue # for readability
@@ -181,7 +181,7 @@ class CoverArtTracks(object):
if not isinstance(art_location, str):
art_location = art_location[0]
if not art_location:
print("not a valid key to a file containing art")
return False
+35 -25
Ver Arquivo
@@ -1,20 +1,22 @@
__version_info__ = (1,1,1)
__version_info__ = (1, 1, 1)
__version__ = '1.1.1'
import requests
import json
import rb3compat
from collections import defaultdict
import requests
import rb3compat
api_uri = 'http://api.discogs.com'
user_agent = None
class APIBase(object):
def __init__(self):
self._cached_response = None
self._params = {}
self._headers = { 'accept-encoding': 'gzip, deflate' }
self._headers = {'accept-encoding': 'gzip, deflate'}
def __str__(self):
return '<%s "%s">' % (self.__class__.__name__, self._id)
@@ -36,20 +38,21 @@ class APIBase(object):
if not self._check_user_agent():
raise DiscogsAPIError('Invalid or no User-Agent set')
try:
#gs = GSetting()
#setting = gs.get_setting(gs.Path.PLUGIN)
#type_val = setting[gs.PluginKey.PROXY_TYPE]
#if type_val == 0:
# gs = GSetting()
# setting = gs.get_setting(gs.Path.PLUGIN)
# type_val = setting[gs.PluginKey.PROXY_TYPE]
# if type_val == 0:
# type_name = 'http'
#elif type_val == 1:
# elif type_val == 1:
# type_name = 'https'
#elif type_val == 2:
# elif type_val == 2:
# type_name = 'ftp'
#proxy_name = setting[gs.PluginKey.PROXY_VALUE]
proxydict = {'http':''}
#proxydict[type_name] = proxy_name
self._cached_response = requests.get(self._uri, params=self._params, headers=self._headers, proxies=proxydict)
# proxy_name = setting[gs.PluginKey.PROXY_VALUE]
proxydict = {'http': ''}
# proxydict[type_name] = proxy_name
self._cached_response = requests.get(self._uri, params=self._params, headers=self._headers,
proxies=proxydict)
except:
raise DiscogsAPIError('bad response')
@@ -61,10 +64,9 @@ class APIBase(object):
@property
def _uri(self):
import urllib
return '%s/%s/%s' % (api_uri, self._uri_name, rb3compat.quote(rb3compat.unicodeencode(self._id, 'utf-8')))
#return '%s/%s/%s' % (api_uri, self._uri_name, urllib.quote(unicode(self._id).encode('utf-8')))
# return '%s/%s/%s' % (api_uri, self._uri_name, urllib.quote(unicode(self._id).encode('utf-8')))
@property
def data(self):
if self._response.content and self._response.status_code == 200:
@@ -74,9 +76,11 @@ class APIBase(object):
status_code = self._response.status_code
raise DiscogsAPIError('%s %s' % (status_code, rb3compat.responses()[status_code]))
class DiscogsAPIError(BaseException):
pass
def _parse_credits(extraartists):
"""
Parse release and track level credits
@@ -94,16 +98,18 @@ def _parse_credits(extraartists):
_credits[role].append(artist_dict)
return _credits
def _class_from_string(api_string):
class_map = {
'master': MasterRelease,
'release': Release,
'artist': Artist,
'label': Label
'master': MasterRelease,
'release': Release,
'artist': Artist,
'label': Label
}
return class_map[api_string]
class Artist(APIBase):
def __init__(self, name, anv=None):
self._id = name
@@ -134,7 +140,7 @@ class Artist(APIBase):
@property
def releases(self):
# TODO: Implement fetch many release IDs
#return [Release(r.get('id') for r in self.data.get('releases')]
# return [Release(r.get('id') for r in self.data.get('releases')]
if not self._releases:
self._params.update({'releases': '1'})
self._clear_cache()
@@ -143,6 +149,7 @@ class Artist(APIBase):
self._releases.append(_class_from_string(r['type'])(r['id']))
return self._releases
class Release(APIBase):
def __init__(self, id):
self._id = id
@@ -168,7 +175,7 @@ class Release(APIBase):
@property
def labels(self):
if not self._labels:
self._labels = [Label(l['name']) for l in self.data.get('labels', [])]
self._labels = [Label(l['name']) for l in self.data.get('labels', [])]
return self._labels
@property
@@ -199,6 +206,7 @@ class Release(APIBase):
def title(self):
return self.data.get('title')
class MasterRelease(APIBase):
def __init__(self, id):
self._id = id
@@ -240,6 +248,7 @@ class MasterRelease(APIBase):
def tracklist(self):
return self.key_release.tracklist
class Label(APIBase):
def __init__(self, name):
self._id = name
@@ -266,6 +275,7 @@ class Label(APIBase):
self._clear_cache()
return self.data.get('releases')
class Search(APIBase):
def __init__(self, query, page=1):
self._id = query
+72 -74
Ver Arquivo
@@ -35,10 +35,10 @@ import rb
def pygobject_version():
'''
"""
returns float of the major and minor parts of a pygobject version
e.g. version (3, 9, 5) return float(3.9)
'''
"""
to_number = lambda t: ".".join(str(v) for v in t)
str_version = to_number(GObject.pygobject_version)
@@ -47,10 +47,10 @@ def pygobject_version():
def compare_pygobject_version(version):
'''
"""
return True if version is less than pygobject_version
i.e. 3.9 < 3.11
'''
"""
to_number = lambda t: ".".join(str(v) for v in t)
str_version = to_number(GObject.pygobject_version)
@@ -172,17 +172,17 @@ def is_rb3(*args):
class Menu(GObject.Object):
'''
"""
Menu object used to create window popup menus
'''
"""
__gsignals__ = {
'pre-popup': (GObject.SIGNAL_RUN_LAST, None, ())
}
def __init__(self, plugin, shell):
'''
"""
Initializes the menu.
'''
"""
super(Menu, self).__init__()
self.plugin = plugin
self.shell = shell
@@ -192,22 +192,22 @@ class Menu(GObject.Object):
self._rbmenu_objects = {}
def add_menu_item(self, menubar, section_name, action):
'''
"""
add a new menu item to the popup
:param menubar: `str` is the name GtkMenu (or ignored for RB2.99+)
:param section_name: `str` is the name of the section to add the item to (RB2.99+)
:param action: `Action` to associate with the menu item
'''
"""
return self.insert_menu_item(menubar, section_name, -1, action)
def insert_menu_item(self, menubar, section_name, position, action):
'''
"""
add a new menu item to the popup
:param menubar: `str` is the name GtkMenu (or ignored for RB2.99+)
:param section_name: `str` is the name of the section to add the item to (RB2.99+)
:param position: `int` position to add to GtkMenu (ignored for RB2.99+)
:param action: `Action` to associate with the menu item
'''
"""
label = action.label
if is_rb3(self.shell):
@@ -238,11 +238,11 @@ class Menu(GObject.Object):
return item
def insert_separator(self, menubar, at_position):
'''
"""
add a separator to the popup (only required for RB2.98 and earlier)
:param menubar: `str` is the name GtkMenu (or ignored for RB2.99+)
:param position: `int` position to add to GtkMenu (ignored for RB2.99+)
'''
"""
if not is_rb3(self.shell):
menu_item = Gtk.SeparatorMenuItem().new()
menu_item.set_visible(True)
@@ -255,11 +255,11 @@ class Menu(GObject.Object):
uim.ensure_update()
def remove_menu_items(self, menubar, section_name):
'''
"""
utility function to remove all menuitems associated with the menu section
:param menubar: `str` is the name of the GtkMenu containing the menu items (ignored for RB2.99+)
:param section_name: `str` is the name of the section containing the menu items (for RB2.99+ only)
'''
"""
if is_rb3(self.shell):
if not section_name in self._rbmenu_items:
return
@@ -287,11 +287,11 @@ class Menu(GObject.Object):
uim.ensure_update()
def load_from_file(self, rb2_ui_filename, rb3_ui_filename):
'''
"""
utility function to load the menu structure
:param rb2_ui_filename: `str` RB2.98 and below UI file
:param rb3_ui_filename: `str` RB2.99 and higher UI file
'''
"""
self.builder = Gtk.Builder()
try:
from coverart_browser_prefs import CoverLocale
@@ -331,21 +331,21 @@ class Menu(GObject.Object):
_menu_connect(key, value)
def connect_signals(self, signals):
'''
"""
connect all signal handlers with their menuitem counterparts
:param signals: `dict` key is the name of the menuitem
and value is the function callback when the menu is activated
'''
"""
if is_rb3(self.shell):
self._connect_rb3_signals(signals)
else:
self._connect_rb2_signals(signals)
def get_gtkmenu(self, source, popup_name):
'''
"""
utility function to obtain the GtkMenu from the menu UI file
:param popup_name: `str` is the name menu-id in the UI file
'''
"""
if popup_name in self._rbmenu_objects:
return self._rbmenu_objects[popup_name]
item = self.builder.get_object(popup_name)
@@ -363,10 +363,10 @@ class Menu(GObject.Object):
return popup_menu
def get_menu_object(self, menu_name_or_link):
'''
"""
utility function returns the GtkMenuItem/Gio.MenuItem
:param menu_name_or_link: `str` to search for in the UI file
'''
"""
if menu_name_or_link in self._rbmenu_objects:
return self._rbmenu_objects[menu_name_or_link]
item = self.builder.get_object(menu_name_or_link)
@@ -384,12 +384,12 @@ class Menu(GObject.Object):
return popup_menu
def set_sensitive(self, menu_or_action_item, enable):
'''
"""
utility function to enable/disable a menu-item
:param menu_or_action_item: `GtkMenuItem` or `Gio.SimpleAction`
that is to be enabled/disabled
:param enable: `bool` value to enable/disable
'''
"""
if is_rb3(self.shell):
item = self.shell.props.window.lookup_action(menu_or_action_item)
@@ -399,29 +399,29 @@ class Menu(GObject.Object):
item.set_sensitive(enable)
def popup(self, source, menu_name, button, time):
'''
"""
utility function to show the popup menu
'''
"""
self.emit('pre-popup')
menu = self.get_gtkmenu(source, menu_name)
menu.popup(None, None, None, None, button, time)
class ActionGroup(object):
'''
"""
container for all Actions used to associate with menu items
'''
"""
# action_state
STANDARD = 0
TOGGLE = 1
def __init__(self, shell, group_name):
'''
"""
constructor
:param shell: `RBShell`
:param group_name: `str` unique name for the object to create
'''
"""
self.group_name = group_name
self.shell = shell
@@ -439,22 +439,22 @@ class ActionGroup(object):
return self.group_name
def remove_actions(self):
'''
"""
utility function to remove all actions associated with the ActionGroup
'''
"""
for action in self.actiongroup.list_actions():
self.actiongroup.remove_action(action)
def get_action(self, action_name):
'''
"""
utility function to obtain the Action from the ActionGroup
:param action_name: `str` is the Action unique name
'''
"""
return self._actions[action_name]
def add_action_with_accel(self, func, action_name, accel, **args):
'''
"""
Creates an Action with an accelerator and adds it to the ActionGroup
:param func: function callback used when user activates the action
@@ -464,12 +464,12 @@ class ActionGroup(object):
Notes:
see notes for add_action
'''
"""
args['accel'] = accel
return self.add_action(func, action_name, **args)
def add_action(self, func, action_name, **args):
'''
"""
Creates an Action and adds it to the ActionGroup
:param func: function callback used when user activates the action
@@ -481,7 +481,7 @@ class ActionGroup(object):
key value of "action_type" is the RB2.99 Gio.Action type ("win" or "app")
by default it assumes all actions are "win" type
key value of "action_state" determines what action state to create
'''
"""
if 'label' in args:
label = args['label']
else:
@@ -550,9 +550,9 @@ class ActionGroup(object):
class ApplicationShell(object):
'''
"""
Unique class that mirrors RB.Application & RB.Shell menu functionality
'''
"""
# storage for the instance reference
__instance = None
@@ -570,22 +570,22 @@ class ApplicationShell(object):
self._action_groups = {}
def insert_action_group(self, action_group):
'''
"""
Adds an ActionGroup to the ApplicationShell
:param action_group: `ActionGroup` to add
'''
"""
self._action_groups[action_group.name] = action_group
def lookup_action(self, action_group_name, action_name, action_type='app'):
'''
"""
looks up (finds) an action created by another plugin. If found returns
an Action or None if no matching Action.
:param action_group_name: `str` is the Gtk.ActionGroup name (ignored for RB2.99+)
:param action_name: `str` unique name for the action to look for
:param action_type: `str` RB2.99+ action type ("win" or "app")
'''
"""
if is_rb3(self.shell):
if action_type == "app":
@@ -611,7 +611,7 @@ class ApplicationShell(object):
return None
def add_app_menuitems(self, ui_string, group_name, menu='tools'):
'''
"""
utility function to add application menu items.
For RB2.99 all application menu items are added to the "tools" section of the
@@ -627,7 +627,7 @@ class ApplicationShell(object):
:param group_name: `str` unique name of the ActionGroup to add menu items to
:param menu: `str` RB2.99 menu section to add to - nominally either
'tools' or 'view'
'''
"""
if is_rb3(self.shell):
root = ET.fromstring(ui_string)
for elem in root.findall(".//menuitem"):
@@ -652,7 +652,7 @@ class ApplicationShell(object):
uim.ensure_update()
def add_browser_menuitems(self, ui_string, group_name):
'''
"""
utility function to add popup menu items to existing browser popups
For RB2.99 all menu items are are assumed to be of action_type "win".
@@ -665,7 +665,7 @@ class ApplicationShell(object):
this string is in XML format
:param group_name: `str` unique name of the ActionGroup to add menu items to
'''
"""
if is_rb3(self.shell):
root = ET.fromstring(ui_string)
for elem in root.findall("./popup"):
@@ -703,9 +703,9 @@ class ApplicationShell(object):
uim.ensure_update()
def cleanup(self):
'''
"""
utility remove any menuitems created.
'''
"""
if is_rb3(self.shell):
for uid in self._uids:
Gio.Application.get_default().remove_plugin_menu_item(self._uids[uid],
@@ -736,17 +736,17 @@ class ApplicationShell(object):
class Action(object):
'''
"""
class that wraps around either a Gio.Action or a Gtk.Action
'''
"""
def __init__(self, shell, action):
'''
"""
constructor.
:param shell: `RBShell`
:param action: `Gio.Action` or `Gtk.Action`
'''
"""
self.shell = shell
self.action = action
@@ -776,12 +776,12 @@ class Action(object):
@property
def label(self):
'''
"""
get the menu label associated with the Action
for RB2.99+ actions dont have menu labels so this is managed
manually
'''
"""
if not is_rb3(self.shell):
return self.action.get_label()
else:
@@ -796,9 +796,9 @@ class Action(object):
@property
def accel(self):
'''
"""
get the accelerator associated with the Action
'''
"""
return self._accel
@accel.setter
@@ -809,41 +809,41 @@ class Action(object):
self._accel = ''
def get_sensitive(self):
'''
"""
get the sensitivity (enabled/disabled) state of the Action
returns boolean
'''
"""
if is_rb3(self.shell):
return self.action.get_enabled()
else:
return self.action.get_sensitive()
def set_state(self, value):
'''
"""
set the state of a stateful action - this is applicable only
to RB2.99+
'''
"""
if is_rb3(self.shell) and self.action.props.state_type:
self.action.change_state(GLib.Variant('b', value))
def activate(self):
'''
"""
invokes the activate signal for the action
'''
"""
if is_rb3(self.shell):
self.action.activate(None)
else:
self.action.activate()
def set_active(self, value):
'''
"""
activate or deactivate a stateful action signal
For consistency with earlier RB versions, this will fire the
activate signal for the action
:param value: `boolean` state value
'''
"""
if is_rb3(self.shell):
self.action.change_state(GLib.Variant('b', value))
@@ -855,11 +855,11 @@ class Action(object):
self.action.set_active(value)
def get_active(self):
'''
"""
get the state of the action
returns `boolean` state value
'''
"""
if is_rb3(self.shell):
returnval = self._current_state
else:
@@ -868,13 +868,11 @@ class Action(object):
return returnval
def associate_menuitem(self, menuitem):
'''
"""
links a menu with the action
'''
"""
if is_rb3(self.shell):
menuitem.set_detailed_action('win.' + self.action.get_name())
else:
menuitem.set_related_action(self.action)
+43 -44
Ver Arquivo
@@ -27,57 +27,56 @@
from gi.repository import RB
from gi.repository import Gst, GstPbutils
class EmbeddedSearch(object):
def finished_cb(self, discoverer):
self.callback(True)
def finished_cb(self, discoverer):
self.callback(True)
def discovered_cb(self, discoverer, info, error):
tags = info.get_tags()
if tags is None:
return
def discovered_cb(self, discoverer, info, error):
tags = info.get_tags()
if tags is None:
return
for tagname in ('image', 'preview-image'):
(found, sample) = tags.get_sample(tagname)
if not found:
print("no %s" % tagname)
continue
for tagname in ('image', 'preview-image'):
(found, sample) = tags.get_sample(tagname)
if not found:
print("no %s" % tagname)
continue
pixbuf = RB.gst_process_embedded_image(tags, tagname)
if not pixbuf:
print("no pixbuf in %s" % tagname)
continue
pixbuf = RB.gst_process_embedded_image(tags, tagname)
if not pixbuf:
print("no pixbuf in %s" % tagname)
continue
print("trying to store pixbuf from %s" % tagname)
key = RB.ExtDBKey.create_storage("album", self.search_key.get_field("album"))
artists = self.search_key.get_field_values("artist")
key.add_field("artist", artists[0])
self.store.store(key, RB.ExtDBSourceType.EMBEDDED, pixbuf)
return
print("trying to store pixbuf from %s" % tagname)
key = RB.ExtDBKey.create_storage("album", self.search_key.get_field("album"))
artists = self.search_key.get_field_values("artist")
key.add_field("artist", artists[0])
self.store.store(key, RB.ExtDBSourceType.EMBEDDED, pixbuf)
return
def search(self, key, last_time, store, callback, args):
location = key.get_info("location")
if location is None:
print("not searching, we don't have a location")
callback(True)
return
if location.startswith("file://") is False:
print("not searching in non-local file %s" % location)
callback(True)
return
def search (self, key, last_time, store, callback, args):
location = key.get_info("location")
if location is None:
print("not searching, we don't have a location")
callback(True)
return
# should avoid checking the playing entry, since the player already handles that
if location.startswith("file://") is False:
print("not searching in non-local file %s" % location)
callback(True)
return
self.callback = callback
self.callback_args = args
self.store = store
self.search_key = key
# should avoid checking the playing entry, since the player already handles that
self.callback = callback
self.callback_args = args
self.store = store
self.search_key = key
print("discovering %s" % location)
self.discoverer = GstPbutils.Discoverer(timeout=Gst.SECOND*5)
self.discoverer.connect('finished', self.finished_cb)
self.discoverer.connect('discovered', self.discovered_cb)
self.discoverer.start()
self.discoverer.discover_uri_async(location)
print("discovering %s" % location)
self.discoverer = GstPbutils.Discoverer(timeout=Gst.SECOND * 5)
self.discoverer.connect('finished', self.finished_cb)
self.discoverer.connect('discovered', self.discovered_cb)
self.discoverer.start()
self.discoverer.discover_uri_async(location)
-3
Ver Arquivo
@@ -30,7 +30,6 @@ import re
import rb3compat
from coverart_album_search import BaseSearch
if rb3compat.PYVER >= 3:
import configparser
else:
@@ -108,7 +107,6 @@ class LastFMSearch(BaseSearch):
print("last.fm query url = %s" % url)
return url
def album_info_cb(self, data):
if data is None:
print("last.fm query returned nothing")
@@ -172,7 +170,6 @@ class LastFMSearch(BaseSearch):
l = rb.Loader()
self.rate_limit(l.get_url, (url, self.album_info_cb), 5)
def search(self, key, last_time, store, callback, args):
if user_has_account() == False:
+2 -4
Ver Arquivo
@@ -128,7 +128,6 @@ class LocalSearch:
sys.excepthook(*sys.exc_info())
self.finished(results)
def _enum_children_cb(self, parent, result, data):
try:
enumfiles = parent.enumerate_children_finish(result)
@@ -140,7 +139,6 @@ class LocalSearch:
sys.excepthook(*sys.exc_info())
self.callback(True)
def search(self, key, last_time, store, callback, args):
# ignore last_time
@@ -158,10 +156,10 @@ class LocalSearch:
self.album = key.get_field("album")
if not self.album:
print ('no album name')
print('no album name')
callback(args)
return
self.artists = key.get_field_values("artist")
self.store = store
self.callback = callback
+1
Ver Arquivo
@@ -34,6 +34,7 @@ import rb3compat
from coverart_album_search import BaseSearch
# musicbrainz URLs
MUSICBRAINZ_RELEASE_URL = "http://musicbrainz.org/ws/2/release/%s?inc=artists"
MUSICBRAINZ_RELEASE_PREFIX = "http://musicbrainz.org/release/"
-1
Ver Arquivo
@@ -31,7 +31,6 @@ from gi.repository import RB
import rb3compat
gettext.install('rhythmbox', RB.locale_dir())
ART_FOLDER = os.path.expanduser(os.path.join(RB.user_cache_dir(), 'covers'))