~ubuntu-branches/ubuntu/oneiric/rhythmbox/oneiric

« back to all changes in this revision

Viewing changes to plugins/magnatune/MagnatuneSource.py

  • Committer: Bazaar Package Importer
  • Author(s): Rico Tzschichholz
  • Date: 2011-07-29 16:41:38 UTC
  • mto: This revision was merged to the branch mainline in revision 191.
  • Revision ID: james.westby@ubuntu.com-20110729164138-wwicy8nqalm18ck7
Tags: upstream-2.90.1~20110802
ImportĀ upstreamĀ versionĀ 2.90.1~20110802

Show diffs side-by-side

added added

removed removed

Lines of Context:
 
1
# -*- Mode: python; coding: utf-8; tab-width: 8; indent-tabs-mode: t; -*-
 
2
#
 
3
# Copyright (C) 2006 Adam Zimmerman  <adam_zimmerman@sfu.ca>
 
4
# Copyright (C) 2006 James Livingston  <doclivingston@gmail.com>
 
5
#
 
6
# This program is free software; you can redistribute it and/or modify
 
7
# it under the terms of the GNU General Public License as published by
 
8
# the Free Software Foundation; either version 2, or (at your option)
 
9
# any later version.
 
10
#
 
11
# The Rhythmbox authors hereby grant permission for non-GPL compatible
 
12
# GStreamer plugins to be used and distributed together with GStreamer
 
13
# and Rhythmbox. This permission is above and beyond the permissions granted
 
14
# by the GPL license by which Rhythmbox is covered. If you modify this code
 
15
# you may extend this exception to your version of the code, but you are not
 
16
# obligated to do so. If you do not wish to do so, delete this exception
 
17
# statement from your version.
 
18
#
 
19
# This program is distributed in the hope that it will be useful,
 
20
# but WITHOUT ANY WARRANTY; without even the implied warranty of
 
21
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 
22
# GNU General Public License for more details.
 
23
#
 
24
# You should have received a copy of the GNU General Public License
 
25
# along with this program; if not, write to the Free Software
 
26
# Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301  USA.
 
27
 
 
28
import os
 
29
import gobject
 
30
import xml
 
31
import urllib
 
32
import urlparse
 
33
import threading
 
34
import zipfile
 
35
import gnomekeyring as keyring
 
36
 
 
37
import rb
 
38
from gi.repository import RB
 
39
from gi.repository import Gtk, Gio
 
40
# XXX use GnomeKeyring when introspection is available
 
41
 
 
42
from TrackListHandler import TrackListHandler
 
43
from BuyAlbumHandler import BuyAlbumHandler, MagnatunePurchaseError
 
44
 
 
45
magnatune_partner_id = "rhythmbox"
 
46
 
 
47
# URIs
 
48
magnatune_song_info_uri = Gio.file_new_for_uri("http://magnatune.com/info/song_info_xml.zip")
 
49
magnatune_buy_album_uri = "https://magnatune.com/buy/choose?"
 
50
magnatune_api_download_uri = "http://%s:%s@download.magnatune.com/buy/membership_free_dl_xml?"
 
51
 
 
52
magnatune_in_progress_dir = Gio.file_new_for_path(RB.user_data_dir()).resolve_relative_path('magnatune')
 
53
magnatune_cache_dir = Gio.file_new_for_path(RB.user_cache_dir()).resolve_relative_path('magnatune')
 
54
 
 
55
magnatune_song_info = os.path.join(magnatune_cache_dir.get_path(), 'song_info.xml')
 
56
magnatune_song_info_temp = os.path.join(magnatune_cache_dir.get_path(), 'song_info.zip.tmp')
 
57
 
 
58
 
 
59
class MagnatuneSource(RB.BrowserSource):
 
60
        def __init__(self):
 
61
                RB.BrowserSource.__init__(self)
 
62
                self.hate = self
 
63
 
 
64
                self.__settings = Gio.Settings("org.gnome.rhythmbox.plugins.magnatune")
 
65
                # source state
 
66
                self.__activated = False
 
67
                self.__db = None
 
68
                self.__notify_id = 0 # gobject.idle_add id for status notifications
 
69
                self.__info_screen = None # the loading screen
 
70
 
 
71
                # track data
 
72
                self.__sku_dict = {}
 
73
                self.__home_dict = {}
 
74
                self.__art_dict = {}
 
75
 
 
76
                # catalogue stuff
 
77
                self.__updating = True # whether we're loading the catalog right now
 
78
                self.__has_loaded = False # whether the catalog has been loaded yet
 
79
                self.__update_id = 0 # gobject.idle_add id for catalog updates
 
80
                self.__catalogue_loader = None
 
81
                self.__catalogue_check = None
 
82
                self.__load_progress = (0, 0) # (complete, total)
 
83
 
 
84
                # album download stuff
 
85
                self.__downloads = {} # keeps track of download progress for each file
 
86
                self.__cancellables = {} # keeps track of Gio.Cancellable objects so we can abort album downloads
 
87
 
 
88
        #
 
89
        # RBSource methods
 
90
        #
 
91
 
 
92
        def do_impl_show_entry_popup(self):
 
93
                self.show_source_popup("/MagnatuneSourceViewPopup")
 
94
 
 
95
        def do_get_status(self, status, progress_text, progress):
 
96
                if self.__updating:
 
97
                        complete, total = self.__load_progress
 
98
                        if total > 0:
 
99
                                progress = min(float(complete) / total, 1.0)
 
100
                        else:
 
101
                                progress = -1.0
 
102
                        return (_("Loading Magnatune catalog"), None, progress)
 
103
                elif len(self.__downloads) > 0:
 
104
                        complete, total = map(sum, zip(*self.__downloads.itervalues()))
 
105
                        if total > 0:
 
106
                                progress = min(float(complete) / total, 1.0)
 
107
                        else:
 
108
                                progress = -1.0
 
109
                        return (_("Downloading Magnatune Album(s)"), None, progress)
 
110
                else:
 
111
                        qm = self.props.query_model
 
112
                        return (qm.compute_status_normal("%d song", "%d songs"), None, 2.0)
 
113
 
 
114
        def do_get_ui_actions(self):
 
115
                return ["MagnatuneDownloadAlbum",
 
116
                        "MagnatuneArtistInfo",
 
117
                        "MagnatuneCancelDownload"]
 
118
 
 
119
        def do_selected(self):
 
120
                if not self.__activated:
 
121
                        shell = self.props.shell
 
122
                        self.__db = shell.props.db
 
123
                        self.__entry_type = self.props.entry_type
 
124
 
 
125
                        if not magnatune_in_progress_dir.query_exists(None):
 
126
                                magnatune_in_progress_path = magnatune_in_progress_dir.get_path()
 
127
                                os.mkdir(magnatune_in_progress_path, 0700)
 
128
 
 
129
                        if not magnatune_cache_dir.query_exists(None):
 
130
                                magnatune_cache_path = magnatune_cache_dir.get_path()
 
131
                                os.mkdir(magnatune_cache_path, 0700)
 
132
 
 
133
                        self.__activated = True
 
134
                        self.__show_loading_screen(True)
 
135
 
 
136
                        # start our catalogue updates
 
137
                        self.__update_id = gobject.timeout_add_seconds(6 * 60 * 60, self.__update_catalogue)
 
138
                        self.__update_catalogue()
 
139
 
 
140
        def do_impl_can_delete(self):
 
141
                return False
 
142
 
 
143
        def do_impl_pack_paned(self, paned):
 
144
                self.__paned_box = Gtk.VBox(homogeneous=False, spacing=5)
 
145
                self.pack_start(self.__paned_box, True, True, 0)
 
146
                self.__paned_box.pack_start(paned, True, True, 0)
 
147
 
 
148
 
 
149
        def do_delete_thyself(self):
 
150
                if self.__update_id != 0:
 
151
                        gobject.source_remove(self.__update_id)
 
152
                        self.__update_id = 0
 
153
 
 
154
                if self.__notify_id != 0:
 
155
                        gobject.source_remove(self.__notify_id)
 
156
                        self.__notify_id = 0
 
157
 
 
158
                if self.__catalogue_loader is not None:
 
159
                        self.__catalogue_loader.cancel()
 
160
                        self.__catalogue_loader = None
 
161
 
 
162
                if self.__catalogue_check is not None:
 
163
                        self.__catalogue_check.cancel()
 
164
                        self.__catalogue_check = None
 
165
 
 
166
                RB.BrowserSource.do_delete_thyself(self)
 
167
 
 
168
        #
 
169
        # methods for use by plugin and UI
 
170
        #
 
171
 
 
172
        def display_artist_info(self):
 
173
                screen = self.props.shell.props.window.get_screen()
 
174
                tracks = self.get_entry_view().get_selected_entries()
 
175
                urls = set([])
 
176
 
 
177
                for tr in tracks:
 
178
                        sku = self.__sku_dict[self.__db.entry_get_string(tr, RB.RhythmDBPropType.LOCATION)]
 
179
                        url = self.__home_dict[sku]
 
180
                        if url not in urls:
 
181
                                Gtk.show_uri(screen, url, Gdk.CURRENT_TIME)
 
182
                                urls.add(url)
 
183
 
 
184
        def purchase_redirect(self):
 
185
                screen = self.props.shell.props.window.get_screen()
 
186
                tracks = self.get_entry_view().get_selected_entries()
 
187
                urls = set([])
 
188
 
 
189
                for tr in tracks:
 
190
                        sku = self.__sku_dict[self.__db.entry_get_string(tr, RB.RhythmDBPropType.LOCATION)]
 
191
                        url = magnatune_buy_album_uri + urllib.urlencode({ 'sku': sku, 'ref': magnatune_partner_id })
 
192
                        if url not in urls:
 
193
                                Gtk.show_uri(screen, url, Gdk.CURRENT_TIME)
 
194
                                urls.add(url)
 
195
 
 
196
        def download_album(self):
 
197
                if selt.__settings['account_type'] != 'download':
 
198
                        # The user doesn't have a download account, so redirect them to the purchase page.
 
199
                        self.purchase_redirect()
 
200
                        return
 
201
 
 
202
                try:
 
203
                        # Just use the first library location
 
204
                        library = Gio.Settings("org.gnome.rhythmbox.rhythmdb")
 
205
                        library_location = library['locations'][0]
 
206
                except IndexError, e:
 
207
                        RB.error_dialog(title = _("Couldn't purchase album"),
 
208
                                        message = _("You must have a library location set to purchase an album."))
 
209
                        return
 
210
 
 
211
                tracks = self.get_entry_view().get_selected_entries()
 
212
                skus = []
 
213
 
 
214
                for track in tracks:
 
215
                        sku = self.__sku_dict[self.__db.entry_get_string(track, RB.RhythmDBPropType.LOCATION)]
 
216
                        if sku in skus:
 
217
                                continue
 
218
                        skus.append(sku)
 
219
                        self.__auth_download(sku)
 
220
 
 
221
        #
 
222
        # internal catalogue downloading and loading
 
223
        #
 
224
 
 
225
        def __update_catalogue(self):
 
226
                def update_cb(result):
 
227
                        self.__catalogue_check = None
 
228
                        if result is True:
 
229
                                download_catalogue()
 
230
                        elif self.__has_loaded is False:
 
231
                                load_catalogue()
 
232
 
 
233
                def download_catalogue():
 
234
                        def find_song_info(catalogue):
 
235
                                for info in catalogue.infolist():
 
236
                                        if info.filename.endswith("song_info.xml"):
 
237
                                                return info.filename;
 
238
                                return None
 
239
 
 
240
                        def download_progress(complete, total):
 
241
                                self.__load_progress = (complete, total)
 
242
                                self.__notify_status_changed()
 
243
 
 
244
                        def download_finished(uri, result):
 
245
                                try:
 
246
                                        success = uri.copy_finish(result)
 
247
                                except:
 
248
                                        success = False
 
249
 
 
250
                                if not success:
 
251
                                        return
 
252
 
 
253
                                # done downloading, unzip to real location
 
254
                                catalog_zip = zipfile.ZipFile(magnatune_song_info_temp)
 
255
                                catalog = open(magnatune_song_info, 'w')
 
256
                                filename = find_song_info(catalog_zip)
 
257
                                if filename is None:
 
258
                                        RB.error_dialog(title=_("Unable to load catalog"),
 
259
                                                        message=_("Rhythmbox could not understand the Magnatune catalog, please file a bug."))
 
260
                                        return
 
261
                                catalog.write(catalog_zip.read(filename))
 
262
                                catalog.close()
 
263
                                catalog_zip.close()
 
264
 
 
265
                                dest.delete()
 
266
                                self.__updating = False
 
267
                                self.__catalogue_loader = None
 
268
                                self.__notify_status_changed()
 
269
 
 
270
                                load_catalogue()
 
271
 
 
272
 
 
273
                        self.__updating = True
 
274
 
 
275
                        dest = Gio.file_new_for_path(magnatune_song_info_temp)
 
276
                        self.__catalogue_loader = Gio.Cancellable()
 
277
                        try:
 
278
                                # For some reason, Gio.FileCopyFlags.OVERWRITE doesn't work for copy_async
 
279
                                dest.delete()
 
280
                        except:
 
281
                                pass
 
282
                        magnatune_song_info_uri.copy_async(dest,
 
283
                                                           download_finished,
 
284
                                                           progress_callback=download_progress,
 
285
                                                           flags=Gio.FileCopyFlags.OVERWRITE,
 
286
                                                           cancellable=self.__catalogue_loader)
 
287
 
 
288
                def load_catalogue():
 
289
                        def got_items(result, items):
 
290
                                account_type = self.__settings['account_type']
 
291
                                username = ""
 
292
                                password = ""
 
293
                                if account_type == 'none':
 
294
                                        pass
 
295
                                elif result is not None or len(items) == 0:
 
296
                                        RB.error_dialog(title = _("Couldn't get account details"),
 
297
                                                        message = str(result))
 
298
                                        return
 
299
                                else:
 
300
                                        try:
 
301
                                                username, password = items[0].secret.split('\n')
 
302
                                        except ValueError: # Couldn't parse secret, possibly because it's empty
 
303
                                                pass
 
304
                                parser = xml.sax.make_parser()
 
305
                                parser.setContentHandler(TrackListHandler(self.__db, self.__entry_type, self.__sku_dict, self.__home_dict, self.__art_dict, account_type, username, password))
 
306
 
 
307
                                self.__catalogue_loader = rb.ChunkLoader()
 
308
                                self.__catalogue_loader.get_url_chunks(magnatune_song_info, 64*1024, True, catalogue_chunk_cb, parser)
 
309
 
 
310
                        def catalogue_chunk_cb(result, total, parser):
 
311
                                if not result or isinstance(result, Exception):
 
312
                                        if result:
 
313
                                                # report error somehow?
 
314
                                                print "error loading catalogue: %s" % result
 
315
 
 
316
                                        try:
 
317
                                                parser.close()
 
318
                                        except xml.sax.SAXParseException, e:
 
319
                                                # there isn't much we can do here
 
320
                                                print "error parsing catalogue: %s" % e
 
321
 
 
322
                                        self.__show_loading_screen(False)
 
323
                                        self.__updating = False
 
324
                                        self.__catalogue_loader = None
 
325
 
 
326
                                        # restart in-progress downloads
 
327
                                        # (doesn't really belong here)
 
328
                                        for f in magnatune_in_progress_dir.enumerate_children('standard::name'):
 
329
                                                name = f.get_name()
 
330
                                                if not name.startswith("in_progress_"):
 
331
                                                        continue
 
332
                                                uri = magnatune_in_progress_dir.resolve_relative_path(name).load_contents()[0]
 
333
                                                print "restarting download from %s" % uri
 
334
                                                self.__download_album(Gio.file_new_for_uri(uri), name[12:])
 
335
                                else:
 
336
                                        # hack around some weird chars that show up in the catalogue for some reason
 
337
                                        result = result.replace("\x19", "'")
 
338
                                        result = result.replace("\x13", "-")
 
339
 
 
340
                                        # argh.
 
341
                                        result = result.replace("Rock & Roll", "Rock &amp; Roll")
 
342
 
 
343
                                        try:
 
344
                                                parser.feed(result)
 
345
                                        except xml.sax.SAXParseException, e:
 
346
                                                print "error parsing catalogue: %s" % e
 
347
 
 
348
                                        load_size['size'] += len(result)
 
349
                                        self.__load_progress = (load_size['size'], total)
 
350
 
 
351
                                self.__notify_status_changed()
 
352
 
 
353
 
 
354
                        self.__has_loaded = True
 
355
                        self.__updating = True
 
356
                        self.__load_progress = (0, 0) # (complete, total)
 
357
                        self.__notify_status_changed()
 
358
 
 
359
                        load_size = {'size': 0}
 
360
                        keyring.find_items(keyring.ITEM_GENERIC_SECRET, {'rhythmbox-plugin': 'magnatune'}, got_items)
 
361
 
 
362
 
 
363
                self.__catalogue_check = rb.UpdateCheck()
 
364
                self.__catalogue_check.check_for_update(magnatune_song_info, magnatune_song_info_uri.get_uri(), update_cb)
 
365
 
 
366
 
 
367
        def __show_loading_screen(self, show):
 
368
                if self.__info_screen is None:
 
369
                        # load the builder stuff
 
370
                        builder = Gtk.Builder()
 
371
                        builder.add_from_file(rb.find_plugin_file(self.props.plugin, "magnatune-loading.ui"))
 
372
                        self.__info_screen = builder.get_object("magnatune_loading_scrolledwindow")
 
373
                        self.pack_start(self.__info_screen, True, True, 0)
 
374
                        self.get_entry_view().set_no_show_all(True)
 
375
                        self.__info_screen.set_no_show_all(True)
 
376
 
 
377
                self.__info_screen.set_property("visible", show)
 
378
                self.__paned_box.set_property("visible", not show)
 
379
 
 
380
        def __notify_status_changed(self):
 
381
                def change_idle_cb():
 
382
                        self.notify_status_changed()
 
383
                        self.__notify_id = 0
 
384
                        return False
 
385
 
 
386
                if self.__notify_id == 0:
 
387
                        self.__notify_id = gobject.idle_add(change_idle_cb)
 
388
 
 
389
        #
 
390
        # internal purchasing code
 
391
        #
 
392
 
 
393
        def __auth_download(self, sku): # http://magnatune.com/info/api
 
394
                def got_items(result, items):
 
395
                        if result is not None or len(items) == 0:
 
396
                                RB.error_dialog(title = _("Couldn't get account details"),
 
397
                                                message = str(result))
 
398
                                return
 
399
 
 
400
                        try:
 
401
                                username, password = items[0].secret.split('\n')
 
402
                        except ValueError: # Couldn't parse secret, possibly because it's empty
 
403
                                username = ""
 
404
                                password = ""
 
405
                        print "downloading album: " + sku
 
406
                        url_dict = {
 
407
                                'id':   magnatune_partner_id,
 
408
                                'sku':  sku
 
409
                        }
 
410
                        url = magnatune_api_download_uri % (username, password)
 
411
                        url = url + urllib.urlencode(url_dict)
 
412
 
 
413
                        l = rb.Loader()
 
414
                        l.get_url(url, auth_data_cb, (username, password))
 
415
 
 
416
                def auth_data_cb(data, (username, password)):
 
417
                        buy_album_handler = BuyAlbumHandler(self.__settings['format'])
 
418
                        auth_parser = xml.sax.make_parser()
 
419
                        auth_parser.setContentHandler(buy_album_handler)
 
420
 
 
421
                        if data is None:
 
422
                                # hmm.
 
423
                                return
 
424
 
 
425
                        try:
 
426
                                data = data.replace("<br>", "") # get rid of any stray <br> tags that will mess up the parser
 
427
                                # print data
 
428
                                auth_parser.feed(data)
 
429
                                auth_parser.close()
 
430
 
 
431
                                # process the URI: add authentication info, quote the filename component for some reason
 
432
                                parsed = urlparse.urlparse(buy_album_handler.url)
 
433
                                netloc = "%s:%s@%s" % (username, password, parsed.hostname)
 
434
 
 
435
                                spath = os.path.split(urllib.url2pathname(parsed.path))
 
436
                                basename = spath[1]
 
437
                                path = urllib.pathname2url(os.path.join(spath[0], urllib.quote(basename)))
 
438
 
 
439
                                authed = (parsed[0], netloc, path) + parsed[3:]
 
440
                                audio_dl_uri = urlparse.urlunparse(authed)
 
441
 
 
442
                                self.__download_album(Gio.file_new_for_uri(audio_dl_uri), sku)
 
443
 
 
444
                        except MagnatunePurchaseError, e:
 
445
                                RB.error_dialog(title = _("Download Error"),
 
446
                                                message = _("An error occurred while trying to authorize the download.\nThe Magnatune server returned:\n%s") % str(e))
 
447
                        except Exception, e:
 
448
                                RB.error_dialog(title = _("Error"),
 
449
                                                message = _("An error occurred while trying to download the album.\nThe error text is:\n%s") % str(e))
 
450
 
 
451
 
 
452
                keyring.find_items(keyring.ITEM_GENERIC_SECRET, {'rhythmbox-plugin': 'magnatune'}, got_items)
 
453
 
 
454
        def __download_album(self, audio_dl_uri, sku):
 
455
                def download_progress(current, total):
 
456
                        self.__downloads[str_uri] = (current, total)
 
457
                        self.__notify_status_changed()
 
458
 
 
459
                def download_finished(uri, result):
 
460
                        del self.__cancellables[str_uri]
 
461
                        del self.__downloads[str_uri]
 
462
 
 
463
                        try:
 
464
                                success = uri.copy_finish(result)
 
465
                        except Exception, e:
 
466
                                success = False
 
467
                                print "Download not completed: " + str(e)
 
468
 
 
469
                        if success:
 
470
                                threading.Thread(target=unzip_album).start()
 
471
                        else:
 
472
                                remove_download_files()
 
473
 
 
474
                        if len(self.__downloads) == 0: # All downloads are complete
 
475
                                shell = self.props.shell
 
476
                                manager = shell.props.ui_manager
 
477
                                manager.get_action("/MagnatuneSourceViewPopup/MagnatuneCancelDownload").set_sensitive(False)
 
478
                                if success:
 
479
                                        shell.notify_custom(4000, _("Finished Downloading"), _("All Magnatune downloads have been completed."))
 
480
 
 
481
                        self.__notify_status_changed()
 
482
 
 
483
                def unzip_album():
 
484
                        # just use the first library location
 
485
                        library = Gio.Settings("org.gnome.rhythmbox.rhythmdb")
 
486
                        library_location = Gio.file_new_for_uri(library['locations'][0])
 
487
 
 
488
                        album = zipfile.ZipFile(dest.get_path())
 
489
                        for track in album.namelist():
 
490
                                track_uri = library_location.resolve_relative_path(track).get_uri()
 
491
 
 
492
                                track_uri = RB.sanitize_uri_for_filesystem(track_uri)
 
493
                                RB.uri_create_parent_dirs(track_uri)
 
494
 
 
495
                                track_out = Gio.file_new_for_uri(track_uri).create()
 
496
                                if track_out is not None:
 
497
                                        track_out.write(album.read(track))
 
498
                                        track_out.close()
 
499
                                        self.__db.add_uri(track_uri)
 
500
 
 
501
                        album.close()
 
502
                        remove_download_files()
 
503
 
 
504
                def remove_download_files():
 
505
                        in_progress.delete()
 
506
                        dest.delete()
 
507
 
 
508
 
 
509
                in_progress = magnatune_in_progress_dir.resolve_relative_path("in_progress_" + sku)
 
510
                dest = magnatune_in_progress_dir.resolve_relative_path(sku)
 
511
 
 
512
                str_uri = audio_dl_uri.get_uri()
 
513
                in_progress.replace_contents(str_uri, None, False, flags=Gio.FileCreateFlags.PRIVATE|Gio.FileCreateFlags.REPLACE_DESTINATION)
 
514
 
 
515
                shell = self.props.shell
 
516
                manager = shell.props.ui_manager
 
517
                manager.get_action("/MagnatuneSourceViewPopup/MagnatuneCancelDownload").set_sensitive(True)
 
518
 
 
519
                self.__downloads[str_uri] = (0, 0) # (current, total)
 
520
 
 
521
                cancel = Gio.Cancellable()
 
522
                self.__cancellables[str_uri] = cancel
 
523
                try:
 
524
                        # For some reason, Gio.FileCopyFlags.OVERWRITE doesn't work for copy_async
 
525
                        dest.delete()
 
526
                except:
 
527
                        pass
 
528
 
 
529
                # no way to resume downloads, sadly
 
530
                audio_dl_uri.copy_async(dest,
 
531
                                        download_finished,
 
532
                                        progress_callback=download_progress,
 
533
                                        flags=Gio.FileCopyFlags.OVERWRITE,
 
534
                                        cancellable=cancel)
 
535
 
 
536
 
 
537
        def cancel_downloads(self):
 
538
                for cancel in self.__cancellables.values():
 
539
                        cancel.cancel()
 
540
 
 
541
                shell = self.props.shell
 
542
                manager = shell.props.ui_manager
 
543
                manager.get_action("/MagnatuneSourceViewPopup/MagnatuneCancelDownload").set_sensitive(False)
 
544
 
 
545
        def playing_entry_changed(self, entry):
 
546
                if not self.__db or not entry:
 
547
                        return
 
548
                if entry.get_entry_type() != self.__db.entry_type_get_by_name("MagnatuneEntryType"):
 
549
                        return
 
550
 
 
551
                gobject.idle_add(self.emit_cover_art_uri, entry)
 
552
 
 
553
        def emit_cover_art_uri(self, entry):
 
554
                sku = self.__sku_dict[self.__db.entry_get_string(entry, RB.RhythmDBPropType.LOCATION)]
 
555
                url = self.__art_dict[sku]
 
556
                self.__db.emit_entry_extra_metadata_notify(entry, 'rb:coverArt-uri', url)
 
557
                return False
 
558
 
 
559
gobject.type_register(MagnatuneSource)