Example #1
0
			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()
Example #2
0
	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(" & ", " &amp; ") # 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))
Example #3
0
			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()
Example #4
0
	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()
Example #6
0
            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)
Example #10
0
	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))
Example #11
0
		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))
Example #12
0
 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"
Example #13
0
	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
Example #15
0
    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
Example #17
0
	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)
Example #18
0
        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)
Example #19
0
	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))
Example #20
0
    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"] = ""
Example #23
0
	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")
Example #24
0
 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
Example #26
0
 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")
Example #29
0
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)
Example #30
0
    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)
Example #31
0
# 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
Example #32
0
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):
Example #33
0
    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
Example #34
0
 def set_folder_default(self, button, file_chooser):
     file_chooser.set_current_folder(
         os.path.join(RB.user_cache_dir(), "lyrics"))
Example #35
0
 def preamp_changed_cb(self, preamp):
     RB.settings_delayed_sync(self.settings, self.sync_preamp, preamp)
Example #36
0
 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
Example #38
0
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(),
Example #39
0
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))
Example #42
0
 def getMeasureResultsDir(self):
     cachedir = RB.user_cache_dir() + "/DRC"
     measureResultsDir = cachedir + "/MeasureResults"
     if not os.path.exists(measureResultsDir):
         os.makedirs(measureResultsDir)
     return measureResultsDir
Example #43
0
 def getTmpCfgDir(self):
     cachedir = RB.user_cache_dir() + "/DRC"
     tmpCfgDir = cachedir + "/TmpDRCCfg"
     if not os.path.exists(tmpCfgDir):
         os.makedirs(tmpCfgDir)
     return tmpCfgDir
Example #44
0
    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')
Example #45
0
        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 &amp; 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)
Example #46
0
 def actual_key_case(self, k):
     return self._s.get(RB.search_fold(k))
Example #47
0
 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", "")
Example #48
0
 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
Example #50
0
 def __init__(self, d):
     self._d = d
     self._s = dict((RB.search_fold(k), k) for k in d)
Example #51
0
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')
Example #52
0
    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
Example #53
0
    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')
Example #54
0
    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
Example #55
0
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 = {}
Example #56
0
    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)