gpodder/src/gpodder/services.py

199 lines
6.7 KiB
Python

# -*- coding: utf-8 -*-
#
# gPodder - A media aggregator and podcast client
# Copyright (C) 2005-2007 Thomas Perl <thp at perli.net>
#
# gPodder is free software; you can redistribute it and/or modify
# it under the terms of the GNU General Public License as published by
# the Free Software Foundation; either version 3 of the License, or
# (at your option) any later version.
#
# gPodder 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/>.
#
#
# services.py -- Core Services for gPodder
# Thomas Perl <thp@perli.net> 2007-08-24
#
#
from gpodder.liblogger import log
from gpodder import libgpodder
import gtk
import gobject
import threading
class DownloadStatusManager( object):
COLUMN_NAMES = { 0: 'episode', 1: 'speed', 2: 'progress', 3: 'url' }
COLUMN_TYPES = ( gobject.TYPE_STRING, gobject.TYPE_STRING, gobject.TYPE_INT, gobject.TYPE_STRING )
def __init__( self):
self.status_list = {}
self.next_status_id = 0
self.last_progress_status = ( 0, 0 )
self.max_downloads = libgpodder.gPodderLib().max_downloads
self.semaphore = threading.Semaphore( self.max_downloads)
self.tree_model = gtk.ListStore( *self.COLUMN_TYPES)
self.tree_model_lock = threading.Lock()
self.observers = { 'list-changed': [], 'progress-changed': [], 'progress-detail': [], }
def register( self, signal_name, observer):
if signal_name in self.observers:
if not observer in self.observers[signal_name]:
self.observers[signal_name].append( observer)
else:
log( 'Observer already added to signal "%s".', signal_name, sender = self)
else:
log( 'Signal "%s" is not available for registration.', signal_name, sender = self)
def unregister( self, signal_name, observer):
if signal_name in self.observers:
if observer in self.observers[signal_name]:
self.observers[signal_name].remove( observer)
else:
log( 'Observer could not be removed from signal "%s".', signal_name, sender = self)
else:
log( 'Signal "%s" is not available for un-registration.', signal_name, sender = self)
def notify( self, signal_name, *args):
if signal_name in self.observers:
for observer in self.observers[signal_name]:
gobject.idle_add( observer, *args)
else:
log( 'Signal "%s" is not available for notification.', signal_name, sender = self)
def notify_progress( self):
now = ( self.count(), self.average_progress() )
if now != self.last_progress_status:
self.notify( 'progress-changed', *now)
self.last_progress_status = now
def s_acquire( self):
if not libgpodder.gPodderLib().max_downloads_enabled:
return False
# Release queue slots if user has enabled more slots
while self.max_downloads < libgpodder.gPodderLib().max_downloads:
self.semaphore.release()
self.max_downloads += 1
# Acquire queue slots if user has decreased the slots
while self.max_downloads > libgpodder.gPodderLib().max_downloads:
self.semaphore.acquire()
self.max_downloads -= 1
return self.semaphore.acquire()
def s_release( self):
self.semaphore.release()
def reserve_download_id( self):
id = self.next_status_id
self.next_status_id = id + 1
return id
def remove_iter( self, iter):
self.tree_model.remove( iter)
return False
def register_download_id( self, id, thread):
self.tree_model_lock.acquire()
self.status_list[id] = { 'iter': self.tree_model.append(), 'thread': thread, 'progress': 0 }
self.notify( 'list-changed')
self.tree_model_lock.release()
def remove_download_id( self, id):
if not id in self.status_list:
return
iter = self.status_list[id]['iter']
if iter != None:
self.tree_model_lock.acquire()
gobject.idle_add( self.remove_iter, iter)
self.tree_model_lock.release()
self.status_list[id]['iter'] = None
self.status_list[id]['thread'].cancel()
del self.status_list[id]
self.notify( 'list-changed')
self.notify_progress()
def count( self):
return len(self.status_list)
def has_items( self):
return self.count() > 0
def average_progress( self):
if not len(self.status_list):
return 0
return sum( [ status['progress'] for status in self.status_list.values() ]) / len( self.status_list)
def update_status( self, id, **kwargs):
if not id in self.status_list:
return
iter = self.status_list[id]['iter']
if iter:
self.tree_model_lock.acquire()
for ( column, key ) in self.COLUMN_NAMES.items():
if key in kwargs:
gobject.idle_add( self.tree_model.set, iter, column, kwargs[key])
self.status_list[id][key] = kwargs[key]
self.tree_model_lock.release()
if 'progress' in kwargs and 'speed' in kwargs and 'url' in self.status_list[id]:
self.notify( 'progress-detail', self.status_list[id]['url'], kwargs['progress'], kwargs['speed'])
self.notify_progress()
def request_progress_detail( self, url):
for status in self.status_list.values():
if 'url' in status and status['url'] == url and 'progress' in status and 'speed' in status:
self.notify( 'progress-detail', url, status['progress'], status['speed'])
def is_download_in_progress( self, url):
for element in self.status_list:
thread = self.status_list[element]['thread']
if thread != None and thread.url == url:
return True
return False
def cancel_all( self):
for element in self.status_list:
self.status_list[element]['iter'] = None
self.status_list[element]['thread'].cancel()
# clear the tree model after cancelling
gobject.idle_add( self.tree_model.clear)
def cancel_by_url( self, url):
for element in self.status_list:
thread = self.status_list[element]['thread']
if thread != None and thread.url == url:
self.remove_download_id( element)
return True
return False
download_status_manager = DownloadStatusManager()