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

« back to all changes in this revision

Viewing changes to plugins/magnatune/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, gio
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, GConf
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(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(path=RB.user_data_dir()).resolve_relative_path('magnatune')
53
 
magnatune_cache_dir = gio.File(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
 
        __gproperties__ = {
61
 
                'plugin': (RB.Plugin, 'plugin', 'plugin', gobject.PARAM_WRITABLE|gobject.PARAM_CONSTRUCT_ONLY),
62
 
        }
63
 
 
64
 
        __client = GConf.Client.get_default()
65
 
 
66
 
 
67
 
        def __init__(self):
68
 
                RB.BrowserSource.__init__(self, name=_("Magnatune"))
69
 
 
70
 
                # source state
71
 
                self.__activated = False
72
 
                self.__db = None
73
 
                self.__notify_id = 0 # gobject.idle_add id for status notifications
74
 
                self.__info_screen = None # the loading screen
75
 
 
76
 
                # track data
77
 
                self.__sku_dict = {}
78
 
                self.__home_dict = {}
79
 
                self.__art_dict = {}
80
 
 
81
 
                # catalogue stuff
82
 
                self.__updating = True # whether we're loading the catalog right now
83
 
                self.__has_loaded = False # whether the catalog has been loaded yet
84
 
                self.__update_id = 0 # gobject.idle_add id for catalog updates
85
 
                self.__catalogue_loader = None
86
 
                self.__catalogue_check = None
87
 
                self.__load_progress = (0, 0) # (complete, total)
88
 
 
89
 
                # album download stuff
90
 
                self.__downloads = {} # keeps track of download progress for each file
91
 
                self.__cancellables = {} # keeps track of gio.Cancellable objects so we can abort album downloads
92
 
 
93
 
 
94
 
        def do_set_property(self, property, value):
95
 
                if property.name == 'plugin':
96
 
                        self.__plugin = value
97
 
                else:
98
 
                        raise AttributeError, 'unknown property %s' % property.name
99
 
 
100
 
        #
101
 
        # RBSource methods
102
 
        #
103
 
 
104
 
        def do_impl_show_entry_popup(self):
105
 
                self.show_source_popup("/MagnatuneSourceViewPopup")
106
 
 
107
 
        def do_get_status(self, status, progress_text, progress):
108
 
                if self.__updating:
109
 
                        complete, total = self.__load_progress
110
 
                        if total > 0:
111
 
                                progress = min(float(complete) / total, 1.0)
112
 
                        else:
113
 
                                progress = -1.0
114
 
                        return (_("Loading Magnatune catalog"), None, progress)
115
 
                elif len(self.__downloads) > 0:
116
 
                        complete, total = map(sum, zip(*self.__downloads.itervalues()))
117
 
                        if total > 0:
118
 
                                progress = min(float(complete) / total, 1.0)
119
 
                        else:
120
 
                                progress = -1.0
121
 
                        return (_("Downloading Magnatune Album(s)"), None, progress)
122
 
                else:
123
 
                        qm = self.get_property("query-model")
124
 
                        return (qm.compute_status_normal("%d song", "%d songs"), None, 2.0)
125
 
 
126
 
        def do_get_ui_actions(self):
127
 
                return ["MagnatuneDownloadAlbum",
128
 
                        "MagnatuneArtistInfo",
129
 
                        "MagnatuneCancelDownload"]
130
 
 
131
 
        def do_selected(self):
132
 
                if not self.__activated:
133
 
                        shell = self.get_property('shell')
134
 
                        self.__db = shell.get_property('db')
135
 
                        self.__entry_type = self.get_property('entry-type')
136
 
 
137
 
                        # move files from old ~/.gnome2 paths
138
 
                        if not magnatune_in_progress_dir.query_exists():
139
 
                                self.__move_data_files()
140
 
 
141
 
                        self.__activated = True
142
 
                        self.__show_loading_screen(True)
143
 
 
144
 
                        # start our catalogue updates
145
 
                        self.__update_id = gobject.timeout_add_seconds(6 * 60 * 60, self.__update_catalogue)
146
 
                        self.__update_catalogue()
147
 
 
148
 
                        self.get_entry_view().set_sorting_type(self.__client.get_string("/apps/rhythmbox/plugins/magnatune/sorting"))
149
 
 
150
 
        def do_impl_get_browser_key(self):
151
 
                return "/apps/rhythmbox/plugins/magnatune/show_browser"
152
 
 
153
 
        def do_impl_get_paned_key(self):
154
 
                return "/apps/rhythmbox/plugins/magnatune/paned_position"
155
 
 
156
 
        def do_impl_can_delete(self):
157
 
                return False
158
 
 
159
 
        def do_impl_pack_paned(self, paned):
160
 
                self.__paned_box = Gtk.VBox(homogeneous=False, spacing=5)
161
 
                self.pack_start(self.__paned_box, True, True, 0)
162
 
                self.__paned_box.pack_start(paned, True, True, 0)
163
 
 
164
 
 
165
 
        def do_delete_thyself(self):
166
 
                if self.__update_id != 0:
167
 
                        gobject.source_remove(self.__update_id)
168
 
                        self.__update_id = 0
169
 
 
170
 
                if self.__notify_id != 0:
171
 
                        gobject.source_remove(self.__notify_id)
172
 
                        self.__notify_id = 0
173
 
 
174
 
                if self.__catalogue_loader is not None:
175
 
                        self.__catalogue_loader.cancel()
176
 
                        self.__catalogue_loader = None
177
 
 
178
 
                if self.__catalogue_check is not None:
179
 
                        self.__catalogue_check.cancel()
180
 
                        self.__catalogue_check = None
181
 
 
182
 
                self.__client.set_string("/apps/rhythmbox/plugins/magnatune/sorting", self.get_entry_view().get_sorting_type())
183
 
 
184
 
                RB.BrowserSource.do_delete_thyself(self)
185
 
 
186
 
        #
187
 
        # methods for use by plugin and UI
188
 
        #
189
 
 
190
 
        def display_artist_info(self):
191
 
                screen = self.props.shell.props.window.get_screen()
192
 
                tracks = self.get_entry_view().get_selected_entries()
193
 
                urls = set([])
194
 
 
195
 
                for tr in tracks:
196
 
                        sku = self.__sku_dict[self.__db.entry_get_string(tr, RB.RhythmDBPropType.LOCATION)]
197
 
                        url = self.__home_dict[sku]
198
 
                        if url not in urls:
199
 
                                Gtk.show_uri(screen, url, Gdk.CURRENT_TIME)
200
 
                                urls.add(url)
201
 
 
202
 
        def purchase_redirect(self):
203
 
                screen = self.props.shell.props.window.get_screen()
204
 
                tracks = self.get_entry_view().get_selected_entries()
205
 
                urls = set([])
206
 
 
207
 
                for tr in tracks:
208
 
                        sku = self.__sku_dict[self.__db.entry_get_string(tr, RB.RhythmDBPropType.LOCATION)]
209
 
                        url = magnatune_buy_album_uri + urllib.urlencode({ 'sku': sku, 'ref': magnatune_partner_id })
210
 
                        if url not in urls:
211
 
                                Gtk.show_uri(screen, url, Gdk.CURRENT_TIME)
212
 
                                urls.add(url)
213
 
 
214
 
        def download_album(self):
215
 
                if self.__client.get_string(self.__plugin.gconf_keys['account_type']) != 'download':
216
 
                        # The user doesn't have a download account, so redirect them to the purchase page.
217
 
                        self.purchase_redirect()
218
 
                        return
219
 
 
220
 
                try:
221
 
                        # Just use the first library location
222
 
                        library_location = rb.get_gconf_string_list("/apps/rhythmbox/library_locations")[0];
223
 
                except IndexError, e:
224
 
                        RB.error_dialog(title = _("Couldn't purchase album"),
225
 
                                        message = _("You must have a library location set to purchase an album."))
226
 
                        return
227
 
 
228
 
                tracks = self.get_entry_view().get_selected_entries()
229
 
                skus = []
230
 
 
231
 
                for track in tracks:
232
 
                        sku = self.__sku_dict[self.__db.entry_get_string(track, RB.RhythmDBPropType.LOCATION)]
233
 
                        if sku in skus:
234
 
                                continue
235
 
                        skus.append(sku)
236
 
                        self.__auth_download(sku)
237
 
 
238
 
        #
239
 
        # internal catalogue downloading and loading
240
 
        #
241
 
 
242
 
        def __update_catalogue(self):
243
 
                def update_cb(result):
244
 
                        self.__catalogue_check = None
245
 
                        if result is True:
246
 
                                download_catalogue()
247
 
                        elif self.__has_loaded is False:
248
 
                                load_catalogue()
249
 
 
250
 
                def download_catalogue():
251
 
                        def find_song_info(catalogue):
252
 
                                for info in catalogue.infolist():
253
 
                                        if info.filename.endswith("song_info.xml"):
254
 
                                                return info.filename;
255
 
                                return None
256
 
 
257
 
                        def download_progress(complete, total):
258
 
                                self.__load_progress = (complete, total)
259
 
                                self.__notify_status_changed()
260
 
 
261
 
                        def download_finished(uri, result):
262
 
                                try:
263
 
                                        success = uri.copy_finish(result)
264
 
                                except:
265
 
                                        success = False
266
 
 
267
 
                                if not success:
268
 
                                        return
269
 
 
270
 
                                # done downloading, unzip to real location
271
 
                                catalog_zip = zipfile.ZipFile(magnatune_song_info_temp)
272
 
                                catalog = open(magnatune_song_info, 'w')
273
 
                                filename = find_song_info(catalog_zip)
274
 
                                if filename is None:
275
 
                                        RB.error_dialog(title=_("Unable to load catalog"),
276
 
                                                        message=_("Rhythmbox could not understand the Magnatune catalog, please file a bug."))
277
 
                                        return
278
 
                                catalog.write(catalog_zip.read(filename))
279
 
                                catalog.close()
280
 
                                catalog_zip.close()
281
 
 
282
 
                                dest.delete()
283
 
                                self.__updating = False
284
 
                                self.__catalogue_loader = None
285
 
                                self.__notify_status_changed()
286
 
 
287
 
                                load_catalogue()
288
 
 
289
 
 
290
 
                        self.__updating = True
291
 
 
292
 
                        dest = gio.File(magnatune_song_info_temp)
293
 
                        self.__catalogue_loader = gio.Cancellable()
294
 
                        try:
295
 
                                # For some reason, gio.FILE_COPY_OVERWRITE doesn't work for copy_async
296
 
                                dest.delete()
297
 
                        except:
298
 
                                pass
299
 
                        magnatune_song_info_uri.copy_async(dest,
300
 
                                                           download_finished,
301
 
                                                           progress_callback=download_progress,
302
 
                                                           flags=gio.FILE_COPY_OVERWRITE,
303
 
                                                           cancellable=self.__catalogue_loader)
304
 
 
305
 
                def load_catalogue():
306
 
                        def got_items(result, items):
307
 
                                account_type = self.__client.get_string(self.__plugin.gconf_keys['account_type'])
308
 
                                username = ""
309
 
                                password = ""
310
 
                                if account_type == 'none':
311
 
                                        pass
312
 
                                elif result is not None or len(items) == 0:
313
 
                                        RB.error_dialog(title = _("Couldn't get account details"),
314
 
                                                        message = str(result))
315
 
                                        return
316
 
                                else:
317
 
                                        try:
318
 
                                                username, password = items[0].secret.split('\n')
319
 
                                        except ValueError: # Couldn't parse secret, possibly because it's empty
320
 
                                                pass
321
 
                                parser = xml.sax.make_parser()
322
 
                                parser.setContentHandler(TrackListHandler(self.__db, self.__entry_type, self.__sku_dict, self.__home_dict, self.__art_dict, account_type, username, password))
323
 
 
324
 
                                self.__catalogue_loader = rb.ChunkLoader()
325
 
                                self.__catalogue_loader.get_url_chunks(magnatune_song_info, 64*1024, True, catalogue_chunk_cb, parser)
326
 
 
327
 
                        def catalogue_chunk_cb(result, total, parser):
328
 
                                if not result or isinstance(result, Exception):
329
 
                                        if result:
330
 
                                                # report error somehow?
331
 
                                                print "error loading catalogue: %s" % result
332
 
 
333
 
                                        try:
334
 
                                                parser.close()
335
 
                                        except xml.sax.SAXParseException, e:
336
 
                                                # there isn't much we can do here
337
 
                                                print "error parsing catalogue: %s" % e
338
 
 
339
 
                                        self.__show_loading_screen(False)
340
 
                                        self.__updating = False
341
 
                                        self.__catalogue_loader = None
342
 
 
343
 
                                        # restart in-progress downloads
344
 
                                        # (doesn't really belong here)
345
 
                                        for f in magnatune_in_progress_dir.enumerate_children('standard::name'):
346
 
                                                name = f.get_name()
347
 
                                                if not name.startswith("in_progress_"):
348
 
                                                        continue
349
 
                                                uri = magnatune_in_progress_dir.resolve_relative_path(name).load_contents()[0]
350
 
                                                print "restarting download from %s" % uri
351
 
                                                self.__download_album(gio.File(uri=uri), name[12:])
352
 
                                else:
353
 
                                        # hack around some weird chars that show up in the catalogue for some reason
354
 
                                        result = result.replace("\x19", "'")
355
 
                                        result = result.replace("\x13", "-")
356
 
 
357
 
                                        # argh.
358
 
                                        result = result.replace("Rock & Roll", "Rock &amp; Roll")
359
 
 
360
 
                                        try:
361
 
                                                parser.feed(result)
362
 
                                        except xml.sax.SAXParseException, e:
363
 
                                                print "error parsing catalogue: %s" % e
364
 
 
365
 
                                        load_size['size'] += len(result)
366
 
                                        self.__load_progress = (load_size['size'], total)
367
 
 
368
 
                                self.__notify_status_changed()
369
 
 
370
 
 
371
 
                        self.__has_loaded = True
372
 
                        self.__updating = True
373
 
                        self.__load_progress = (0, 0) # (complete, total)
374
 
                        self.__notify_status_changed()
375
 
 
376
 
                        load_size = {'size': 0}
377
 
                        keyring.find_items(keyring.ITEM_GENERIC_SECRET, {'rhythmbox-plugin': 'magnatune'}, got_items)
378
 
 
379
 
 
380
 
                self.__catalogue_check = rb.UpdateCheck()
381
 
                self.__catalogue_check.check_for_update(magnatune_song_info, magnatune_song_info_uri.get_uri(), update_cb)
382
 
 
383
 
 
384
 
        def __show_loading_screen(self, show):
385
 
                if self.__info_screen is None:
386
 
                        # load the builder stuff
387
 
                        builder = Gtk.Builder()
388
 
                        builder.add_from_file(self.__plugin.find_file("magnatune-loading.ui"))
389
 
                        self.__info_screen = builder.get_object("magnatune_loading_scrolledwindow")
390
 
                        self.pack_start(self.__info_screen, True, True, 0)
391
 
                        self.get_entry_view().set_no_show_all(True)
392
 
                        self.__info_screen.set_no_show_all(True)
393
 
 
394
 
                self.__info_screen.set_property("visible", show)
395
 
                self.__paned_box.set_property("visible", not show)
396
 
 
397
 
        def __notify_status_changed(self):
398
 
                def change_idle_cb():
399
 
                        self.notify_status_changed()
400
 
                        self.__notify_id = 0
401
 
                        return False
402
 
 
403
 
                if self.__notify_id == 0:
404
 
                        self.__notify_id = gobject.idle_add(change_idle_cb)
405
 
 
406
 
        #
407
 
        # internal purchasing code
408
 
        #
409
 
 
410
 
        def __auth_download(self, sku): # http://magnatune.com/info/api
411
 
                def got_items(result, items):
412
 
                        if result is not None or len(items) == 0:
413
 
                                RB.error_dialog(title = _("Couldn't get account details"),
414
 
                                                message = str(result))
415
 
                                return
416
 
 
417
 
                        try:
418
 
                                username, password = items[0].secret.split('\n')
419
 
                        except ValueError: # Couldn't parse secret, possibly because it's empty
420
 
                                username = ""
421
 
                                password = ""
422
 
                        print "downloading album: " + sku
423
 
                        url_dict = {
424
 
                                'id':   magnatune_partner_id,
425
 
                                'sku':  sku
426
 
                        }
427
 
                        url = magnatune_api_download_uri % (username, password)
428
 
                        url = url + urllib.urlencode(url_dict)
429
 
 
430
 
                        l = rb.Loader()
431
 
                        l.get_url(url, auth_data_cb, (username, password))
432
 
 
433
 
                def auth_data_cb(data, (username, password)):
434
 
                        buy_album_handler = BuyAlbumHandler(self.__client.get_string(self.__plugin.gconf_keys['format']))
435
 
                        auth_parser = xml.sax.make_parser()
436
 
                        auth_parser.setContentHandler(buy_album_handler)
437
 
 
438
 
                        if data is None:
439
 
                                # hmm.
440
 
                                return
441
 
 
442
 
                        try:
443
 
                                data = data.replace("<br>", "") # get rid of any stray <br> tags that will mess up the parser
444
 
                                # print data
445
 
                                auth_parser.feed(data)
446
 
                                auth_parser.close()
447
 
 
448
 
                                # process the URI: add authentication info, quote the filename component for some reason
449
 
                                parsed = urlparse.urlparse(buy_album_handler.url)
450
 
                                netloc = "%s:%s@%s" % (username, password, parsed.hostname)
451
 
 
452
 
                                spath = os.path.split(urllib.url2pathname(parsed.path))
453
 
                                basename = spath[1]
454
 
                                path = urllib.pathname2url(os.path.join(spath[0], urllib.quote(basename)))
455
 
 
456
 
                                authed = (parsed[0], netloc, path) + parsed[3:]
457
 
                                audio_dl_uri = urlparse.urlunparse(authed)
458
 
 
459
 
                                self.__download_album(gio.File(audio_dl_uri), sku)
460
 
 
461
 
                        except MagnatunePurchaseError, e:
462
 
                                RB.error_dialog(title = _("Download Error"),
463
 
                                                message = _("An error occurred while trying to authorize the download.\nThe Magnatune server returned:\n%s") % str(e))
464
 
                        except Exception, e:
465
 
                                RB.error_dialog(title = _("Error"),
466
 
                                                message = _("An error occurred while trying to download the album.\nThe error text is:\n%s") % str(e))
467
 
 
468
 
 
469
 
                keyring.find_items(keyring.ITEM_GENERIC_SECRET, {'rhythmbox-plugin': 'magnatune'}, got_items)
470
 
 
471
 
        def __download_album(self, audio_dl_uri, sku):
472
 
                def download_progress(current, total):
473
 
                        self.__downloads[str_uri] = (current, total)
474
 
                        self.__notify_status_changed()
475
 
 
476
 
                def download_finished(uri, result):
477
 
                        del self.__cancellables[str_uri]
478
 
                        del self.__downloads[str_uri]
479
 
 
480
 
                        try:
481
 
                                success = uri.copy_finish(result)
482
 
                        except Exception, e:
483
 
                                success = False
484
 
                                print "Download not completed: " + str(e)
485
 
 
486
 
                        if success:
487
 
                                threading.Thread(target=unzip_album).start()
488
 
                        else:
489
 
                                remove_download_files()
490
 
 
491
 
                        if len(self.__downloads) == 0: # All downloads are complete
492
 
                                shell = self.get_property('shell')
493
 
                                manager = shell.get_player().get_property('ui-manager')
494
 
                                manager.get_action("/MagnatuneSourceViewPopup/MagnatuneCancelDownload").set_sensitive(False)
495
 
                                if success:
496
 
                                        shell.notify_custom(4000, _("Finished Downloading"), _("All Magnatune downloads have been completed."))
497
 
 
498
 
                        self.__notify_status_changed()
499
 
 
500
 
                def unzip_album():
501
 
                        # just use the first library location
502
 
                        library_location = gio.File(uri=rb.get_gconf_string_list("/apps/rhythmbox/library_locations")[0]);
503
 
 
504
 
                        album = zipfile.ZipFile(dest.get_path())
505
 
                        for track in album.namelist():
506
 
                                track_uri = library_location.resolve_relative_path(track).get_uri()
507
 
 
508
 
                                track_uri = RB.sanitize_uri_for_filesystem(track_uri)
509
 
                                RB.uri_create_parent_dirs(track_uri)
510
 
 
511
 
                                track_out = gio.File(uri=track_uri).create()
512
 
                                if track_out is not None:
513
 
                                        track_out.write(album.read(track))
514
 
                                        track_out.close()
515
 
                                        self.__db.add_uri(track_uri)
516
 
 
517
 
                        album.close()
518
 
                        remove_download_files()
519
 
 
520
 
                def remove_download_files():
521
 
                        in_progress.delete()
522
 
                        dest.delete()
523
 
 
524
 
 
525
 
                in_progress = magnatune_in_progress_dir.resolve_relative_path("in_progress_" + sku)
526
 
                dest = magnatune_in_progress_dir.resolve_relative_path(sku)
527
 
 
528
 
                str_uri = audio_dl_uri.get_uri()
529
 
                in_progress.replace_contents(str_uri, None, False, flags=gio.FILE_CREATE_PRIVATE|gio.FILE_CREATE_REPLACE_DESTINATION)
530
 
 
531
 
                shell = self.get_property('shell')
532
 
                manager = shell.get_player().get_property('ui-manager')
533
 
                manager.get_action("/MagnatuneSourceViewPopup/MagnatuneCancelDownload").set_sensitive(True)
534
 
 
535
 
                self.__downloads[str_uri] = (0, 0) # (current, total)
536
 
 
537
 
                cancel = gio.Cancellable()
538
 
                self.__cancellables[str_uri] = cancel
539
 
                try:
540
 
                        # For some reason, gio.FILE_COPY_OVERWRITE doesn't work for copy_async
541
 
                        dest.delete()
542
 
                except:
543
 
                        pass
544
 
 
545
 
                # no way to resume downloads, sadly
546
 
                audio_dl_uri.copy_async(dest,
547
 
                                        download_finished,
548
 
                                        progress_callback=download_progress,
549
 
                                        flags=gio.FILE_COPY_OVERWRITE,
550
 
                                        cancellable=cancel)
551
 
 
552
 
 
553
 
        def cancel_downloads(self):
554
 
                for cancel in self.__cancellables.values():
555
 
                        cancel.cancel()
556
 
 
557
 
                shell = self.get_property('shell')
558
 
                manager = shell.get_player().get_property('ui-manager')
559
 
                manager.get_action("/MagnatuneSourceViewPopup/MagnatuneCancelDownload").set_sensitive(False)
560
 
 
561
 
        def playing_entry_changed(self, entry):
562
 
                if not self.__db or not entry:
563
 
                        return
564
 
                if entry.get_entry_type() != self.__db.entry_type_get_by_name("MagnatuneEntryType"):
565
 
                        return
566
 
 
567
 
                gobject.idle_add(self.emit_cover_art_uri, entry)
568
 
 
569
 
        def emit_cover_art_uri(self, entry):
570
 
                sku = self.__sku_dict[self.__db.entry_get_string(entry, RB.RhythmDBPropType.LOCATION)]
571
 
                url = self.__art_dict[sku]
572
 
                self.__db.emit_entry_extra_metadata_notify(entry, 'rb:coverArt-uri', url)
573
 
                return False
574
 
 
575
 
        def __move_data_files(self):
576
 
                # create cache and data directories
577
 
                magnatune_in_progress_path = magnatune_in_progress_dir.get_path()
578
 
                magnatune_cache_path = magnatune_cache_dir.get_path()
579
 
 
580
 
                # (we know they don't already exist, and we know the parent dirs do)
581
 
                os.mkdir(magnatune_in_progress_path, 0700)
582
 
                if os.path.exists(magnatune_cache_path) is False:
583
 
                        os.mkdir(magnatune_cache_path, 0700)
584
 
 
585
 
                # move song info to cache dir
586
 
                old_magnatune_dir = os.path.join(RB.dot_dir(), 'magnatune')
587
 
                if os.path.exists(old_magnatune_dir) is False:
588
 
                        print "old magnatune directory does not exist"
589
 
                        return
590
 
 
591
 
                old_song_info = os.path.join(old_magnatune_dir, 'song_info.xml')
592
 
                if os.path.exists(old_song_info):
593
 
                        print "moving existing song_info.xml to cache dir"
594
 
                        os.rename(old_song_info, magnatune_song_info)
595
 
                else:
596
 
                        print "no song_info.xml found (%s)" % old_song_info
597
 
 
598
 
                # move in progress downloads to data dir
599
 
                otherfiles = os.listdir(old_magnatune_dir)
600
 
                for f in otherfiles:
601
 
                        print "moving file %s to new in-progress dir" % f
602
 
                        os.rename(os.path.join(old_magnatune_dir, f),
603
 
                                  os.path.join(magnatune_in_progress_path, f))
604
 
 
605
 
 
606
 
gobject.type_register(MagnatuneSource)