[rhythmbox] magnatune: Use gio.File.copy_async to download albums
- From: Adam Zimmerman <adamz src gnome org>
- To: commits-list gnome org
- Cc:
- Subject: [rhythmbox] magnatune: Use gio.File.copy_async to download albums
- Date: Fri, 19 Feb 2010 21:06:27 +0000 (UTC)
commit ea4db9cae4dde96c83b873a16292c1f7d223897c
Author: Adam Zimmerman <adamz src gnome org>
Date: Fri Feb 19 01:05:46 2010 -0800
magnatune: Use gio.File.copy_async to download albums
This has several benefits:
- uses separate callbacks for progress and completion (code clarity)
- makes the transfer completely async, instead of using python's blocking
file.write() calls
- lets us move towards using gio for all I/O, rather than a mix of gio
and python calls (still more todo here)
plugins/magnatune/magnatune/MagnatuneSource.py | 111 +++++++++++++----------
1 files changed, 63 insertions(+), 48 deletions(-)
---
diff --git a/plugins/magnatune/magnatune/MagnatuneSource.py b/plugins/magnatune/magnatune/MagnatuneSource.py
index bb081c0..473ddf0 100644
--- a/plugins/magnatune/magnatune/MagnatuneSource.py
+++ b/plugins/magnatune/magnatune/MagnatuneSource.py
@@ -48,11 +48,11 @@ magnatune_song_info_uri = "http://magnatune.com/info/song_info_xml.zip"
magnatune_buy_album_uri = "https://magnatune.com/buy/choose?"
magnatune_api_download_uri = "http://%s:%s download magnatune com/buy/membership_free_dl_xml?"
-magnatune_in_progress_dir = os.path.join(rb.user_data_dir(), 'magnatune')
-magnatune_cache_dir = os.path.join(rb.user_cache_dir(), 'magnatune')
+magnatune_in_progress_dir = gio.File(path=rb.user_data_dir()).resolve_relative_path('magnatune')
+magnatune_cache_dir = gio.File(path=rb.user_cache_dir()).resolve_relative_path('magnatune')
-magnatune_song_info = os.path.join(magnatune_cache_dir, 'song_info.xml')
-magnatune_song_info_temp = os.path.join(magnatune_cache_dir, 'song_info.zip.tmp')
+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):
@@ -89,6 +89,8 @@ class MagnatuneSource(rb.BrowserSource):
self.__download_progress = 0.0 # progress of current download(s)
self.purchase_filesize = 0 # total amount of bytes to download
+ self.__cancellables = {} # keeps track of gio.Cancellable objects so we can abort album downloads
+
def do_set_property(self, property, value):
if property.name == 'plugin':
@@ -130,7 +132,7 @@ class MagnatuneSource(rb.BrowserSource):
self.__entry_type = self.get_property('entry-type')
# move files from old ~/.gnome2 paths
- if os.path.exists(magnatune_in_progress_dir) is False:
+ if not magnatune_in_progress_dir.query_exists():
self.__move_data_files()
self.__activated = True
@@ -322,12 +324,13 @@ class MagnatuneSource(rb.BrowserSource):
# restart in-progress downloads
# (doesn't really belong here)
- inprogress = os.listdir(magnatune_in_progress_dir)
- inprogress = filter(lambda x: x.startswith("in_progress_"), inprogress)
- for ip in inprogress:
- for uri in open(os.path.join(magnatune_in_progress_dir, ip)).readlines():
- print "restarting download from %s" % uri
- self.__download_album(uri, ip[12:])
+ for f in magnatune_in_progress_dir.enumerate_children('standard::name'):
+ name = f.get_name()
+ if not name.startswith("in_progress_"):
+ continue
+ uri = magnatune_in_progress_dir.resolve_relative_path(name).load_contents()[0]
+ print "restarting download from %s" % uri
+ self.__download_album(gio.File(uri=uri), name[12:])
else:
# hack around some weird chars that show up in the catalogue for some reason
result = result.replace("\x19", "'")
@@ -379,6 +382,7 @@ class MagnatuneSource(rb.BrowserSource):
#
# internal purchasing code
#
+
def __auth_download(self, sku): # http://magnatune.com/info/api
def got_items(result, items):
if result is not None or len(items) == 0:
@@ -428,7 +432,7 @@ class MagnatuneSource(rb.BrowserSource):
authed = (parsed[0], netloc, path) + parsed[3:]
audio_dl_uri = urlparse.urlunparse(authed)
- self.__download_album(audio_dl_uri, sku)
+ self.__download_album(gio.File(audio_dl_uri), sku)
except MagnatunePurchaseError, e:
rb.error_dialog(title = _("Download Error"),
@@ -441,33 +445,30 @@ class MagnatuneSource(rb.BrowserSource):
keyring.find_items(keyring.ITEM_GENERIC_SECRET, {'rhythmbox-plugin': 'magnatune'}, got_items)
def __download_album(self, audio_dl_uri, sku):
- def download_album_chunk(result, total):
- if not result:
- download_finished(total, True)
- elif isinstance(result, Exception):
- # probably report this somehow?
- pass
- elif self.cancelled:
- download_finished(total, False)
- return False
- else:
- if self.__downloads[audio_dl_uri] == 0:
+ # dictionary used so we can update the values
+ download_info = {'size': 0}
+
+ def download_progress(current, total):
+ if self.__downloads[str_uri] == 0:
self.purchase_filesize += total
+ download_info['size'] = total
+ self.__downloads[str_uri] = current
- out.write(result)
- self.__downloads[audio_dl_uri] += len(result)
+ self.__download_progress = sum(self.__downloads.values()) / float(self.purchase_filesize)
+ self.__notify_status_changed()
- self.__download_progress = sum(self.__downloads.values()) / float(self.purchase_filesize)
- self.__notify_status_changed()
+ def download_finished(uri, result):
+ del self.__cancellables[str_uri]
- def download_finished(total, success):
try:
- del self.__downloads[audio_dl_uri]
- self.purchase_filesize -= total
- except:
- pass
+ success = uri.copy_finish(result)
+ except Exception, e:
+ success = False
+ print "Download not completed: " + str(e)
+
+ del self.__downloads[str_uri]
+ self.purchase_filesize -= download_info['size']
- out.close()
if success:
threading.Thread(target=unzip_album).start()
else:
@@ -483,11 +484,13 @@ class MagnatuneSource(rb.BrowserSource):
icon = rb.try_load_icon(gtk.icon_theme_get_default(), "magnatune", width, 0)
shell.notify_custom(4000, _("Finished Downloading"), _("All Magnatune downloads have been completed."), icon, True)
+ self.__notify_status_changed()
+
def unzip_album():
# just use the first library location
library_location = gio.File(uri=self.__client.get_list("/apps/rhythmbox/library_locations", gconf.VALUE_STRING)[0])
- album = zipfile.ZipFile(dest)
+ album = zipfile.ZipFile(dest.get_path())
for track in album.namelist():
track_uri = library_location.resolve_relative_path(track).get_uri()
@@ -504,34 +507,43 @@ class MagnatuneSource(rb.BrowserSource):
remove_download_files()
def remove_download_files():
- os.unlink(in_progress)
- os.unlink(dest)
+ in_progress.delete()
+ dest.delete()
- in_progress = os.path.join(magnatune_in_progress_dir, "in_progress_" + sku)
- dest = os.path.join(magnatune_in_progress_dir, sku)
+ in_progress = magnatune_in_progress_dir.resolve_relative_path("in_progress_" + sku)
+ dest = magnatune_in_progress_dir.resolve_relative_path(sku)
- ip = open(in_progress, 'w')
- ip.write(str(audio_dl_uri))
- ip.close()
+ str_uri = audio_dl_uri.get_uri()
+ in_progress.replace_contents(str_uri, None, False, flags=gio.FILE_CREATE_PRIVATE|gio.FILE_CREATE_REPLACE_DESTINATION)
shell = self.get_property('shell')
manager = shell.get_player().get_property('ui-manager')
manager.get_action("/MagnatuneSourceViewPopup/MagnatuneCancelDownload").set_sensitive(True)
self.__downloading = True
- self.cancelled = False
- self.__downloads[audio_dl_uri] = 0
+ self.__downloads[str_uri] = 0
- # no way to resume downloads, sadly
- out = open(dest, 'w')
+ cancel = gio.Cancellable()
+ self.__cancellables[str_uri] = cancel
+ try:
+ # For some reason, gio.FILE_COPY_OVERWRITE doesn't work for copy_async
+ dest.delete()
+ except:
+ pass
- dl = rb.ChunkLoader()
- dl.get_url_chunks(audio_dl_uri, 4*1024, True, download_album_chunk)
+ # no way to resume downloads, sadly
+ audio_dl_uri.copy_async(dest,
+ download_finished,
+ progress_callback=download_progress,
+ flags=gio.FILE_COPY_OVERWRITE,
+ cancellable=cancel)
def cancel_downloads(self):
- self.cancelled = True
+ for cancel in self.__cancellables.values():
+ cancel.cancel()
+
shell = self.get_property('shell')
manager = shell.get_player().get_property('ui-manager')
manager.get_action("/MagnatuneSourceViewPopup/MagnatuneCancelDownload").set_sensitive(False)
@@ -552,6 +564,9 @@ class MagnatuneSource(rb.BrowserSource):
def __move_data_files(self):
# create cache and data directories
+ magnatune_in_progress_dir = magnatune_in_progress_dir.get_path()
+ magnatune_cache_dir = magnatune_cache_dir.get_path()
+
# (we know they don't already exist, and we know the parent dirs do)
os.mkdir(magnatune_in_progress_dir, 0700)
if os.path.exists(magnatune_cache_dir) is False:
[
Date Prev][
Date Next] [
Thread Prev][
Thread Next]
[
Thread Index]
[
Date Index]
[
Author Index]