def download_finished(uri, result): try: success = uri.copy_finish(result) except: success = False if not success: return # done downloading, unzip to real location catalog_zip = zipfile.ZipFile(magnatune_song_info_temp) catalog = open(magnatune_song_info, 'w') filename = find_song_info(catalog_zip) if filename is None: RB.error_dialog(title=_("Unable to load catalog"), message=_("Rhythmbox could not understand the Magnatune catalog, please file a bug.")) return catalog.write(catalog_zip.read(filename)) catalog.close() catalog_zip.close() dest.delete() self.__updating = False self.__catalogue_loader = None self.__notify_status_changed() load_catalogue()
def __auth_download(self, sku): # http://magnatune.com/info/api def auth_data_cb(data, (username, password)): dl_album_handler = DownloadAlbumHandler(self.__settings['format']) auth_parser = xml.sax.make_parser() auth_parser.setContentHandler(dl_album_handler) if data is None: # hmm. return try: data = data.replace("<br>", "") # get rid of any stray <br> tags that will mess up the parser data = data.replace(" & ", " & ") # clean up some missing escaping # print data auth_parser.feed(data) auth_parser.close() # process the URI: add authentication info, quote the filename component for some reason parsed = urlparse.urlparse(dl_album_handler.url) netloc = "%s:%s@%s" % (username, password, parsed.hostname) spath = os.path.split(urllib.url2pathname(parsed.path)) basename = spath[1] path = urllib.pathname2url(os.path.join(spath[0], urllib.quote(basename))) authed = (parsed[0], netloc, path) + parsed[3:] audio_dl_uri = urlparse.urlunparse(authed) print "download uri for %s is %s" % (sku, audio_dl_uri) self.__download_album(audio_dl_uri, sku) except MagnatuneDownloadError, e: RB.error_dialog(title = _("Download Error"), message = _("An error occurred while trying to authorize the download.\nThe Magnatune server returned:\n%s") % str(e))
def download_finished(copy, success, self): if not success: print("catalog download failed") print(copy.get_error()) return print("catalog download successful") # done downloading, unzip to real location catalog_zip = zipfile.ZipFile(magnatune_song_info_temp) catalog = open(magnatune_song_info, 'wb') filename = find_song_info(catalog_zip) if filename is None: RB.error_dialog(title=_("Unable to load catalog"), message=_("Rhythmbox could not understand the Magnatune catalog, please file a bug.")) return catalog.write(catalog_zip.read(filename)) catalog.close() catalog_zip.close() df = Gio.file_new_for_path(magnatune_song_info_temp) df.delete(None) self.__catalogue_loader = None self.__load_progress.props.task_outcome = RB.TaskOutcome.COMPLETE load_catalogue()
def __init__(self, shell): # make sure the replaygain elements are available missing = [] required = ("rgvolume", "rglimiter") for e in required: if Gst.ElementFactory.find(e) is None: missing.append(e) if len(missing) > 0: msg = _("The GStreamer elements required for ReplayGain processing are not available. The missing elements are: %s") % ", ".join(missing) RB.error_dialog(shell.props.window, _("ReplayGain GStreamer plugins not available"), msg) raise Exception(msg) self.shell_player = shell.props.shell_player self.player = self.shell_player.props.player self.settings = Gio.Settings("org.gnome.rhythmbox.plugins.replaygain") self.settings.connect("changed::limiter", self.limiter_changed_cb) self.previous_gain = [] self.fallback_gain = 0.0 self.resetting_rgvolume = False # we use different means to hook into the playback pipeline depending on # the playback backend in use if GObject.signal_lookup("get-stream-filters", self.player): self.setup_xfade_mode() self.deactivate_backend = self.deactivate_xfade_mode else: self.setup_playbin2_mode() self.deactivate_backend = self.deactivate_playbin2_mode
def songs_loaded_cb(file, result, data): try: (ok, contents, etag) = file.load_contents_finish(result) except Exception as e: RB.error_dialog( title=_("Unable to load songs"), message=_("Rhythmbox could not load the Ampache songs.")) return try: # instantiate songs parser parser = xml.sax.make_parser() parser.setContentHandler( SongsHandler( is_playlist, source, self.__db, self.__entry_type, self.__albumart, self.__handshake_auth, self.__entries)) parser.feed(contents) except xml.sax.SAXParseException as e: print("error parsing songs: %s" % e) self.__text = '' self.__progress = 1 self.notify_status_changed() # load next cache load_iterate()
def download_finished(copy, success, self): if not success: print "catalog download failed" print copy.get_error() return print "catalog download successful" # done downloading, unzip to real location catalog_zip = zipfile.ZipFile(magnatune_song_info_temp) catalog = open(magnatune_song_info, "w") filename = find_song_info(catalog_zip) if filename is None: RB.error_dialog( title=_("Unable to load catalog"), message=_("Rhythmbox could not understand the Magnatune catalog, please file a bug."), ) return catalog.write(catalog_zip.read(filename)) catalog.close() catalog_zip.close() df = Gio.file_new_for_path(magnatune_song_info_temp) df.delete(None) self.__updating = False self.__catalogue_loader = None self.__notify_status_changed() load_catalogue()
def amend_genre_info(self, current_genre, new_genre, icon_name): root = ET.parse(open(self._user_popups)).getroot() base = self._sprite_name + '/alt/alt' found = False if current_genre != "": for elem in root.xpath(base): if RB.search_fold(elem.text) == RB.search_fold(current_genre): found = True del self.genre_alternate[GenreType(name=elem.text, genre_type=self.GENRE_USER)] break else: elem = ET.SubElement(root.xpath(self._sprite_name + '/alt')[0], "alt") if elem != None: found = True if found: elem.text = rb3compat.unicodestr(new_genre, 'utf-8') elem.attrib['genre'] = icon_name tree = ET.ElementTree(root) tree.write(self._user_popups, pretty_print=True, xml_declaration=True) self.genre_alternate[GenreType(name=elem.text, genre_type=self.GENRE_USER)] = icon_name return GenreType(name=elem.text, genre_type=self.GENRE_USER) else: print("nothing found to amend") return None
def similar_info_cb(self, data, _): if not data: print ("nothing to do") self._clear_next() return similar = json.loads(data.decode('utf-8')) # loop through the response and find all titles for the artists returned self.artist = {} if 'songs' not in similar['response']: print ("No matching data returned from EchoNest") self._clear_next() return for song in similar['response']['songs']: name = RB.search_fold(song['artist_name']) if name not in self.artist: self.artist[name] = [] self.artist[name].append(RB.search_fold(song['title'])) if len(self.artist) == 0: print ("no artists returned") self._clear_next() return # loop through every track - see if the track contains the artist & title # if yes then this is a candidate similar track to remember query_model = self.shell.props.library_source.props.base_query_model self._load_albums(iter(query_model), albums={}, model=query_model, total=len(query_model), progress=0.)
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) gettext.bindtextdomain(locale_type, RB.locale_dir()) gettext.textdomain(locale_type) gettext.install(locale_type)
def __auth_download(self, sku): # http://magnatune.com/info/api def got_items(result, items): if result is not None or len(items) == 0: RB.error_dialog(title = _("Couldn't get account details"), message = str(result)) return try: username, password = items[0].secret.split('\n') except ValueError: # Couldn't parse secret, possibly because it's empty username = "" password = "" print "downloading album: " + sku url_dict = { 'id': magnatune_partner_id, 'sku': sku } url = magnatune_api_download_uri % (username, password) url = url + urllib.urlencode(url_dict) l = rb.Loader() l.get_url(url, auth_data_cb, (username, password)) def auth_data_cb(data, (username, password)): buy_album_handler = BuyAlbumHandler(self.__settings['format']) auth_parser = xml.sax.make_parser() auth_parser.setContentHandler(buy_album_handler) if data is None: # hmm. return try: data = data.replace("<br>", "") # get rid of any stray <br> tags that will mess up the parser # print data auth_parser.feed(data) auth_parser.close() # process the URI: add authentication info, quote the filename component for some reason parsed = urlparse.urlparse(buy_album_handler.url) netloc = "%s:%s@%s" % (username, password, parsed.hostname) spath = os.path.split(urllib.url2pathname(parsed.path)) basename = spath[1] path = urllib.pathname2url(os.path.join(spath[0], urllib.quote(basename))) authed = (parsed[0], netloc, path) + parsed[3:] audio_dl_uri = urlparse.urlunparse(authed) self.__download_album(Gio.file_new_for_uri(audio_dl_uri), sku) except MagnatunePurchaseError, e: RB.error_dialog(title = _("Download Error"), message = _("An error occurred while trying to authorize the download.\nThe Magnatune server returned:\n%s") % str(e))
def close_button_pressed(x, y): try: if keyring_data['id'] and keyring_data['item']: # The async version is not in the python bindings, grr... keyring.item_set_info_sync(None, keyring_data['id'], keyring_data['item']) else: RB.error_dialog(title = _("Couldn't store account information"), message = _("There was a problem accessing the keyring. Check the debug output for more information.")) except Exception, e: RB.error_dialog(title = _("Couldn't store account information"), message = str(e))
def __init__(self, *args, **kwargs): GObject.Object.__init__(self) super(Fileorganizer, self).__init__(*args, **kwargs) self.configurator = FileorganizerConf() self.conf = configparser.RawConfigParser() self.configfile = RB.find_user_data_file(PLUGIN_PATH + CONFIGFILE) self.ui_file = RB.find_user_data_file(PLUGIN_PATH + UIFILE) self.shell = None self.rbdb = None self.action_group = None self.action = None self.source = None self.plugin_info = "fileorganizer"
def download_album(self): if selt.__settings['account_type'] != 'download': # The user doesn't have a download account, so redirect them to the purchase page. self.purchase_redirect() return try: # Just use the first library location library = Gio.Settings("org.gnome.rhythmbox.rhythmdb") library_location = library['locations'][0] except IndexError, e: RB.error_dialog(title = _("Couldn't purchase album"), message = _("You must have a library location set to purchase an album.")) return
def _compare(self, model, row1, row2, user_data): if not model.iter_has_child(row1) or \ not model.iter_has_child(row2): return 0 sort_column = 0 value1 = RB.search_fold(model.get_value(row1, sort_column)) value2 = RB.search_fold(model.get_value(row2, sort_column)) if value1 < value2: return -1 elif value1 == value2: return 0 else: return 1
def do_activate(self): ''' Plugin activation ''' shell = self.object if hasattr(shell.props, 'application'): # Newer Rhythmbox app = shell.props.application action = Gio.SimpleAction.new("leftfeet-generate", None) action.connect('activate', self.generate_action, shell) app.add_action(action) app.add_plugin_menu_item('tools', 'leftfeet-generate', Gio.MenuItem.new(label = _("Generate play queue"), detailed_action = 'app.leftfeet-generate')) else: # Rhythmbox 2.96 manager = shell.props.ui_manager action_group = Gtk.ActionGroup(name = 'LeftFeetActions') action = Gtk.Action(name = 'leftfeet-generate', label = _('Generate play queue'), tooltip = _('Generate a play queue with LeftFeet'), stock_id = None) action.connect('activate', self.generate_action, None, shell) action_group.add_action(action) manager.insert_action_group(action_group, 0) ui_id = manager.add_ui_from_string(ui_str) manager.ensure_update() shell.set_data('leftfeet', {'ui_id': ui_id, 'action_group': action_group}) self.settings = dbm.open(RB.find_user_data_file('leftfeet.db'), 'c')
def __init__(self, plugin, sprite_name, size=None): super(GenreConfiguredSpriteSheet, self).__init__(plugin, sprite_name, size) self.genre_alternate = {} # contains GenreType tuples self._alt_icons = {} self._sprite_name = sprite_name self._size = size popups = rb.find_plugin_file(plugin, 'img/popups.xml') root = ET.parse(open(popups)).getroot() self._parse_popups(plugin, root, self.GENRE_SYSTEM) try: # self._user_popups = RB.find_user_data_file('plugins/coverart_browser/img/usericons/popups.xml') self._user_popups = RB.user_cache_dir() + "/coverart_browser/usericons/popups.xml" root = ET.parse(open(self._user_popups)).getroot() self._parse_popups(plugin, root, self.GENRE_USER) elem = root.xpath(self._sprite_name + '/index') curr_index = int(elem[0].text) for index in range(0, curr_index + 1): key = RB.ExtDBKey.create_lookup('icon', str(index)) icon_location = self._genre_db.lookup(key) sprite = GdkPixbuf.Pixbuf.new_from_file(icon_location) if self._size: sprite = sprite.scale_simple(self._size[0], self._size[1], GdkPixbuf.InterpType.BILINEAR) self._alt_icons[str(index)] = sprite self.names.append(str(index)) except: pass
def do_activate(self): shell = self.object self.db = shell.props.db self.shell_player = shell.props.shell_player self.shell_player.connect("playing-song-changed", self.playing_song_changed_cb) self.shell_player.connect("playing-song-property-changed", self.playing_song_property_changed_cb) self.shell_player.connect("playing-changed", self.playing_changed_cb) self.shell_player.connect("elapsed-nano-changed", self.elapsed_nano_changed_cb) self.playing_song_changed_cb(self.shell_player, self.shell_player.get_playing_entry()) self.http_server = Soup.Server() self.http_server.add_handler(path="/art/", callback=self.http_art_cb) self.http_server.add_handler(path="/icon/", callback=self.http_icon_cb) self.http_server.add_handler(path="/entry/current/stream", callback=self.http_track_cb) self.http_server.add_handler(path="/css/", callback=self.http_static_css_cb) self.http_server.add_handler(path="/js/", callback=self.http_static_js_cb) self.http_server.add_websocket_handler("/ws/player", None, None, self.player_websocket_cb) self.http_server.add_handler(path="/", callback=self.http_root_cb) self.http_listen() self.http_server.run_async() self.artcache = os.path.join(RB.user_cache_dir(), "album-art", "") self.art_store = RB.ExtDB(name="album-art") self.art_store.connect("added", self.art_added_cb)
def __init__(self, **kwargs): super(AmpacheBrowser, self).__init__(kwargs) self.__limit = 5000 self.__songs_cache = '_songs' self.__cache_directory = os.path.join( RB.user_cache_dir(), 'ampache') self.__songs_cache_filename = os.path.join( self.__cache_directory, ''.join([self.__songs_cache, '.xml'])) self.__settings = Gio.Settings('org.gnome.rhythmbox.plugins.ampache') self.__albumart = {} self.__playlists = collections.deque( [[0, self.__songs_cache]]) self.__caches = collections.deque() self.__playlist_sources = [] self.__entries = [] self.__text = None self.__progress_text = None self.__progress = 1 self.__activated = False # add action RefetchAmpache and assign callback refetch_ampache app = Gio.Application.get_default() action = Gio.SimpleAction(name='refetch-ampache') action.connect('activate', self.refetch_ampache) app.add_action(action)
def __move_data_files(self): # create cache and data directories magnatune_in_progress_path = magnatune_in_progress_dir.get_path() magnatune_cache_path = magnatune_cache_dir.get_path() # (we know they don't already exist, and we know the parent dirs do) os.mkdir(magnatune_in_progress_path, 0700) if os.path.exists(magnatune_cache_path) is False: os.mkdir(magnatune_cache_path, 0700) # move song info to cache dir old_magnatune_dir = os.path.join(RB.dot_dir(), 'magnatune') if os.path.exists(old_magnatune_dir) is False: print "old magnatune directory does not exist" return old_song_info = os.path.join(old_magnatune_dir, 'song_info.xml') if os.path.exists(old_song_info): print "moving existing song_info.xml to cache dir" os.rename(old_song_info, magnatune_song_info) else: print "no song_info.xml found (%s)" % old_song_info # move in progress downloads to data dir otherfiles = os.listdir(old_magnatune_dir) for f in otherfiles: print "moving file %s to new in-progress dir" % f os.rename(os.path.join(old_magnatune_dir, f), os.path.join(magnatune_in_progress_path, f))
def download_album(self): if self.__settings["account-type"] != "download": # The user doesn't have a download account, so redirect them to the download signup page self.download_redirect() return try: # Just use the first library location library = Gio.Settings("org.gnome.rhythmbox.rhythmdb") library_location = library["locations"][0] except IndexError, e: RB.error_dialog( title=_("Couldn't download album"), message=_("You must have a library location set to download an album."), ) return
def process_track(album, track): self.album_manager.progress = self._track_count / total self._track_count = self._track_count + 1 key = album.create_ext_db_key() finalPath = rb3compat.unquote(track.location)[7:] album_name = RB.search_fold(album.name) if use_album_name: folder_store = final_folder_store + '/' + album_name else: folder_store = final_folder_store try: if not os.path.exists(folder_store): os.makedirs(folder_store) if convert: self.convert_to_mp3(finalPath, folder_store, bitrate) finalPath = self._calc_mp3_filename(finalPath, folder_store) print(finalPath) else: shutil.copy(finalPath, folder_store) except IOError as err: print(err.args[0]) return False dest = os.path.join(folder_store, os.path.basename(finalPath)) desturi = 'file://' + rb3compat.pathname2url(dest) return search_tracks.embed(desturi, key, resize)
def __set_client(self): """ setup the client api """ cache_dir = RB.find_user_cache_file("baidu-music") if not os.path.isdir(cache_dir): os.mkdir(cache_dir) cookie = RB.find_user_cache_file("baidu-music/cookie") self.client = Client(cookie, debug=False) username = self.settings.get_string("username") password = self.settings.get_string("password") if username and password and not self.client.islogin: try: self.client.login(username, password) except Exception, e: self.settings["username"] = "" self.settings["password"] = ""
def __init__(self): RB.BrowserSource.__init__(self, name=_("Jamendo")) # catalogue stuff self.hate = self self.__db = None self.__saxHandler = None self.__activated = False self.__notify_id = 0 self.__update_id = 0 self.__info_screen = None self.__updating = True self.__load_current_size = 0 self.__load_total_size = 0 self.__db_load_finished = False self.__catalogue_loader = None self.__catalogue_check = None self.__jamendo_dir = RB.find_user_cache_file("jamendo") if os.path.exists(self.__jamendo_dir) is False: os.makedirs(self.__jamendo_dir, 0700) self.__local_catalogue_path = os.path.join(self.__jamendo_dir, "dbdump.xml") self.__local_catalogue_temp = os.path.join(self.__jamendo_dir, "dbdump.xml.tmp") self.settings = Gio.Settings("org.gnome.rhythmbox.plugins.jamendo")
def check_lyrics_folder(self): folder = self.settings["lyrics-folder-change"] changed = False if _DEBUG == True: import sys func_name = sys._getframe().f_code.co_name debug_file = open ( "debug_file", "a+" ) debug_file.write ( func_name + ": " + folder + '\n'); debug_file.close() # expand user directory if "~" in folder: folder = os.path.expanduser(folder) changed = True # path not set or invalid if not folder or not os.path.exists(folder): folder = os.path.join(RB.user_cache_dir(), "lyrics") folder = os.path.expanduser(folder) if not os.path.exists(folder): os.mkdir(folder) changed = True print "invalid path in lyrics-folder-change, set to default" if changed: self.settings["lyrics-folder-change"] = folder
def _find_alternates(self, test_genre): # the following genre checks are required # 1. if we have user defined genres # 2. then check locale specific system genres # 3. then check local specific alternates # 4. then check if we system genres # where necessary check if any of the genres are a substring # of test_genre - check in reverse order so that we # test largest strings first (prevents spurious matches with # short strings) # N.B. we use RB.search_fold since the strings can be # in a mixture of cases, both unicode (normalized or not) and str # and as usual python cannot mix and match these types. test_genre = RB.search_fold(test_genre) ret, sprite = self._match_genres(test_genre, self._spritesheet.GENRE_USER) if ret: return sprite for genre in sorted(self._spritesheet.locale_names, key=lambda b: (-len(b), b)): if RB.search_fold(genre) in test_genre: return self._spritesheet[self._spritesheet.locale_names[genre]] # next check locale alternates ret, sprite = self._match_genres(test_genre, self._spritesheet.GENRE_LOCALE) if ret: return sprite ret, sprite = self._match_genres(test_genre, self._spritesheet.GENRE_SYSTEM) if ret: return sprite # check if any of the default genres are a substring # of test_genre - check in reverse order so that we # test largest strings first (prevents spurious matches with # short strings) for genre in sorted(self._spritesheet.names, key=lambda b: (-len(b), b)): if RB.search_fold(genre) in test_genre: return self._spritesheet[genre] # if no matches then default to unrecognised image return self._unrecognised_image
def _check_configfile(self): """ Copy the default config template or load existing config file """ if not os.path.isfile(self.configfile): template = RB.find_user_data_file(PLUGIN_PATH + CONFIGTEMPLATE) folder = os.path.split(self.configfile)[0] if not os.path.exists(folder): os.makedirs(folder) shutil.copyfile(template, self.configfile)
def _check_configfile(self): self.configfile = RB.find_user_data_file(PLUGIN_PATH + CONFIG_FILE) if not os.path.isfile(self.configfile): template = rb.find_plugin_file(self, 'template/' + CONFIG_FILE) folder = os.path.split(self.configfile)[0] if not os.path.exists(folder): os.makedirs(folder) shutil.copyfile(template, self.configfile)
def delete_genre(self, current_genre): root = ET.parse(open(self._user_popups)).getroot() base = self._sprite_name + '/alt/alt' found = False for elem in root.xpath(base): if RB.search_fold(elem.text) == RB.search_fold(current_genre): found = True break if found: elem.getparent().remove(elem) tree = ET.ElementTree(root) tree.write(self._user_popups, pretty_print=True, xml_declaration=True) else: print("not found to delete")
def find_plugin_file(plugin, filename): info = plugin.plugin_info data_dir = info.get_data_dir() path = os.path.join(data_dir, filename) print("looking for " + filename + " in " + data_dir) if os.path.exists(path): return path return RB.file(filename)
def find_file(self, filename): info = self.plugin_info data_dir = info.get_data_dir() path = os.path.join(data_dir, filename) if os.path.exists(path): return path return RB.file(filename)
# 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, see <http://www.gnu.org/licenses/>. from gi.repository import RB, Gio, Gtk, GdkPixbuf, GObject, Peas, PeasGtk, WebKit2 from xml.dom import minidom # xml parser from xml.sax.saxutils import unescape # xml unescape import urllib.request, urllib.error, urllib.parse # search line escaping, simple https requests import gettext gettext.install('rhythmbox', RB.locale_dir()) # entry type for results. not saving on disk class VKEntryType(RB.RhythmDBEntryType): def __init__(self): RB.RhythmDBEntryType.__init__(self, name="vk-entry-type", save_to_disk=False) def can_sync_metadata(self, entry): return False def do_sync_metadata(self, entry, changes): return
import sys import re import traceback from gi.repository import GObject, Gio, Gtk, Peas, RB, GLib from lastfmqueue_rb3compat import ActionGroup #~ from lastfmqueue_rb3compat import Action from lastfmqueue_rb3compat import ApplicationShell import rb import urllib from xml.dom import minidom from random import * import gettext gettext.install('rhythmbox', RB.locale_dir(), unicode=True) ui_str = \ """<ui> <menubar name="MenuBar"> <menu name="ControlMenu" action="Control"> <menuitem name="LastFM Queue" action="LastFMQueueAction"/> </menu> </menubar> </ui>""" PATH = 'org.gnome.rhythmbox.plugins.lastfm_queue' ACTIVE_KEY = 'active' class LastFmQueuePlugin(GObject.Object, Peas.Activatable):
You should have received a copy of the GNU General Public License along with this program. If not, see <http://www.gnu.org/licenses/>. """ import re import gettext from gi.repository import Gtk from gi.repository import RB from dialog import AddToPlaylistDialog _ = gettext.gettext APPNAME = "rhythmbox-baidu-music" gettext.install(APPNAME, RB.locale_dir()) gettext.textdomain(APPNAME) class SearchHandle(object): def __init__(self, builder, client, collect_source, temp_source, playlists): # the basic objects self.__collect_source = collect_source self.__temp_source = temp_source self.__client = client self.__builder = builder self.__playlists = playlists # the widgets
def set_folder_default(self, button, file_chooser): file_chooser.set_current_folder( os.path.join(RB.user_cache_dir(), "lyrics"))
def preamp_changed_cb(self, preamp): RB.settings_delayed_sync(self.settings, self.sync_preamp, preamp)
def __getitem__(self, k): return self._d[self._s[RB.search_fold(k)]]
def __download_album(self, audio_dl_uri, sku): def download_progress(copy, complete, total, self): self.__downloads[audio_dl_uri] = (complete, total) self.__notify_status_changed() def download_finished(copy, success, self): del self.__downloads[audio_dl_uri] del self.__copies[audio_dl_uri] print "download of %s finished: %s" % (audio_dl_uri, success) if success: threading.Thread(target=unzip_album).start() else: remove_download_files() if len(self.__downloads) == 0: # All downloads are complete shell = self.props.shell manager = shell.props.ui_manager manager.get_action( "/MagnatuneSourceViewPopup/MagnatuneCancelDownload" ).set_sensitive(False) if success: shell.notify_custom( 4000, _("Finished Downloading"), _("All Magnatune downloads have been completed."), None, False) self.__notify_status_changed() def unzip_album(): # just use the first library location library = Gio.Settings("org.gnome.rhythmbox.rhythmdb") library_location = Gio.file_new_for_uri(library['locations'][0]) print "unzipping %s" % dest.get_path() album = zipfile.ZipFile(dest.get_path()) for track in album.namelist(): track_uri = library_location.resolve_relative_path( track).get_uri() print "zip file entry: %s => %s" % (track, track_uri) track_uri = RB.sanitize_uri_for_filesystem(track_uri) RB.uri_create_parent_dirs(track_uri) track_out = Gio.file_new_for_uri(track_uri).create( Gio.FileCreateFlags.NONE, None) if track_out is not None: track_out.write(album.read(track), None) track_out.close(None) print "adding %s to library" % track_uri self.__db.add_uri(track_uri) album.close() remove_download_files() def remove_download_files(): print "removing download files" in_progress.delete(None) dest.delete(None) in_progress = magnatune_in_progress_dir.resolve_relative_path( "in_progress_" + sku) dest = magnatune_in_progress_dir.resolve_relative_path(sku) in_progress.replace_contents( str(audio_dl_uri), None, False, Gio.FileCreateFlags.PRIVATE | Gio.FileCreateFlags.REPLACE_DESTINATION, None) shell = self.props.shell manager = shell.props.ui_manager manager.get_action("/MagnatuneSourceViewPopup/MagnatuneCancelDownload" ).set_sensitive(True) try: # For some reason, Gio.FileCopyFlags.OVERWRITE doesn't work for copy_async dest.delete(None) except: pass dl = RB.AsyncCopy() dl.set_progress(download_progress, self) dl.start(audio_dl_uri, dest.get_uri(), download_finished, self) self.__downloads[audio_dl_uri] = (0, 0) # (current, total) self.__copies[audio_dl_uri] = dl
import sys import xml import urllib.parse, urllib.request import threading import zipfile import rb from gi.repository import RB from gi.repository import GObject, Gtk, Gdk, Gio, GLib from TrackListHandler import TrackListHandler from DownloadAlbumHandler import DownloadAlbumHandler, MagnatuneDownloadError import MagnatuneAccount import gettext gettext.install('rhythmbox', RB.locale_dir()) magnatune_partner_id = "rhythmbox" # URIs magnatune_song_info_uri = "http://magnatune.com/info/song_info_xml.zip" magnatune_changed_uri = "http://magnatune.com/info/changed.txt" magnatune_buy_album_uri = "https://magnatune.com/buy/choose?" magnatune_api_download_uri = "http://%s:%[email protected]/buy/membership_free_dl_xml?" magnatune_in_progress_dir = Gio.file_new_for_path( RB.user_data_dir()).resolve_relative_path('magnatune') magnatune_cache_dir = Gio.file_new_for_path( RB.user_cache_dir()).resolve_relative_path('magnatune') magnatune_song_info = os.path.join(magnatune_cache_dir.get_path(),
from gi.repository import Gtk, Gio # XXX use GnomeKeyring when introspection is available from TrackListHandler import TrackListHandler from BuyAlbumHandler import BuyAlbumHandler, MagnatunePurchaseError magnatune_partner_id = "rhythmbox" # URIs magnatune_song_info_uri = Gio.file_new_for_uri( "http://magnatune.com/info/song_info_xml.zip") magnatune_buy_album_uri = "https://magnatune.com/buy/choose?" magnatune_api_download_uri = "http://%s:%[email protected]/buy/membership_free_dl_xml?" magnatune_in_progress_dir = Gio.file_new_for_path( RB.user_data_dir()).resolve_relative_path('magnatune') magnatune_cache_dir = Gio.file_new_for_path( RB.user_cache_dir()).resolve_relative_path('magnatune') magnatune_song_info = os.path.join(magnatune_cache_dir.get_path(), 'song_info.xml') magnatune_song_info_temp = os.path.join(magnatune_cache_dir.get_path(), 'song_info.zip.tmp') class MagnatuneSource(RB.BrowserSource): def __init__(self): RB.BrowserSource.__init__(self) self.hate = self self.__settings = Gio.Settings("org.gnome.rhythmbox.plugins.magnatune")
import xml import urllib import urlparse import threading import zipfile import rb from gi.repository import RB from gi.repository import GObject, Gtk, Gdk, Gio from TrackListHandler import TrackListHandler from DownloadAlbumHandler import DownloadAlbumHandler, MagnatuneDownloadError import MagnatuneAccount import gettext gettext.install('rhythmbox', RB.locale_dir()) magnatune_partner_id = "rhythmbox" # URIs magnatune_song_info_uri = "http://magnatune.com/info/song_info_xml.zip" magnatune_changed_uri = "http://magnatune.com/info/changed.txt" magnatune_buy_album_uri = "https://magnatune.com/buy/choose?" magnatune_api_download_uri = "http://%s:%[email protected]/buy/membership_free_dl_xml?" magnatune_in_progress_dir = Gio.file_new_for_path( RB.user_data_dir()).resolve_relative_path('magnatune') magnatune_cache_dir = Gio.file_new_for_path( RB.user_cache_dir()).resolve_relative_path('magnatune') magnatune_song_info = os.path.join(magnatune_cache_dir.get_path(),
# 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 os.path import urllib import rb from gi.repository import RB import gettext gettext.install('rhythmbox', RB.locale_dir()) ART_FOLDER = os.path.expanduser(os.path.join(RB.user_cache_dir(), 'covers')) USEFUL = os.path.exists(ART_FOLDER) class OldCacheSearch(object): def __init__(self): pass def filename(self, album, artist, extension): artist = artist.replace('/', '-') album = album.replace('/', '-') return os.path.join(ART_FOLDER, '%s - %s.%s' % (artist, album, extension))
def getMeasureResultsDir(self): cachedir = RB.user_cache_dir() + "/DRC" measureResultsDir = cachedir + "/MeasureResults" if not os.path.exists(measureResultsDir): os.makedirs(measureResultsDir) return measureResultsDir
def getTmpCfgDir(self): cachedir = RB.user_cache_dir() + "/DRC" tmpCfgDir = cachedir + "/TmpDRCCfg" if not os.path.exists(tmpCfgDir): os.makedirs(tmpCfgDir) return tmpCfgDir
def do_create_configure_widget(self): ''' Creates the plugin's preferences dialog ''' # create the ui cl = CoverLocale() cl.switch_locale(cl.Locale.LOCALE_DOMAIN) builder = Gtk.Builder() builder.set_translation_domain(cl.Locale.LOCALE_DOMAIN) builder.add_from_file(rb.find_plugin_file(self, 'ui/coverart_browser_prefs.ui')) self.launchpad_button = builder.get_object('show_launchpad') self.launchpad_label = builder.get_object('launchpad_label') builder.connect_signals(self) #. TRANSLATORS: Do not translate this string. translators = _('translator-credits') if translators != "translator-credits": self.launchpad_label.set_text(translators) else: self.launchpad_button.set_visible(False) gs = GSetting() # bind the toggles to the settings toggle_statusbar = builder.get_object('custom_statusbar_checkbox') self.settings.bind(gs.PluginKey.CUSTOM_STATUSBAR, toggle_statusbar, 'active', Gio.SettingsBindFlags.DEFAULT) toggle_bottom = builder.get_object('display_bottom_checkbox') self.settings.bind(gs.PluginKey.DISPLAY_BOTTOM, toggle_bottom, 'active', Gio.SettingsBindFlags.DEFAULT) toggle_text = builder.get_object('display_text_checkbox') self.settings.bind(gs.PluginKey.DISPLAY_TEXT, toggle_text, 'active', Gio.SettingsBindFlags.DEFAULT) box_text = builder.get_object('display_text_box') self.settings.bind(gs.PluginKey.DISPLAY_TEXT, box_text, 'sensitive', Gio.SettingsBindFlags.GET) toggle_text_ellipsize = builder.get_object( 'display_text_ellipsize_checkbox') self.settings.bind(gs.PluginKey.DISPLAY_TEXT_ELLIPSIZE, toggle_text_ellipsize, 'active', Gio.SettingsBindFlags.DEFAULT) box_text_ellipsize_length = builder.get_object( 'display_text_ellipsize_length_box') self.settings.bind(gs.PluginKey.DISPLAY_TEXT_ELLIPSIZE, box_text_ellipsize_length, 'sensitive', Gio.SettingsBindFlags.GET) spinner_text_ellipsize_length = builder.get_object( 'display_text_ellipsize_length_spin') self.settings.bind(gs.PluginKey.DISPLAY_TEXT_ELLIPSIZE_LENGTH, spinner_text_ellipsize_length, 'value', Gio.SettingsBindFlags.DEFAULT) spinner_font_size = builder.get_object( 'display_font_spin') self.settings.bind(gs.PluginKey.DISPLAY_FONT_SIZE, spinner_font_size, 'value', Gio.SettingsBindFlags.DEFAULT) cover_size_scale = builder.get_object('cover_size_adjustment') self.settings.bind(gs.PluginKey.COVER_SIZE, cover_size_scale, 'value', Gio.SettingsBindFlags.DEFAULT) add_shadow = builder.get_object('add_shadow_checkbox') self.settings.bind(gs.PluginKey.ADD_SHADOW, add_shadow, 'active', Gio.SettingsBindFlags.DEFAULT) rated_box = builder.get_object('rated_box') self.stars = ReactiveStar(size=StarSize.BIG) self.stars.connect('changed', self.rating_changed_callback) align = Gtk.Alignment.new(0.5, 0, 0, 0.1) align.add(self.stars) rated_box.add(align) self.stars.set_rating(self.settings[gs.PluginKey.RATING]) autostart = builder.get_object('autostart_checkbox') self.settings.bind(gs.PluginKey.AUTOSTART, autostart, 'active', Gio.SettingsBindFlags.DEFAULT) toolbar_pos_combo = builder.get_object('show_in_combobox') renderer = Gtk.CellRendererText() toolbar_pos_combo.pack_start(renderer, True) toolbar_pos_combo.add_attribute(renderer, 'text', 1) self.settings.bind(gs.PluginKey.TOOLBAR_POS, toolbar_pos_combo, 'active-id', Gio.SettingsBindFlags.DEFAULT) light_source_combo = builder.get_object('light_source_combobox') renderer = Gtk.CellRendererText() light_source_combo.pack_start(renderer, True) light_source_combo.add_attribute(renderer, 'text', 1) self.settings.bind(gs.PluginKey.SHADOW_IMAGE, light_source_combo, 'active-id', Gio.SettingsBindFlags.DEFAULT) combo_liststore = builder.get_object('combo_liststore') from coverart_utils import Theme for theme in Theme(self).themes: combo_liststore.append([theme, theme]) theme_combo = builder.get_object('theme_combobox') renderer = Gtk.CellRendererText() theme_combo.pack_start(renderer, True) theme_combo.add_attribute(renderer, 'text', 1) self.settings.bind(gs.PluginKey.THEME, theme_combo, 'active-id', Gio.SettingsBindFlags.DEFAULT) button_relief = builder.get_object('button_relief_checkbox') self.settings.bind(gs.PluginKey.BUTTON_RELIEF, button_relief, 'active', Gio.SettingsBindFlags.DEFAULT) # create user data files popup = RB.find_user_data_file('plugins/coverart_browser/img/usericons/popups.xml') if not os.path.isfile(popup): template = rb.find_plugin_file(self, 'template/popups.xml') folder = os.path.split(popup)[0] if not os.path.exists(folder): os.makedirs(folder) shutil.copyfile(template, popup) # now prepare the genre tab from coverart_utils import GenreConfiguredSpriteSheet from coverart_utils import get_stock_size from coverart_utils import GenreType self._sheet = GenreConfiguredSpriteSheet(self, "genre", get_stock_size()) self.alt_liststore = builder.get_object('alt_liststore') self.alt_user_liststore = builder.get_object('alt_user_liststore') self._iters = {} for key in self._sheet.keys(): store_iter = self.alt_liststore.append([key, self._sheet[key]]) self._iters[(key,self.GENRE_POPUP)] = store_iter for key, value in self._sheet.genre_alternate.iteritems(): if key.genre_type == GenreConfiguredSpriteSheet.GENRE_USER: store_iter = self.alt_user_liststore.append([key.name, self._sheet[self._sheet.genre_alternate[key]], self._sheet.genre_alternate[key]]) self._iters[(key.name, self.GENRE_LIST)] = store_iter self.amend_mode = False self.blank_iter = None self.genre_combobox = builder.get_object('genre_combobox') self.genre_entry = builder.get_object('genre_entry') self.genre_view = builder.get_object('genre_view') self.save_button = builder.get_object('save_button') self.filechooserdialog = builder.get_object('filechooserdialog') # return the dialog return builder.get_object('main_notebook')
def load_catalogue(): def catalogue_chunk_cb(loader, chunk, total, parser): if chunk is None: self.__load_progress.props.task_outcome = RB.TaskOutcome.COMPLETE error = loader.get_error() if error: # report error somehow? print("error loading catalogue: %s" % error) try: parser.close() except xml.sax.SAXParseException as e: # there isn't much we can do here print("error parsing catalogue: %s" % e) self.__show_loading_screen(False) self.__catalogue_loader = None # restart in-progress downloads # (doesn't really belong here) for f in magnatune_in_progress_dir.enumerate_children( 'standard::name', Gio.FileQueryInfoFlags.NONE, None): name = f.get_name() if not name.startswith("in_progress_"): continue (result, uri, etag ) = magnatune_in_progress_dir.resolve_relative_path( name).load_contents(None) uri = uri.decode('utf-8') print("restarting download from %s" % uri) self.__download_album(uri, name[12:]) else: # hack around some weird chars that show up in the catalogue for some reason data = chunk.get_data().decode('utf-8', errors='replace') data = data.replace("\x19", "'") data = data.replace("\x13", "-") # argh. data = data.replace("Rock & Roll", "Rock & Roll") try: parser.feed(data) except xml.sax.SAXParseException as e: print("error parsing catalogue: %s" % e) load_size['size'] += len(data) self.__load_progress.props.task_progress = min( float(load_size['size']) / total, 1.0) self.__has_loaded = True self.__load_progress = RB.TaskProgressSimple.new() self.__load_progress.props.task_label = _( "Loading Magnatune catalog") self.props.shell.props.task_list.add_task(self.__load_progress) load_size = {'size': 0} parser = xml.sax.make_parser() parser.setContentHandler( TrackListHandler(self.__db, self.__entry_type, self.__sku_dict, self.__home_dict, self.__art_dict)) self.__catalogue_loader = RB.ChunkLoader() self.__catalogue_loader.set_callback(catalogue_chunk_cb, parser) self.__catalogue_loader.start(magnatune_song_info, 64 * 1024)
def actual_key_case(self, k): return self._s.get(RB.search_fold(k))
def __init__(self): self.lyrics = "" self.lyrics_cache = os.path.join(RB.user_cache_dir(), "web-lyrics", "") self.krc_dir = os.path.join(RB.music_dir(), "kugou-lyric", "")
def __contains__(self, k): return RB.search_fold(k) in self._s
def __set_sources(self): """ setup the sources includes collect, temp """ shell = self.object # Add icon to the collect source theme = Gtk.IconTheme.get_default() what, width, height = Gtk.icon_size_lookup(Gtk.IconSize.LARGE_TOOLBAR) # create a page group page_group = RB.DisplayPageGroup.get_by_id("baidu-music") if not page_group: page_group = RB.DisplayPageGroup( shell=shell, id="baidu-music", name=_("Baidu Music"), category=RB.DisplayPageGroupType.TRANSIENT, ) shell.append_display_page(page_group, None) #RB.DisplayPageGroup.get_by_id("stores")) # create the temp source self.temp_source = GObject.new( TempSource, name=_("Temporary"), shell=shell, plugin=self, entry_type=self.entry_type, settings=self.settings.get_child("source"), toolbar_path="/TempSourceToolbar", is_local=False, ) icon = Gtk.IconTheme.get_default().load_icon( "audio-x-generic", width, Gtk.IconLookupFlags.GENERIC_FALLBACK) #icon = GdkPixbuf.Pixbuf.new_from_file_at_size( #rb.find_plugin_file(self, TEMP_ICON), width, height #) self.temp_source.set_property("pixbuf", icon) shell.append_display_page(self.temp_source, page_group) # create the collect source self.collect_source = GObject.new( CollectSource, name=_("My Collect"), shell=shell, plugin=self, entry_type=self.entry_type, settings=self.settings.get_child("source"), toolbar_path="/CollectSourceToolbar", is_local=False, ) icon = GdkPixbuf.Pixbuf.new_from_file_at_size( rb.find_plugin_file(self, COLLECT_ICON), width, height ) self.collect_source.set_property("pixbuf", icon) shell.append_display_page(self.collect_source, page_group) shell.register_entry_type_for_source(self.collect_source, self.entry_type) # Add a page_group which includes all online playlists playlist_page_group = RB.DisplayPageGroup.get_by_id("baidu-music-playlists") if not playlist_page_group: playlist_page_group = RB.DisplayPageGroup( shell=shell, id="baidu-music-playlists", name=_("Online Playlists"), category=RB.DisplayPageGroupType.TRANSIENT, ) icon = Gtk.IconTheme.get_default().load_icon( "audio-x-mp3-playlist", width, Gtk.IconLookupFlags.GENERIC_FALLBACK) #icon = GdkPixbuf.Pixbuf.new_from_file_at_size( #rb.find_plugin_file(self, PLAYLIST_ICON), width, height #) playlist_page_group.set_property("pixbuf", icon) shell.append_display_page(playlist_page_group, page_group) self.page_group = page_group self.playlist_page_group = playlist_page_group
def __init__(self, d): self._d = d self._s = dict((RB.search_fold(k), k) for k in d)
import sys import xml import urllib.parse, urllib.request import threading import zipfile import rb from gi.repository import RB from gi.repository import GObject, Gtk, Gdk, Gio, GLib from TrackListHandler import TrackListHandler from DownloadAlbumHandler import DownloadAlbumHandler, MagnatuneDownloadError import MagnatuneAccount import gettext gettext.install('rhythmbox', RB.locale_dir()) magnatune_partner_id = "rhythmbox" # URIs magnatune_song_info_uri = "http://magnatune.com/info/song_info_xml.zip" magnatune_changed_uri = "http://magnatune.com/info/changed.txt" magnatune_buy_album_uri = "https://magnatune.com/buy/choose?" magnatune_api_download_uri = "http://%s:%[email protected]/buy/membership_free_dl_xml?" magnatune_in_progress_dir = Gio.file_new_for_path(RB.user_data_dir()).resolve_relative_path('magnatune') magnatune_cache_dir = Gio.file_new_for_path(RB.user_cache_dir()).resolve_relative_path('magnatune') magnatune_song_info = os.path.join(magnatune_cache_dir.get_path(), 'song_info.xml') magnatune_song_info_temp = os.path.join(magnatune_cache_dir.get_path(), 'song_info.zip.tmp') magnatune_changes = os.path.join(magnatune_cache_dir.get_path(), 'changed.txt')
def __download_album(self, audio_dl_uri, sku): def update_progress(self): complete, total = map(sum, zip(*self.__downloads.values())) if total > 0: self.__download_progress.props.task_progress = min( float(complete) / total, 1.0) def download_progress(copy, complete, total, self): self.__downloads[audio_dl_uri] = (complete, total) update_progress(self) def download_finished(copy, success, self): del self.__downloads[audio_dl_uri] del self.__copies[audio_dl_uri] update_progress(self) print("download of %s finished: %s" % (audio_dl_uri, success)) if success: threading.Thread(target=unzip_album).start() else: remove_download_files() if len(self.__downloads) == 0: self.__download_progress.props.task_outcome = RB.TaskOutcome.COMPLETE self.__download_progress = None def unzip_album(): # just use the first library location library = Gio.Settings.new("org.gnome.rhythmbox.rhythmdb") library_location = Gio.file_new_for_uri(library['locations'][0]) print("unzipping %s" % dest.get_path()) album = zipfile.ZipFile(dest.get_path()) for track in album.namelist(): track_uri = library_location.resolve_relative_path( track).get_uri() print("zip file entry: %s => %s" % (track, track_uri)) track_uri = RB.sanitize_uri_for_filesystem(track_uri) RB.uri_create_parent_dirs(track_uri) track_out = Gio.file_new_for_uri(track_uri).create( Gio.FileCreateFlags.NONE, None) if track_out is not None: track_out.write(album.read(track), None) track_out.close(None) print("adding %s to library" % track_uri) self.__db.add_uri(track_uri) album.close() remove_download_files() def remove_download_files(): print("removing download files") in_progress.delete(None) dest.delete(None) in_progress = magnatune_in_progress_dir.resolve_relative_path( "in_progress_" + sku) dest = magnatune_in_progress_dir.resolve_relative_path(sku) in_progress.replace_contents( audio_dl_uri.encode('utf-8'), None, False, Gio.FileCreateFlags.PRIVATE | Gio.FileCreateFlags.REPLACE_DESTINATION, None) try: # For some reason, Gio.FileCopyFlags.OVERWRITE doesn't work for copy_async dest.delete(None) except: pass if self.__download_progress is None: self.__download_progress = RB.TaskProgressSimple.new() self.__download_progress.props.task_label = _( "Downloading from Magnatune") self.__download_progress.connect('cancel', self.cancel_downloads) dl = RB.AsyncCopy() dl.set_progress(download_progress, self) dl.start(audio_dl_uri, dest.get_uri(), download_finished, self) self.__downloads[audio_dl_uri] = (0, 0) # (current, total) self.__copies[audio_dl_uri] = dl
def _create_display_contents(self, plugin): print("DEBUG - create_display_contents") # create the ui self._first_run = True cl = CoverLocale() cl.switch_locale(cl.Locale.LOCALE_DOMAIN) builder = Gtk.Builder() builder.set_translation_domain(cl.Locale.LOCALE_DOMAIN) builder.add_from_file( rb.find_plugin_file(plugin, 'ui/coverart_browser_prefs.ui')) self.launchpad_button = builder.get_object('show_launchpad') self.launchpad_label = builder.get_object('launchpad_label') builder.connect_signals(self) # . TRANSLATORS: Do not translate this string. translators = _('translator-credits') if translators != "translator-credits": self.launchpad_label.set_text(translators) else: self.launchpad_button.set_visible(False) gs = GSetting() # bind the toggles to the settings toggle_statusbar = builder.get_object('custom_statusbar_checkbox') self.settings.bind(gs.PluginKey.CUSTOM_STATUSBAR, toggle_statusbar, 'active', Gio.SettingsBindFlags.DEFAULT) toggle_text = builder.get_object('display_text_checkbox') self.settings.bind(gs.PluginKey.DISPLAY_TEXT, toggle_text, 'active', Gio.SettingsBindFlags.DEFAULT) box_text = builder.get_object('display_text_box') self.settings.bind(gs.PluginKey.DISPLAY_TEXT, box_text, 'sensitive', Gio.SettingsBindFlags.GET) self.display_text_pos = self.settings[gs.PluginKey.DISPLAY_TEXT_POS] self.display_text_under_radiobutton = builder.get_object( 'display_text_under_radiobutton') self.display_text_within_radiobutton = builder.get_object( 'display_text_within_radiobutton') if self.display_text_pos: self.display_text_under_radiobutton.set_active(True) else: self.display_text_within_radiobutton.set_active(True) random_scale = builder.get_object('random_adjustment') self.settings.bind(gs.PluginKey.RANDOM, random_scale, 'value', Gio.SettingsBindFlags.DEFAULT) toggle_text_ellipsize = builder.get_object( 'display_text_ellipsize_checkbox') self.settings.bind(gs.PluginKey.DISPLAY_TEXT_ELLIPSIZE, toggle_text_ellipsize, 'active', Gio.SettingsBindFlags.DEFAULT) box_text_ellipsize_length = builder.get_object( 'display_text_ellipsize_length_box') self.settings.bind(gs.PluginKey.DISPLAY_TEXT_ELLIPSIZE, box_text_ellipsize_length, 'sensitive', Gio.SettingsBindFlags.GET) spinner_text_ellipsize_length = builder.get_object( 'display_text_ellipsize_length_spin') self.settings.bind(gs.PluginKey.DISPLAY_TEXT_ELLIPSIZE_LENGTH, spinner_text_ellipsize_length, 'value', Gio.SettingsBindFlags.DEFAULT) spinner_font_size = builder.get_object('display_font_spin') self.settings.bind(gs.PluginKey.DISPLAY_FONT_SIZE, spinner_font_size, 'value', Gio.SettingsBindFlags.DEFAULT) cover_size_scale = builder.get_object('cover_size_adjustment') #self.settings.bind(gs.PluginKey.COVER_SIZE, cover_size_scale, 'value', # Gio.SettingsBindFlags.DEFAULT) self._cover_size = self.settings[gs.PluginKey.COVER_SIZE] cover_size_scale.set_value(self._cover_size) cover_size_scale.connect('value-changed', self.on_cover_size_scale_changed) add_shadow = builder.get_object('add_shadow_checkbox') self.settings.bind(gs.PluginKey.ADD_SHADOW, add_shadow, 'active', Gio.SettingsBindFlags.DEFAULT) rated_box = builder.get_object('rated_box') self.stars = ReactiveStar(size=StarSize.BIG) self.stars.connect('changed', self.rating_changed_callback) align = Gtk.Alignment.new(0.5, 0, 0, 0.1) align.add(self.stars) rated_box.add(align) self.stars.set_rating(self.settings[gs.PluginKey.RATING]) autostart = builder.get_object('autostart_checkbox') self.settings.bind(gs.PluginKey.AUTOSTART, autostart, 'active', Gio.SettingsBindFlags.DEFAULT) toolbar_pos_combo = builder.get_object('show_in_combobox') renderer = Gtk.CellRendererText() toolbar_pos_combo.pack_start(renderer, True) toolbar_pos_combo.add_attribute(renderer, 'text', 1) self.settings.bind(gs.PluginKey.TOOLBAR_POS, toolbar_pos_combo, 'active-id', Gio.SettingsBindFlags.DEFAULT) light_source_combo = builder.get_object('light_source_combobox') renderer = Gtk.CellRendererText() light_source_combo.pack_start(renderer, True) light_source_combo.add_attribute(renderer, 'text', 1) self.settings.bind(gs.PluginKey.SHADOW_IMAGE, light_source_combo, 'active-id', Gio.SettingsBindFlags.DEFAULT) combo_liststore = builder.get_object('combo_liststore') from coverart_utils import Theme for theme in Theme(self).themes: combo_liststore.append([theme, theme]) theme_combo = builder.get_object('theme_combobox') renderer = Gtk.CellRendererText() theme_combo.pack_start(renderer, True) theme_combo.add_attribute(renderer, 'text', 1) self.settings.bind(gs.PluginKey.THEME, theme_combo, 'active-id', Gio.SettingsBindFlags.DEFAULT) button_relief = builder.get_object('button_relief_checkbox') self.settings.bind(gs.PluginKey.BUTTON_RELIEF, button_relief, 'active', Gio.SettingsBindFlags.DEFAULT) # create user data files cachedir = RB.user_cache_dir() + "/coverart_browser/usericons" if not os.path.exists(cachedir): os.makedirs(cachedir) popup = cachedir + "/popups.xml" temp = RB.find_user_data_file( 'plugins/coverart_browser/img/usericons/popups.xml') # lets see if there is a legacy file - if necessary copy it to the cache dir if os.path.isfile(temp) and not os.path.isfile(popup): shutil.copyfile(temp, popup) if not os.path.isfile(popup): template = rb.find_plugin_file(plugin, 'template/popups.xml') folder = os.path.split(popup)[0] if not os.path.exists(folder): os.makedirs(folder) shutil.copyfile(template, popup) # now prepare the genre tab from coverart_utils import GenreConfiguredSpriteSheet from coverart_utils import get_stock_size self._sheet = GenreConfiguredSpriteSheet(plugin, "genre", get_stock_size()) self.alt_liststore = builder.get_object('alt_liststore') self.alt_user_liststore = builder.get_object('alt_user_liststore') self._iters = {} for key in list(self._sheet.keys()): store_iter = self.alt_liststore.append([key, self._sheet[key]]) self._iters[(key, self.GENRE_POPUP)] = store_iter for key, value in self._sheet.genre_alternate.items(): if key.genre_type == GenreConfiguredSpriteSheet.GENRE_USER: store_iter = self.alt_user_liststore.append([ key.name, self._sheet[self._sheet.genre_alternate[key]], self._sheet.genre_alternate[key] ]) self._iters[(key.name, self.GENRE_LIST)] = store_iter self.amend_mode = False self.blank_iter = None self.genre_combobox = builder.get_object('genre_combobox') self.genre_entry = builder.get_object('genre_entry') self.genre_view = builder.get_object('genre_view') self.save_button = builder.get_object('save_button') self.filechooserdialog = builder.get_object('filechooserdialog') last_genre_folder = self.settings[gs.PluginKey.LAST_GENRE_FOLDER] if last_genre_folder != "": self.filechooserdialog.set_current_folder(last_genre_folder) padding_scale = builder.get_object('padding_adjustment') self.settings.bind(gs.PluginKey.ICON_PADDING, padding_scale, 'value', Gio.SettingsBindFlags.DEFAULT) spacing_scale = builder.get_object('spacing_adjustment') self.settings.bind(gs.PluginKey.ICON_SPACING, spacing_scale, 'value', Gio.SettingsBindFlags.DEFAULT) icon_automatic = builder.get_object('icon_automatic_checkbox') self.settings.bind(gs.PluginKey.ICON_AUTOMATIC, icon_automatic, 'active', Gio.SettingsBindFlags.DEFAULT) #flow tab flow_combo = builder.get_object('flow_combobox') renderer = Gtk.CellRendererText() flow_combo.pack_start(renderer, True) flow_combo.add_attribute(renderer, 'text', 1) self.settings.bind(gs.PluginKey.FLOW_APPEARANCE, flow_combo, 'active-id', Gio.SettingsBindFlags.DEFAULT) flow_hide = builder.get_object('hide_caption_checkbox') self.settings.bind(gs.PluginKey.FLOW_HIDE_CAPTION, flow_hide, 'active', Gio.SettingsBindFlags.DEFAULT) flow_scale = builder.get_object('cover_scale_adjustment') self.settings.bind(gs.PluginKey.FLOW_SCALE, flow_scale, 'value', Gio.SettingsBindFlags.DEFAULT) flow_width = builder.get_object('cover_width_adjustment') self.settings.bind(gs.PluginKey.FLOW_WIDTH, flow_width, 'value', Gio.SettingsBindFlags.DEFAULT) flow_max = builder.get_object('flow_max_adjustment') self.settings.bind(gs.PluginKey.FLOW_MAX, flow_max, 'value', Gio.SettingsBindFlags.DEFAULT) flow_automatic = builder.get_object('automatic_checkbox') self.settings.bind(gs.PluginKey.FLOW_AUTOMATIC, flow_automatic, 'active', Gio.SettingsBindFlags.DEFAULT) self.background_colour = self.settings[ gs.PluginKey.FLOW_BACKGROUND_COLOUR] self.white_radiobutton = builder.get_object('white_radiobutton') self.black_radiobutton = builder.get_object('black_radiobutton') if self.background_colour == 'W': self.white_radiobutton.set_active(True) else: self.black_radiobutton.set_active(True) self.text_alignment = self.settings[gs.PluginKey.TEXT_ALIGNMENT] self.text_alignment_left_radiobutton = builder.get_object( 'left_alignment_radiobutton') self.text_alignment_centre_radiobutton = builder.get_object( 'centre_alignment_radiobutton') self.text_alignment_right_radiobutton = builder.get_object( 'right_alignment_radiobutton') if self.text_alignment == 0: self.text_alignment_left_radiobutton.set_active(True) elif self.text_alignment == 1: self.text_alignment_centre_radiobutton.set_active(True) else: self.text_alignment_right_radiobutton.set_active(True) # return the dialog self._first_run = False print("end create dialog contents") return builder.get_object('main_notebook')
def get_cover(self, db_entry=None): # Find cover in music dir if db_entry: print("dbentry") cover_dir = path.dirname( url2pathname(db_entry.get_playback_uri()).replace( 'file://', '')) if path.isdir(cover_dir): print(cover_dir) for f in listdir(cover_dir): file_name = path.join(cover_dir, f) mt = mimetypes.guess_type(file_name)[0] if mt and mt.startswith('image/'): if path.splitext(f)[0].lower() in IMAGE_NAMES: print("spli") print(file_name) return file_name # Find cover saved by artdisplay plugin song_info = self.get_song_info(db_entry) for rb_cover_path in ('~/.gnome2/rhythmbox/covers', '~/.cache/rhythmbox/covers/'): for file_type in ('jpg', 'png', 'jpeg', 'gif', 'svg'): cover_file = path.join( path.expanduser(rb_cover_path), '%s - %s.%s' % (song_info['artist'], song_info['album'], file_type)) if path.isfile(cover_file): print("Found image in cache folder") print(cover_file) return cover_file key = db_entry.create_ext_db_key(RB.RhythmDBPropType.ALBUM) cover_db = RB.ExtDB(name='album-art') art_location = cover_db.lookup(key) if art_location and not isinstance(art_location, str): art_location = art_location[0] # hack for RB 3.2 api if art_location and path.exists(art_location): print(art_location) return art_location # Find the image from AlbumArt plugin #cover_art = self.db.entry_request_extra_metadata(db_entry, "rb:coverArt") # If image not found return #if cover_art==None: # print "Image not found, bloody timeouts" # return DesktopControl.UNKNOWN_COVER # Do the dirty work here cover_file = path.expanduser(STORAGE_LOC) + song_info[ 'title'] + "-" + song_info['artist'] + ".jpg" print(cover_file) cover_art.save(cover_file, "jpeg", {"quality": "100"}) print("Returning cover file") print(cover_file) return cover_file # No cover found print("no cover") return DesktopControl.UNKNOWN_COVER # Not playing print("not playing") return None
from PodcastCoverArtSearch import PodcastCoverArtSearch from MusicBrainzCoverArtSearch import MusicBrainzCoverArtSearch from LastFMCoverArtSearch import LastFMCoverArtSearch from EmbeddedCoverArtSearch import EmbeddedCoverArtSearch from LocalCoverArtSearch import LocalCoverArtSearch from urllib import unquote, pathname2url ART_SEARCHES_LOCAL = [LocalCoverArtSearch, EmbeddedCoverArtSearch] ART_SEARCHES_REMOTE = [ PodcastCoverArtSearch, LastFMCoverArtSearch, MusicBrainzCoverArtSearch ] OLD_ART_FOLDER = '~/.gnome2/rhythmbox/covers' ART_FOLDER = os.path.join(RB.user_cache_dir(), 'covers') ART_CACHE_EXTENSION_JPG = 'jpg' ART_CACHE_EXTENSION_PNG = 'png' ART_CACHE_EXTENSION_META = 'rb-meta' ART_CACHE_FORMAT_JPG = 'jpeg' ART_CACHE_FORMAT_PNG = 'png' ART_CACHE_SETTINGS_NAMES_JPG = ["quality"] ART_CACHE_SETTINGS_VALUES_JPG = ["100"] ART_CACHE_SETTINGS_NAMES_PNG = ["compression"] ART_CACHE_SETTINGS_VALUES_PNG = ["9"] class TicketSystem: def __init__(self): self.counter = itertools.count() self.hash = {}
def setup(self): shell = self.props.shell builder = Gtk.Builder() builder.add_from_file( rb.find_plugin_file(self.props.plugin, "soundcloud.ui")) self.scrolled = builder.get_object("container-scrolled") self.scrolled.set_no_show_all(True) self.scrolled.hide() self.more_containers_idle = 0 adj = self.scrolled.get_vadjustment() adj.connect("changed", self.scroll_adjust_changed_cb) adj.connect("value-changed", self.scroll_adjust_changed_cb) self.search_entry = RB.SearchEntry(spacing=6) self.search_entry.props.explicit_mode = True self.fetch_more_button = Gtk.Button.new_with_label( _("Fetch more tracks")) self.fetch_more_button.connect("clicked", self.show_more_cb) self.fetch_more_button.set_sensitive(False) action = Gio.SimpleAction.new("soundcloud-search-type", GLib.VariantType.new('s')) action.connect("activate", self.search_type_action_cb) shell.props.window.add_action(action) m = Gio.Menu() for st in sorted(self.search_types): i = Gio.MenuItem() i.set_label(self.search_types[st]['label']) i.set_action_and_target_value("win.soundcloud-search-type", GLib.Variant.new_string(st)) m.append_item(i) self.search_popup = Gtk.Menu.new_from_model(m) action.activate(GLib.Variant.new_string("tracks")) grid = builder.get_object("soundcloud-source") self.search_entry.connect("search", self.search_entry_cb) self.search_entry.connect("activate", self.search_entry_cb) self.search_entry.connect("show-popup", self.search_popup_cb) self.search_entry.set_size_request(400, -1) searchbox = builder.get_object("search-box") searchbox.pack_start(self.search_entry, False, True, 0) searchbox.pack_start(self.fetch_more_button, False, True, 0) self.search_popup.attach_to_widget(self.search_entry, None) self.containers = builder.get_object("container-store") self.container_view = builder.get_object("containers") self.container_view.set_model(self.containers) action = Gio.SimpleAction.new("soundcloud-open-uri", GLib.VariantType.new('s')) action.connect("activate", self.open_uri_action_cb) shell.props.window.add_action(action) r = Gtk.CellRendererText() c = Gtk.TreeViewColumn("", r, text=0) self.container_view.append_column(c) self.container_view_changed_id = self.container_view.get_selection( ).connect('changed', self.selection_changed_cb) self.songs = RB.EntryView(db=shell.props.db, shell_player=shell.props.shell_player, is_drag_source=True, is_drag_dest=False) self.songs.append_column(RB.EntryViewColumn.TITLE, True) self.songs.append_column(RB.EntryViewColumn.ARTIST, True) self.songs.append_column(RB.EntryViewColumn.DURATION, True) self.songs.append_column(RB.EntryViewColumn.YEAR, False) self.songs.append_column(RB.EntryViewColumn.GENRE, False) self.songs.append_column(RB.EntryViewColumn.BPM, False) self.songs.append_column(RB.EntryViewColumn.FIRST_SEEN, False) self.songs.set_model(self.props.query_model) self.songs.connect("notify::sort-order", self.sort_order_changed_cb) self.songs.connect("selection-changed", self.songs_selection_changed_cb) paned = builder.get_object("paned") paned.pack2(self.songs) self.bind_settings(self.songs, paned, None, True) self.sc_button = Gtk.MenuButton() self.sc_button.set_relief(Gtk.ReliefStyle.NONE) img = Gtk.Image.new_from_file( rb.find_plugin_file(self.props.plugin, "powered-by-soundcloud.png")) self.sc_button.add(img) box = builder.get_object("soundcloud-button-box") box.pack_start(self.sc_button, True, True, 0) self.build_sc_menu() self.pack_start(grid, expand=True, fill=True, padding=0) grid.show_all() self.art_store = RB.ExtDB(name="album-art") player = shell.props.shell_player player.connect('playing-song-changed', self.playing_entry_changed_cb)
def find_plugin_file(self, filename): info = self.plugin_info path = os.path.join(info.get_data_dir(), filename) if os.path.exists(path): return path return RB.file(filename)