First cut of download queue support
git-svn-id: svn://svn.berlios.de/gpodder/trunk@316 b0d088ad-0a06-0410-aad2-9ed5178a7e87
This commit is contained in:
parent
5197cbccfb
commit
b1078b4f9e
8 changed files with 156 additions and 17 deletions
11
ChangeLog
11
ChangeLog
|
@ -1,3 +1,14 @@
|
|||
Tue, 1 May 2007 21:58:58 +0200 <thp@perli.net>
|
||||
* src/gpodder/libwget.py: Implement support for download queue using
|
||||
a semaphore in the downloadStatusManager class
|
||||
* src/gpodder/libgpodder.py: Configuration options "max_downloads"
|
||||
and "max_downloads_enabled" for the download queue
|
||||
* src/gpodder/gpodder.py: Add support for configuration of the
|
||||
download queue code (gPodderProperties dialog)
|
||||
* data/gpodder.glade: Add checkbox + spinbutton for download queue
|
||||
* TODO: Updated TODO list (download queue done)
|
||||
* bin/gpodder: Pushed version + release date
|
||||
|
||||
Sat, 28 Apr 2007 11:10:18 +0200 <thp@perli.net>
|
||||
* TODO: Updated TODO list
|
||||
|
||||
|
|
17
TODO
17
TODO
|
@ -15,20 +15,9 @@
|
|||
* Clean up the "Downloads" tab in the preferences dialog - too much cruft
|
||||
has accumulated over the last few months .. maybe move bittorrent stuff
|
||||
to a seperate tab or group it different? --thp
|
||||
|
||||
* Would it be possible to add some form of bandwidth throttling? I've just
|
||||
started using gpodder and added all my feeds. It immediately marked all
|
||||
my new episodes and went to download them all at the same time making my
|
||||
(relatively slow) connection unusuable.
|
||||
|
||||
Would it therefore be possible to add some throttling options, such as,
|
||||
limit number of concurrent downloads to 'x' and limit maximum bandwidth
|
||||
to 'y'? The latter could be implemented by passing the relevant parameter
|
||||
to wget, the former would probably require some form of download queue.
|
||||
|
||||
--> partially done (limit rate to x kb/s per episode)
|
||||
|
||||
(suggested by Paul Elliott <omahns.home gmail.com>)
|
||||
|
||||
* Improvements for download queue:
|
||||
-> get rid of mandatory restarting for semaphore (x simultaneous downloads)
|
||||
|
||||
* I think it would be nice if gPodder had a color indicator (like it
|
||||
already has for downloaded/deleted episodes) for podcasts that haven't
|
||||
|
|
|
@ -32,8 +32,8 @@ or played back on the user's desktop.
|
|||
# PLEASE DO NOT CHANGE FORMAT OF __version__ LINE (setup.py reads this)
|
||||
|
||||
__author__ = "Thomas Perl <thp@perli.net>"
|
||||
__version__ = "0.9.1+svn20070421"
|
||||
__date__ = "2007-04-21"
|
||||
__version__ = "0.9.1+svn20070501"
|
||||
__date__ = "2007-05-01"
|
||||
__copyright__ = "Copyright (c) 2005-2007 %s. All rights reserved." % __author__
|
||||
__licence__ = "GPL"
|
||||
|
||||
|
|
|
@ -2690,7 +2690,7 @@ you can use the usual format of the environment variables:
|
|||
<widget class="GtkTable" id="tableDownloadsProperties">
|
||||
<property name="border_width">10</property>
|
||||
<property name="visible">True</property>
|
||||
<property name="n_rows">7</property>
|
||||
<property name="n_rows">9</property>
|
||||
<property name="n_columns">3</property>
|
||||
<property name="homogeneous">False</property>
|
||||
<property name="row_spacing">5</property>
|
||||
|
@ -2996,6 +2996,106 @@ you can use the usual format of the environment variables:
|
|||
<property name="x_options">fill</property>
|
||||
</packing>
|
||||
</child>
|
||||
|
||||
<child>
|
||||
<widget class="GtkCheckButton" id="cbMaxDownloads">
|
||||
<property name="visible">True</property>
|
||||
<property name="can_focus">True</property>
|
||||
<property name="label" translatable="yes">Enable download queue:</property>
|
||||
<property name="use_underline">True</property>
|
||||
<property name="relief">GTK_RELIEF_NORMAL</property>
|
||||
<property name="focus_on_click">True</property>
|
||||
<property name="active">False</property>
|
||||
<property name="inconsistent">False</property>
|
||||
<property name="draw_indicator">True</property>
|
||||
<signal name="toggled" handler="on_cbMaxDownloads_toggled" last_modification_time="Tue, 01 May 2007 19:39:03 GMT"/>
|
||||
</widget>
|
||||
<packing>
|
||||
<property name="left_attach">0</property>
|
||||
<property name="right_attach">1</property>
|
||||
<property name="top_attach">7</property>
|
||||
<property name="bottom_attach">8</property>
|
||||
<property name="x_options">fill</property>
|
||||
<property name="y_options"></property>
|
||||
</packing>
|
||||
</child>
|
||||
|
||||
<child>
|
||||
<widget class="GtkSpinButton" id="spinMaxDownloads">
|
||||
<property name="visible">True</property>
|
||||
<property name="sensitive">False</property>
|
||||
<property name="can_focus">True</property>
|
||||
<property name="climb_rate">1</property>
|
||||
<property name="digits">0</property>
|
||||
<property name="numeric">False</property>
|
||||
<property name="update_policy">GTK_UPDATE_ALWAYS</property>
|
||||
<property name="snap_to_ticks">False</property>
|
||||
<property name="wrap">False</property>
|
||||
<property name="adjustment">3 1 10 1 10 10</property>
|
||||
</widget>
|
||||
<packing>
|
||||
<property name="left_attach">1</property>
|
||||
<property name="right_attach">2</property>
|
||||
<property name="top_attach">7</property>
|
||||
<property name="bottom_attach">8</property>
|
||||
<property name="y_options"></property>
|
||||
</packing>
|
||||
</child>
|
||||
|
||||
<child>
|
||||
<widget class="GtkLabel" id="label67">
|
||||
<property name="visible">True</property>
|
||||
<property name="label" translatable="yes">simultaneous downloads</property>
|
||||
<property name="use_underline">False</property>
|
||||
<property name="use_markup">False</property>
|
||||
<property name="justify">GTK_JUSTIFY_LEFT</property>
|
||||
<property name="wrap">False</property>
|
||||
<property name="selectable">False</property>
|
||||
<property name="xalign">0</property>
|
||||
<property name="yalign">0.5</property>
|
||||
<property name="xpad">0</property>
|
||||
<property name="ypad">0</property>
|
||||
<property name="ellipsize">PANGO_ELLIPSIZE_NONE</property>
|
||||
<property name="width_chars">-1</property>
|
||||
<property name="single_line_mode">False</property>
|
||||
<property name="angle">0</property>
|
||||
</widget>
|
||||
<packing>
|
||||
<property name="left_attach">2</property>
|
||||
<property name="right_attach">3</property>
|
||||
<property name="top_attach">7</property>
|
||||
<property name="bottom_attach">8</property>
|
||||
<property name="x_options">fill</property>
|
||||
<property name="y_options"></property>
|
||||
</packing>
|
||||
</child>
|
||||
|
||||
<child>
|
||||
<widget class="GtkLabel" id="label68">
|
||||
<property name="visible">True</property>
|
||||
<property name="label" translatable="yes"><small><b>Please note</b>: Changes for the download queue settings only take effect after gPodder has been restarted.</small></property>
|
||||
<property name="use_underline">False</property>
|
||||
<property name="use_markup">True</property>
|
||||
<property name="justify">GTK_JUSTIFY_LEFT</property>
|
||||
<property name="wrap">True</property>
|
||||
<property name="selectable">False</property>
|
||||
<property name="xalign">0</property>
|
||||
<property name="yalign">0.5</property>
|
||||
<property name="xpad">0</property>
|
||||
<property name="ypad">0</property>
|
||||
<property name="ellipsize">PANGO_ELLIPSIZE_NONE</property>
|
||||
<property name="width_chars">-1</property>
|
||||
<property name="single_line_mode">False</property>
|
||||
<property name="angle">0</property>
|
||||
</widget>
|
||||
<packing>
|
||||
<property name="left_attach">0</property>
|
||||
<property name="right_attach">3</property>
|
||||
<property name="top_attach">8</property>
|
||||
<property name="bottom_attach">9</property>
|
||||
<property name="y_options"></property>
|
||||
</packing>
|
||||
</child>
|
||||
</widget>
|
||||
<packing>
|
||||
<property name="tab_expand">False</property>
|
||||
|
|
|
@ -1173,6 +1173,8 @@ class Gpodderproperties(SimpleGladeApp):
|
|||
self.downloadnew.set_active(gl.download_after_update)
|
||||
self.cbLimitDownloads.set_active(gl.limit_rate)
|
||||
self.spinLimitDownloads.set_value(gl.limit_rate_value)
|
||||
self.cbMaxDownloads.set_active(gl.max_downloads_enabled)
|
||||
self.spinMaxDownloads.set_value(gl.max_downloads)
|
||||
self.showplayed.set_active(gl.show_played)
|
||||
self.only_sync_not_played.set_active(gl.only_sync_not_played)
|
||||
if tagging_supported():
|
||||
|
@ -1326,6 +1328,11 @@ class Gpodderproperties(SimpleGladeApp):
|
|||
self.spinLimitDownloads.set_sensitive( self.cbLimitDownloads.get_active())
|
||||
#-- Gpodderproperties.on_cbLimitDownloads_toggled }
|
||||
|
||||
#-- Gpodderproperties.on_cbMaxDownloads_toggled {
|
||||
def on_cbMaxDownloads_toggled(self, widget, *args):
|
||||
self.spinMaxDownloads.set_sensitive( self.cbMaxDownloads.get_active())
|
||||
#-- Gpodderproperties.on_cbMaxDownloads_toggled }
|
||||
|
||||
#-- Gpodderproperties.on_btnOK_clicked {
|
||||
def on_btnOK_clicked(self, widget, *args):
|
||||
gl = gPodderLib()
|
||||
|
@ -1389,6 +1396,8 @@ class Gpodderproperties(SimpleGladeApp):
|
|||
gl.download_after_update = self.downloadnew.get_active()
|
||||
gl.limit_rate = self.cbLimitDownloads.get_active()
|
||||
gl.limit_rate_value = self.spinLimitDownloads.get_value()
|
||||
gl.max_downloads_enabled = self.cbMaxDownloads.get_active()
|
||||
gl.max_downloads = int(self.spinMaxDownloads.get_value())
|
||||
gl.show_played = self.showplayed.get_active()
|
||||
gl.update_tags = self.updatetags.get_active()
|
||||
gl.only_sync_not_played = self.only_sync_not_played.get_active()
|
||||
|
|
|
@ -276,6 +276,11 @@ class Gpodderproperties(SimpleGladeApp):
|
|||
print "on_cbLimitDownloads_toggled called with self.%s" % widget.get_name()
|
||||
#-- Gpodderproperties.on_cbLimitDownloads_toggled }
|
||||
|
||||
#-- Gpodderproperties.on_cbMaxDownloads_toggled {
|
||||
def on_cbMaxDownloads_toggled(self, widget, *args):
|
||||
print "on_cbMaxDownloads_toggled called with self.%s" % widget.get_name()
|
||||
#-- Gpodderproperties.on_cbMaxDownloads_toggled }
|
||||
|
||||
#-- Gpodderproperties.on_btnOK_clicked {
|
||||
def on_btnOK_clicked(self, widget, *args):
|
||||
print "on_btnOK_clicked called with self.%s" % widget.get_name()
|
||||
|
|
|
@ -137,6 +137,8 @@ class gPodderLibClass( object):
|
|||
self.main_window_height = 450
|
||||
self.main_window_x = 0
|
||||
self.main_window_y = 0
|
||||
self.max_downloads = 3
|
||||
self.max_downloads_enabled = False
|
||||
self.mp3_player_folder = ""
|
||||
self.only_sync_not_played = False
|
||||
self.__download_history = DownloadHistory( self.get_download_history_filename())
|
||||
|
@ -214,6 +216,8 @@ class gPodderLibClass( object):
|
|||
self.write_to_parser( parser, 'use_gnome_bittorrent', self.use_gnome_bittorrent)
|
||||
self.write_to_parser( parser, 'device_type', self.device_type)
|
||||
self.write_to_parser( parser, 'main_window_width', self.main_window_width)
|
||||
self.write_to_parser( parser, 'max_downloads', self.max_downloads)
|
||||
self.write_to_parser( parser, 'max_downloads_enabled', self.max_downloads_enabled)
|
||||
self.write_to_parser( parser, 'main_window_height', self.main_window_height)
|
||||
self.write_to_parser( parser, 'main_window_x', self.main_window_x)
|
||||
self.write_to_parser( parser, 'main_window_y', self.main_window_y)
|
||||
|
@ -357,6 +361,8 @@ class gPodderLibClass( object):
|
|||
self.main_window_height = self.get_int_from_parser( parser, 'main_window_height', 450)
|
||||
self.main_window_x = self.get_int_from_parser( parser, 'main_window_x', 0)
|
||||
self.main_window_y = self.get_int_from_parser( parser, 'main_window_y', 0)
|
||||
self.max_downloads = self.get_int_from_parser( parser, 'max_downloads', 3)
|
||||
self.max_downloads_enabled = self.get_boolean_from_parser(parser, 'max_downloads_enabled', default=False)
|
||||
self.mp3_player_folder = self.get_from_parser( parser, 'mp3_player_folder', '/media/usbdisk')
|
||||
self.only_sync_not_played = self.get_boolean_from_parser(parser, 'only_sync_not_played', default=False)
|
||||
else:
|
||||
|
|
|
@ -33,6 +33,7 @@ from os import system
|
|||
from os import kill
|
||||
from threading import Thread
|
||||
from threading import Lock
|
||||
from threading import Semaphore
|
||||
from shutil import move
|
||||
|
||||
from liblogger import log
|
||||
|
@ -84,6 +85,9 @@ class downloadThread( object):
|
|||
libgpodder.gPodderLib().deleteFilename( self.tempname)
|
||||
command = 'wget --timeout=120 --continue --tries=inf %s --output-document="%s" "%s"' % ( limit_str, self.tempname, self.url )
|
||||
log( 'Command: %s', command)
|
||||
if self.statusmgr:
|
||||
self.statusmgr.updateInfo( self.statusmgr_id, { 'episode':self.cutename, 'speed':_('Queued'), 'progress':0, 'url':self.url})
|
||||
self.statusmgr.s_acquire()
|
||||
process = popen2.Popen3( command, True)
|
||||
|
||||
self.pid = process.pid
|
||||
|
@ -148,6 +152,9 @@ class downloadThread( object):
|
|||
|
||||
if self.ready_event != None:
|
||||
self.ready_event.set()
|
||||
|
||||
if self.statusmgr:
|
||||
self.statusmgr.s_release()
|
||||
|
||||
def cancel( self):
|
||||
self.is_cancelled = True
|
||||
|
@ -165,6 +172,8 @@ class downloadStatusManager( object):
|
|||
self.next_status_id = 0 # Episode name Speed progress (100) url of download
|
||||
self.smlock = Lock()
|
||||
|
||||
self.semaphore = Semaphore( libgpodder.gPodderLib().max_downloads)
|
||||
|
||||
# use smlock around every tree_model usage, as seen here:
|
||||
self.smlock.acquire()
|
||||
self.tree_model = gtk.ListStore( gobject.TYPE_STRING, gobject.TYPE_STRING, gobject.TYPE_INT, gobject.TYPE_STRING)
|
||||
|
@ -175,6 +184,16 @@ class downloadStatusManager( object):
|
|||
self.change_notification = change_notification
|
||||
self.smlock.release()
|
||||
|
||||
def s_acquire( self, blocking = True):
|
||||
if not libgpodder.gPodderLib().max_downloads_enabled:
|
||||
# If we disabled the limit, don't block new downloads,
|
||||
# even if we still have a semaphore created
|
||||
blocking = False
|
||||
self.semaphore.acquire( blocking)
|
||||
|
||||
def s_release( self):
|
||||
self.semaphore.release()
|
||||
|
||||
def has_items( self):
|
||||
return bool( len( self.status_list))
|
||||
|
||||
|
|
Loading…
Reference in a new issue