New Configuration/Settings Manager; massive code clean-ups
git-svn-id: svn://svn.berlios.de/gpodder/trunk@447 b0d088ad-0a06-0410-aad2-9ed5178a7e87
This commit is contained in:
parent
b89489e961
commit
ac149c7b7a
26
ChangeLog
26
ChangeLog
|
@ -1,3 +1,29 @@
|
|||
Fri, 02 Nov 2007 17:28:05 +0100 <thp@perli.net>
|
||||
New Configuration/Settings Manager; massive code clean-ups
|
||||
|
||||
* src/gpodder/config.py: Added new Configuration Manager that
|
||||
automatically keeps track of saving changed values and is also able to
|
||||
watch GTK widgets for changes; this should simplify our settings
|
||||
management and give us a single place for maintaining settings
|
||||
* src/gpodder/download.py: Access settings from new config manager
|
||||
* src/gpodder/gui.py: Make use of new config manager to connect
|
||||
widgets and settings from the GUI directly to the config manager;
|
||||
remove manual loading and saving of settings; auto-connect as much as
|
||||
possible in the gPodderProperties dialog to get real-time automatic
|
||||
configuration saving; fix the other code to use new config manager
|
||||
* src/gpodder/libgpodder.py: MASSIVE code clean-up; removed lots of
|
||||
old cruft and dead code that has been lying around in libgpodder for
|
||||
some time now; remove configuration code; utilize config manager;
|
||||
unify DownloadHistory+PlaybackHistory in new HistoryStore class;
|
||||
reduce number of import statements
|
||||
* src/gpodder/libipodsync.py: Access settings from new config manager
|
||||
* src/gpodder/libplayers.py: Removed dotdesktop_command()
|
||||
* src/gpodder/libpodcasts.py: Move locking functionality into this
|
||||
module, as locking is only used here; access config from new manager
|
||||
* src/gpodder/services.py: Use config manager to get settings
|
||||
* src/gpodder/util.py: Add format_desktop_command() function, based on
|
||||
the dotdesktop_command() function from libplayers
|
||||
|
||||
Fri, 02 Nov 2007 07:49:38 +0100 <thp@perli.net>
|
||||
Add ability to open download folder from channel's context menu
|
||||
|
||||
|
|
|
@ -0,0 +1,224 @@
|
|||
# -*- 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/>.
|
||||
#
|
||||
|
||||
|
||||
#
|
||||
# config.py -- gPodder Configuration Manager
|
||||
# Thomas Perl <thp@perli.net> 2007-11-02
|
||||
#
|
||||
|
||||
|
||||
import gtk
|
||||
import gobject
|
||||
|
||||
from gpodder.liblogger import log
|
||||
|
||||
import atexit
|
||||
import os.path
|
||||
import time
|
||||
import threading
|
||||
import ConfigParser
|
||||
|
||||
gPodderSettings = {
|
||||
# General settings
|
||||
'player': ( str, 'xdg-open' ),
|
||||
'opml_url': ( str, 'http://gpodder.berlios.de/directory.opml' ),
|
||||
'http_proxy': ( str, '' ),
|
||||
'ftp_proxy': ( str, '' ),
|
||||
'custom_sync_name': ( str, '{episode.basename}' ),
|
||||
'custom_sync_name_enabled': ( bool, True ),
|
||||
'max_downloads': ( int, 3 ),
|
||||
'max_downloads_enabled': ( bool, False ),
|
||||
'limit_rate': ( bool, False ),
|
||||
'limit_rate_value': ( float, 500.0 ),
|
||||
'bittorrent_dir': ( str, os.path.expanduser( '~/gpodder-downloads/torrents') ),
|
||||
|
||||
# Boolean config flags
|
||||
'update_on_startup': ( bool, False ),
|
||||
'download_after_update': ( bool, False ),
|
||||
'use_gnome_bittorrent': ( bool, True ),
|
||||
'only_sync_not_played': ( bool, False ),
|
||||
'proxy_use_environment': ( bool, True ),
|
||||
'update_tags': ( bool, False ),
|
||||
|
||||
# Settings that are updated directly in code
|
||||
'ipod_mount': ( str, '/media/ipod' ),
|
||||
'mp3_player_folder': ( str, '/media/usbdisk' ),
|
||||
'device_type': ( str, 'none' ),
|
||||
'download_dir': ( str, os.path.expanduser( '~/gpodder-downloads') ),
|
||||
|
||||
# Special settings (not in preferences)
|
||||
'default_new': ( int, 1 ),
|
||||
|
||||
# Window and paned positions
|
||||
'main_window_x': ( int, 100 ),
|
||||
'main_window_y': ( int, 100 ),
|
||||
'main_window_width': ( int, 700 ),
|
||||
'main_window_height': ( int, 500 ),
|
||||
'paned_position': ( int, 200 ),
|
||||
}
|
||||
|
||||
class Config(dict):
|
||||
Settings = gPodderSettings
|
||||
|
||||
def __init__( self, filename = 'gpodder.conf'):
|
||||
dict.__init__( self)
|
||||
self.__save_thread = None
|
||||
self.__filename = filename
|
||||
self.__section = 'gpodder-conf-1'
|
||||
|
||||
atexit.register( self.__atexit)
|
||||
|
||||
self.load()
|
||||
|
||||
def __getattr__( self, name):
|
||||
if name in self.Settings:
|
||||
( fieldtype, default ) = self.Settings[name]
|
||||
return self[name]
|
||||
else:
|
||||
raise AttributeError
|
||||
|
||||
def connect_gtk_editable( self, name, editable):
|
||||
if name in self.Settings:
|
||||
editable.delete_text( 0, -1)
|
||||
editable.insert_text( str(getattr( self, name)))
|
||||
editable.connect( 'changed', lambda editable: setattr( self, name, editable.get_chars( 0, -1)))
|
||||
else:
|
||||
raise ValueError( '%s is not a setting' % name)
|
||||
|
||||
def connect_gtk_spinbutton( self, name, spinbutton):
|
||||
if name in self.Settings:
|
||||
spinbutton.set_value( getattr( self, name))
|
||||
spinbutton.connect( 'value-changed', lambda spinbutton: setattr( self, name, spinbutton.get_value()))
|
||||
else:
|
||||
raise ValueError( '%s is not a setting' % name)
|
||||
|
||||
def connect_gtk_paned( self, name, paned):
|
||||
if name in self.Settings:
|
||||
paned.set_position( getattr( self, name))
|
||||
paned_child = paned.get_child1()
|
||||
paned_child.connect( 'size-allocate', lambda x, y: setattr( self, name, paned.get_position()))
|
||||
else:
|
||||
raise ValueError( '%s is not a setting' % name)
|
||||
|
||||
def connect_gtk_togglebutton( self, name, togglebutton):
|
||||
if name in self.Settings:
|
||||
togglebutton.set_active( getattr( self, name))
|
||||
togglebutton.connect( 'toggled', lambda togglebutton: setattr( self, name, togglebutton.get_active()))
|
||||
else:
|
||||
raise ValueError( '%s is not a setting' % name)
|
||||
|
||||
def connect_gtk_filechooser( self, name, filechooser):
|
||||
if name in self.Settings:
|
||||
filechooser.set_filename( getattr( self, name))
|
||||
filechooser.connect( 'selection-changed', lambda filechooser: setattr( self, name, filechooser.get_filename()))
|
||||
else:
|
||||
raise ValueError( '%s is not a setting' % name)
|
||||
|
||||
def receive_configure_event( self, widget, event, config_prefix):
|
||||
( x, y, width, height ) = map( lambda x: config_prefix + '_' + x, [ 'x', 'y', 'width', 'height' ])
|
||||
( x_pos, y_pos ) = widget.get_position()
|
||||
( width_size, height_size ) = widget.get_size()
|
||||
setattr( self, x, x_pos)
|
||||
setattr( self, y, y_pos)
|
||||
setattr( self, width, width_size)
|
||||
setattr( self, height, height_size)
|
||||
|
||||
def connect_gtk_window( self, window, config_prefix = 'main_window'):
|
||||
( x, y, width, height ) = map( lambda x: config_prefix + '_' + x, [ 'x', 'y', 'width', 'height' ])
|
||||
if set( ( x, y, width, height )).issubset( set( self.Settings)):
|
||||
window.resize( getattr( self, width), getattr( self, height))
|
||||
window.move( getattr( self, x), getattr( self, y))
|
||||
window.connect( 'configure-event', self.receive_configure_event, config_prefix)
|
||||
else:
|
||||
raise ValueError( 'Missing settings in set: %s' % ', '.join( ( x, y, width, height )))
|
||||
|
||||
def schedule_save( self):
|
||||
if self.__save_thread == None:
|
||||
self.__save_thread = threading.Thread( target = self.save_thread_proc)
|
||||
self.__save_thread.start()
|
||||
|
||||
def save_thread_proc( self):
|
||||
for i in range( 100):
|
||||
if self.__save_thread != None:
|
||||
time.sleep( .1)
|
||||
if self.__save_thread != None:
|
||||
self.save()
|
||||
|
||||
def __atexit( self):
|
||||
if self.__save_thread != None:
|
||||
self.save()
|
||||
|
||||
def save( self, filename = None):
|
||||
if filename != None:
|
||||
self.__filename = filename
|
||||
|
||||
log( 'Flushing settings to disk', sender = self)
|
||||
|
||||
parser = ConfigParser.RawConfigParser()
|
||||
parser.add_section( self.__section)
|
||||
|
||||
for ( key, ( fieldtype, default ) ) in self.Settings.items():
|
||||
parser.set( self.__section, key, getattr( self, key, default))
|
||||
|
||||
try:
|
||||
parser.write( open( self.__filename, 'w'))
|
||||
except:
|
||||
raise IOError( 'Cannot write to file: %s' % self.__filename)
|
||||
|
||||
self.__save_thread = None
|
||||
|
||||
def load( self, filename = None):
|
||||
if filename != None:
|
||||
self.__filename = filename
|
||||
|
||||
parser = ConfigParser.RawConfigParser()
|
||||
try:
|
||||
parser.read( self.__filename)
|
||||
except:
|
||||
pass
|
||||
|
||||
for ( key, ( fieldtype, default ) ) in self.Settings.items():
|
||||
try:
|
||||
if fieldtype == int:
|
||||
value = parser.getint( self.__section, key)
|
||||
elif fieldtype == float:
|
||||
value = parser.getfloat( self.__section, key)
|
||||
elif fieldtype == bool:
|
||||
value = parser.getboolean( self.__section, key)
|
||||
else:
|
||||
value = fieldtype(parser.get( self.__section, key))
|
||||
except:
|
||||
value = default
|
||||
|
||||
self[key] = value
|
||||
|
||||
def __setattr__( self, name, value):
|
||||
if name in self.Settings:
|
||||
( fieldtype, default ) = self.Settings[name]
|
||||
try:
|
||||
if self[name] != fieldtype(value):
|
||||
log( 'Update: %s = %s', name, value, sender = self)
|
||||
self[name] = fieldtype(value)
|
||||
self.schedule_save()
|
||||
except:
|
||||
raise ValueError( '%s has to be of type %s' % ( name, fieldtype.__name__ ))
|
||||
else:
|
||||
object.__setattr__( self, name, value)
|
||||
|
|
@ -45,14 +45,14 @@ class DownloadURLOpener(urllib.FancyURLopener):
|
|||
|
||||
def __init__( self, channel):
|
||||
gl = libgpodder.gPodderLib()
|
||||
if gl.proxy_use_environment:
|
||||
if gl.config.proxy_use_environment:
|
||||
proxies = None
|
||||
else:
|
||||
proxies = {}
|
||||
if gl.http_proxy:
|
||||
proxies['http'] = gl.http_proxy
|
||||
if gl.ftp_proxy:
|
||||
proxies['ftp'] = gl.ftp_proxy
|
||||
if gl.config.http_proxy:
|
||||
proxies['http'] = gl.config.http_proxy
|
||||
if gl.config.ftp_proxy:
|
||||
proxies['ftp'] = gl.config.ftp_proxy
|
||||
|
||||
self.channel = channel
|
||||
urllib.FancyURLopener.__init__( self, proxies)
|
||||
|
@ -81,8 +81,8 @@ class DownloadThread(threading.Thread):
|
|||
self.tempname = os.path.join( os.path.dirname( self.filename), '.tmp-' + os.path.basename( self.filename))
|
||||
|
||||
gl = libgpodder.gPodderLib()
|
||||
self.limit_rate = gl.limit_rate
|
||||
self.limit_rate_value = gl.limit_rate_value
|
||||
self.limit_rate = gl.config.limit_rate
|
||||
self.limit_rate_value = gl.config.limit_rate_value
|
||||
|
||||
self.cancelled = False
|
||||
self.start_time = 0.0
|
||||
|
|
|
@ -151,9 +151,10 @@ class gPodder(GladeWidget):
|
|||
self.uar = None
|
||||
|
||||
gl = gPodderLib()
|
||||
self.gPodder.resize( gl.main_window_width, gl.main_window_height)
|
||||
self.gPodder.move( gl.main_window_x, gl.main_window_y)
|
||||
self.channelPaned.set_position( gl.paned_position)
|
||||
|
||||
gl.config.connect_gtk_window( self.gPodder)
|
||||
gl.config.connect_gtk_paned( 'paned_position', self.channelPaned)
|
||||
|
||||
while gtk.events_pending():
|
||||
gtk.main_iteration( False)
|
||||
|
||||
|
@ -257,7 +258,7 @@ class gPodder(GladeWidget):
|
|||
gl.clean_up_downloads( delete_partial = True)
|
||||
|
||||
# Now, update the feed cache, when everything's in place
|
||||
self.update_feed_cache( force_update = gl.update_on_startup)
|
||||
self.update_feed_cache( force_update = gl.config.update_on_startup)
|
||||
|
||||
def treeview_channels_button_pressed( self, treeview, event):
|
||||
if event.button == 3:
|
||||
|
@ -498,11 +499,11 @@ class gPodder(GladeWidget):
|
|||
can_download = True
|
||||
|
||||
if util.file_type_by_extension( util.file_extension_from_url( url)) == 'torrent':
|
||||
can_download = can_download or gPodderLib().use_gnome_bittorrent
|
||||
can_download = can_download or gPodderLib().config.use_gnome_bittorrent
|
||||
|
||||
can_download = can_download and not can_cancel
|
||||
can_play = can_play and not can_cancel and not can_download
|
||||
can_transfer = can_play and gPodderLib().device_type != 'none'
|
||||
can_transfer = can_play and gPodderLib().config.device_type != 'none'
|
||||
|
||||
self.toolPlay.set_sensitive( can_play)
|
||||
self.toolDownload.set_sensitive( can_download)
|
||||
|
@ -618,7 +619,7 @@ class gPodder(GladeWidget):
|
|||
for channel in downloaded_channels:
|
||||
sync.set_progress_overall( i, len(downloaded_channels))
|
||||
channel.load_settings()
|
||||
sync.sync_channel( channel, sync_played_episodes = not gPodderLib().only_sync_not_played)
|
||||
sync.sync_channel( channel, sync_played_episodes = not gPodderLib().config.only_sync_not_played)
|
||||
i += 1
|
||||
sync.set_progress_overall( i, len(downloaded_channels))
|
||||
else:
|
||||
|
@ -716,7 +717,7 @@ class gPodder(GladeWidget):
|
|||
self.updateComboBox()
|
||||
|
||||
# download all new?
|
||||
if force_update and gPodderLib().download_after_update:
|
||||
if force_update and gPodderLib().config.download_after_update:
|
||||
self.on_itemDownloadAllNew_activate( self.gPodder)
|
||||
|
||||
def download_podcast_by_url( self, url, want_message_dialog = True, widget = None):
|
||||
|
@ -767,15 +768,6 @@ class gPodder(GladeWidget):
|
|||
|
||||
gl = gPodderLib()
|
||||
|
||||
size = self.gPodder.get_size()
|
||||
pos = self.gPodder.get_position()
|
||||
gl.main_window_width = size[0]
|
||||
gl.main_window_height = size[1]
|
||||
gl.main_window_x = pos[0]
|
||||
gl.main_window_y = pos[1]
|
||||
gl.paned_position = self.channelPaned.get_position()
|
||||
gl.propertiesChanged()
|
||||
|
||||
self.gtk_main_quit()
|
||||
sys.exit( 0)
|
||||
|
||||
|
@ -854,24 +846,24 @@ class gPodder(GladeWidget):
|
|||
|
||||
def on_sync_to_ipod_activate(self, widget, *args):
|
||||
gl = gPodderLib()
|
||||
if gl.device_type == 'none':
|
||||
if gl.config.device_type == 'none':
|
||||
title = _('No device configured')
|
||||
message = _('To use the synchronization feature, please configure your device in the preferences dialog first.')
|
||||
self.show_message( message, title)
|
||||
return
|
||||
|
||||
if gl.device_type == 'ipod' and not ipod_supported():
|
||||
if gl.config.device_type == 'ipod' and not ipod_supported():
|
||||
title = _('Libraries needed: gpod, pymad')
|
||||
message = _('To use the iPod synchronization feature, you need to install the <b>python-gpod</b> and <b>python-pymad</b> libraries from your distribution vendor. More information about the needed libraries can be found on the gPodder website.')
|
||||
self.show_message( message, title)
|
||||
return
|
||||
|
||||
if gl.device_type in [ 'ipod', 'filesystem' ]:
|
||||
if gl.config.device_type in [ 'ipod', 'filesystem' ]:
|
||||
sync_class = None
|
||||
|
||||
if gl.device_type == 'filesystem':
|
||||
if gl.config.device_type == 'filesystem':
|
||||
sync_class = gPodder_FSSync
|
||||
elif gl.device_type == 'ipod':
|
||||
elif gl.config.device_type == 'ipod':
|
||||
sync_class = gPodder_iPodSync
|
||||
|
||||
if not sync_class:
|
||||
|
@ -888,27 +880,27 @@ class gPodder(GladeWidget):
|
|||
|
||||
def on_cleanup_ipod_activate(self, widget, *args):
|
||||
gl = gPodderLib()
|
||||
if gl.device_type == 'none':
|
||||
if gl.config.device_type == 'none':
|
||||
title = _('No device configured')
|
||||
message = _('To use the synchronization feature, please configure your device in the preferences dialog first.')
|
||||
self.show_message( message, title)
|
||||
return
|
||||
|
||||
if gl.device_type == 'ipod' and not ipod_supported():
|
||||
if gl.config.device_type == 'ipod' and not ipod_supported():
|
||||
title = _('Libraries needed: gpod, pymad')
|
||||
message = _('To use the iPod synchronization feature, you need to install the <b>python-gpod</b> and <b>python-pymad</b> libraries from your distribution vendor. More information about the needed libraries can be found on the gPodder website.')
|
||||
self.show_message( message, title)
|
||||
return
|
||||
|
||||
if gl.device_type in [ 'ipod', 'filesystem' ]:
|
||||
if gl.config.device_type in [ 'ipod', 'filesystem' ]:
|
||||
sync_class = None
|
||||
|
||||
if gl.device_type == 'filesystem':
|
||||
if gl.config.device_type == 'filesystem':
|
||||
title = _('Delete podcasts from MP3 player?')
|
||||
message = _('Do you really want to completely remove all episodes from your MP3 player?')
|
||||
if self.show_confirmation( message, title):
|
||||
sync_class = gPodder_FSSync
|
||||
elif gl.device_type == 'ipod':
|
||||
elif gl.config.device_type == 'ipod':
|
||||
title = _('Delete podcasts on iPod?')
|
||||
message = _('Do you really want to completely remove all episodes in the <b>Podcasts</b> playlist on your iPod?')
|
||||
if self.show_confirmation( message, title):
|
||||
|
@ -981,7 +973,7 @@ class gPodder(GladeWidget):
|
|||
dlg.destroy()
|
||||
|
||||
def on_itemImportChannels_activate(self, widget, *args):
|
||||
gPodderOpmlLister().get_channels_from_url( gPodderLib().opml_url, lambda url: self.add_new_channel(url,False), lambda: self.on_itemDownloadAllNew_activate( self.gPodder))
|
||||
gPodderOpmlLister().get_channels_from_url( gPodderLib().config.opml_url, lambda url: self.add_new_channel(url,False), lambda: self.on_itemDownloadAllNew_activate( self.gPodder))
|
||||
|
||||
def on_btnTransfer_clicked(self, widget, *args):
|
||||
self.on_treeAvailable_row_activated( widget, args)
|
||||
|
@ -1311,43 +1303,45 @@ class gPodderProperties(GladeWidget):
|
|||
def new(self):
|
||||
self.callback_finished = None
|
||||
gl = gPodderLib()
|
||||
self.httpProxy.set_text( gl.http_proxy)
|
||||
self.ftpProxy.set_text( gl.ftp_proxy)
|
||||
self.openApp.set_text( gl.open_app)
|
||||
self.iPodMountpoint.set_label( gl.ipod_mount)
|
||||
self.ipodIcon.set_from_icon_name( 'gnome-dev-ipod', gtk.ICON_SIZE_BUTTON)
|
||||
self.filesystemMountpoint.set_label( gl.mp3_player_folder)
|
||||
self.opmlURL.set_text( gl.opml_url)
|
||||
if gl.downloaddir:
|
||||
self.chooserDownloadTo.set_filename( gl.downloaddir)
|
||||
if gl.torrentdir:
|
||||
self.chooserBitTorrentTo.set_filename( gl.torrentdir)
|
||||
self.radio_copy_torrents.set_active( not gl.use_gnome_bittorrent)
|
||||
self.radio_gnome_bittorrent.set_active( gl.use_gnome_bittorrent)
|
||||
self.updateonstartup.set_active(gl.update_on_startup)
|
||||
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.cbCustomSyncName.set_active(gl.custom_sync_name_enabled)
|
||||
self.entryCustomSyncName.set_text(gl.custom_sync_name)
|
||||
|
||||
gl.config.connect_gtk_editable( 'http_proxy', self.httpProxy)
|
||||
gl.config.connect_gtk_editable( 'ftp_proxy', self.ftpProxy)
|
||||
gl.config.connect_gtk_editable( 'player', self.openApp)
|
||||
gl.config.connect_gtk_editable( 'opml_url', self.opmlURL)
|
||||
gl.config.connect_gtk_editable( 'custom_sync_name', self.entryCustomSyncName)
|
||||
gl.config.connect_gtk_togglebutton( 'custom_sync_name_enabled', self.cbCustomSyncName)
|
||||
gl.config.connect_gtk_togglebutton( 'download_after_update', self.downloadnew)
|
||||
gl.config.connect_gtk_togglebutton( 'use_gnome_bittorrent', self.radio_gnome_bittorrent)
|
||||
gl.config.connect_gtk_togglebutton( 'update_on_startup', self.updateonstartup)
|
||||
gl.config.connect_gtk_togglebutton( 'only_sync_not_played', self.only_sync_not_played)
|
||||
gl.config.connect_gtk_spinbutton( 'max_downloads', self.spinMaxDownloads)
|
||||
gl.config.connect_gtk_togglebutton( 'max_downloads_enabled', self.cbMaxDownloads)
|
||||
gl.config.connect_gtk_spinbutton( 'limit_rate_value', self.spinLimitDownloads)
|
||||
gl.config.connect_gtk_togglebutton( 'limit_rate', self.cbLimitDownloads)
|
||||
gl.config.connect_gtk_togglebutton( 'proxy_use_environment', self.cbEnvironmentVariables)
|
||||
gl.config.connect_gtk_filechooser( 'bittorrent_dir', self.chooserBitTorrentTo)
|
||||
|
||||
self.entryCustomSyncName.set_sensitive( self.cbCustomSyncName.get_active())
|
||||
self.spinMaxDownloads.set_value(gl.max_downloads)
|
||||
self.only_sync_not_played.set_active(gl.only_sync_not_played)
|
||||
self.radio_copy_torrents.set_active( not self.radio_gnome_bittorrent.get_active())
|
||||
|
||||
self.iPodMountpoint.set_label( gl.config.ipod_mount)
|
||||
self.filesystemMountpoint.set_label( gl.config.mp3_player_folder)
|
||||
self.chooserDownloadTo.set_filename( gl.downloaddir)
|
||||
|
||||
if tagging_supported():
|
||||
self.updatetags.set_active(gl.update_tags)
|
||||
gl.config.connect_gtk_togglebutton( 'update_tags', self.updatetags)
|
||||
else:
|
||||
self.updatetags.set_sensitive( False)
|
||||
new_label = '%s (%s)' % ( self.updatetags.get_label(), _('needs python-eyed3') )
|
||||
self.updatetags.set_label( new_label)
|
||||
|
||||
# device type
|
||||
self.comboboxDeviceType.set_active( 0)
|
||||
if gl.device_type == 'ipod':
|
||||
if gl.config.device_type == 'ipod':
|
||||
self.comboboxDeviceType.set_active( 1)
|
||||
elif gl.device_type == 'filesystem':
|
||||
elif gl.config.device_type == 'filesystem':
|
||||
self.comboboxDeviceType.set_active( 2)
|
||||
# the use proxy env vars check box
|
||||
self.cbEnvironmentVariables.set_active( gl.proxy_use_environment)
|
||||
|
||||
# setup cell renderers
|
||||
cellrenderer = gtk.CellRendererPixbuf()
|
||||
self.comboPlayerApp.pack_start( cellrenderer, False)
|
||||
|
@ -1356,6 +1350,8 @@ class gPodderProperties(GladeWidget):
|
|||
self.comboPlayerApp.pack_start( cellrenderer, True)
|
||||
self.comboPlayerApp.add_attribute( cellrenderer, 'markup', 0)
|
||||
|
||||
self.ipodIcon.set_from_icon_name( 'gnome-dev-ipod', gtk.ICON_SIZE_BUTTON)
|
||||
|
||||
def update_mountpoint( self, ipod):
|
||||
if ipod == None or ipod.mount_point == None:
|
||||
self.iPodMountpoint.set_label( '')
|
||||
|
@ -1485,13 +1481,8 @@ class gPodderProperties(GladeWidget):
|
|||
|
||||
def on_btnOK_clicked(self, widget, *args):
|
||||
gl = gPodderLib()
|
||||
gl.http_proxy = self.httpProxy.get_text()
|
||||
gl.ftp_proxy = self.ftpProxy.get_text()
|
||||
gl.open_app = self.openApp.get_text()
|
||||
gl.proxy_use_environment = self.cbEnvironmentVariables.get_active()
|
||||
gl.ipod_mount = self.iPodMountpoint.get_label()
|
||||
gl.mp3_player_folder = self.filesystemMountpoint.get_label()
|
||||
gl.opml_url = self.opmlURL.get_text()
|
||||
gl.config.ipod_mount = self.iPodMountpoint.get_label()
|
||||
gl.config.mp3_player_folder = self.filesystemMountpoint.get_label()
|
||||
|
||||
if gl.downloaddir != self.chooserDownloadTo.get_filename():
|
||||
new_download_dir = self.chooserDownloadTo.get_filename()
|
||||
|
@ -1542,26 +1533,13 @@ class gPodderProperties(GladeWidget):
|
|||
|
||||
dlg.destroy()
|
||||
|
||||
gl.torrentdir = self.chooserBitTorrentTo.get_filename()
|
||||
gl.use_gnome_bittorrent = self.radio_gnome_bittorrent.get_active()
|
||||
gl.update_on_startup = self.updateonstartup.get_active()
|
||||
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.custom_sync_name = self.entryCustomSyncName.get_text()
|
||||
gl.custom_sync_name_enabled = self.cbCustomSyncName.get_active()
|
||||
gl.update_tags = self.updatetags.get_active()
|
||||
gl.only_sync_not_played = self.only_sync_not_played.get_active()
|
||||
device_type = self.comboboxDeviceType.get_active()
|
||||
if device_type == 0:
|
||||
gl.device_type = 'none'
|
||||
gl.config.device_type = 'none'
|
||||
elif device_type == 1:
|
||||
gl.device_type = 'ipod'
|
||||
gl.config.device_type = 'ipod'
|
||||
elif device_type == 2:
|
||||
gl.device_type = 'filesystem'
|
||||
gl.propertiesChanged()
|
||||
gl.config.device_type = 'filesystem'
|
||||
self.gPodderProperties.destroy()
|
||||
if self.callback_finished:
|
||||
self.callback_finished()
|
||||
|
|
|
@ -24,6 +24,7 @@
|
|||
#
|
||||
|
||||
import gtk
|
||||
import gtk.gdk
|
||||
import gobject
|
||||
import thread
|
||||
import threading
|
||||
|
@ -32,58 +33,21 @@ import shutil
|
|||
|
||||
from gpodder import util
|
||||
from gpodder import opml
|
||||
from gpodder import config
|
||||
|
||||
from os.path import expanduser
|
||||
from os.path import exists
|
||||
from os.path import splitext
|
||||
from liblogger import log
|
||||
from os.path import dirname
|
||||
from os.path import basename
|
||||
from os.path import isfile
|
||||
from os.path import isdir
|
||||
from os.path import islink
|
||||
from os.path import getsize
|
||||
from os.path import join
|
||||
import os
|
||||
import os.path
|
||||
from os import mkdir
|
||||
from os import rmdir
|
||||
from os import makedirs
|
||||
from os import environ
|
||||
from os import system
|
||||
from os import unlink
|
||||
from os import listdir
|
||||
from glob import glob
|
||||
import glob
|
||||
import types
|
||||
import subprocess
|
||||
|
||||
from libplayers import dotdesktop_command
|
||||
from liblogger import log
|
||||
|
||||
from types import ListType
|
||||
|
||||
from gtk.gdk import PixbufLoader
|
||||
|
||||
from ConfigParser import ConfigParser
|
||||
|
||||
from xml.sax import saxutils
|
||||
|
||||
from urlparse import urlparse
|
||||
|
||||
from subprocess import Popen
|
||||
import shlex
|
||||
|
||||
# global recursive lock for thread exclusion
|
||||
globalLock = threading.RLock()
|
||||
|
||||
# my gpodderlib variable
|
||||
g_podder_lib = None
|
||||
|
||||
# default url to use for opml directory on the web
|
||||
default_opml_directory = 'http://gpodder.berlios.de/directory.opml'
|
||||
|
||||
def getLock():
|
||||
globalLock.acquire()
|
||||
|
||||
def releaseLock():
|
||||
globalLock.release()
|
||||
|
||||
# some awkward kind of "singleton" ;)
|
||||
def gPodderLib():
|
||||
global g_podder_lib
|
||||
|
@ -92,154 +56,66 @@ def gPodderLib():
|
|||
return g_podder_lib
|
||||
|
||||
class gPodderLibClass( object):
|
||||
gpodderconf_section = 'gpodder-conf-1'
|
||||
|
||||
def __init__( self):
|
||||
self.gpodderdir = expanduser( "~/.config/gpodder/")
|
||||
util.make_directory( self.gpodderdir)
|
||||
self.feed_cache_file = os.path.join( self.gpodderdir, 'feedcache.db')
|
||||
self.channel_settings_file = os.path.join( self.gpodderdir, 'channelsettings.db')
|
||||
self.channel_opml_file = os.path.join( self.gpodderdir, 'channels.opml')
|
||||
self.__download_dir = None
|
||||
try:
|
||||
self.http_proxy = environ['http_proxy']
|
||||
except:
|
||||
self.http_proxy = ''
|
||||
try:
|
||||
self.ftp_proxy = environ['ftp_proxy']
|
||||
except:
|
||||
self.ftp_proxy = ''
|
||||
self.proxy_use_environment = True
|
||||
self.open_app = ""
|
||||
self.ipod_mount = ""
|
||||
self.opml_url = ""
|
||||
self.update_on_startup = False
|
||||
self.download_after_update = True
|
||||
self.torrentdir = expanduser('~/gpodder-downloads/torrents')
|
||||
self.use_gnome_bittorrent = True
|
||||
self.limit_rate = False
|
||||
self.limit_rate_value = 4.0
|
||||
self.update_tags = False
|
||||
self.desktop_link = _("gPodder downloads")
|
||||
self.device_type = None
|
||||
self.main_window_width = 600
|
||||
self.main_window_height = 450
|
||||
self.main_window_x = 0
|
||||
self.main_window_y = 0
|
||||
self.paned_position = 150
|
||||
self.max_downloads = 3
|
||||
self.max_downloads_enabled = False
|
||||
self.custom_sync_name_enabled = False
|
||||
self.custom_sync_name = '{episode.title}'
|
||||
self.default_new = 1
|
||||
self.mp3_player_folder = ""
|
||||
self.only_sync_not_played = False
|
||||
self.__download_history = DownloadHistory( self.get_download_history_filename())
|
||||
self.__playback_history = PlaybackHistory( self.get_playback_history_filename())
|
||||
self.loadConfig()
|
||||
gpodder_dir = os.path.expanduser( '~/.config/gpodder/')
|
||||
util.make_directory( gpodder_dir)
|
||||
|
||||
self.feed_cache_file = os.path.join( gpodder_dir, 'feedcache.db')
|
||||
self.channel_settings_file = os.path.join( gpodder_dir, 'channelsettings.db')
|
||||
self.channel_opml_file = os.path.join( gpodder_dir, 'channels.opml')
|
||||
|
||||
self.config = config.Config( os.path.join( gpodder_dir, 'gpodder.conf'))
|
||||
|
||||
self.__download_history = HistoryStore( os.path.join( gpodder_dir, 'download-history.txt'))
|
||||
self.__playback_history = HistoryStore( os.path.join( gpodder_dir, 'playback-history.txt'))
|
||||
|
||||
def getConfigFilename( self):
|
||||
return self.gpodderdir + "gpodder.conf"
|
||||
|
||||
def getChannelsFilename( self):
|
||||
return self.gpodderdir + "channels.xml"
|
||||
|
||||
def get_download_history_filename( self):
|
||||
return self.gpodderdir + 'download-history.txt'
|
||||
|
||||
def get_playback_history_filename( self):
|
||||
return self.gpodderdir + 'playback-history.txt'
|
||||
|
||||
def get_device_name( self):
|
||||
if self.device_type == 'ipod':
|
||||
if self.config.device_type == 'ipod':
|
||||
return _('iPod')
|
||||
elif self.device_type == 'filesystem':
|
||||
elif self.config.device_type == 'filesystem':
|
||||
return _('MP3 player')
|
||||
else:
|
||||
log( 'Warning: Called get_device_name() when no device was selected.', sender = self)
|
||||
return '(unknown device)'
|
||||
|
||||
def propertiesChanged( self):
|
||||
# set new environment variables for subprocesses to use,
|
||||
# but only if we are not told to passthru the env vars
|
||||
if not self.proxy_use_environment:
|
||||
environ['http_proxy'] = self.http_proxy
|
||||
environ['ftp_proxy'] = self.ftp_proxy
|
||||
# save settings for next startup
|
||||
self.saveConfig()
|
||||
|
||||
def clean_up_downloads( self, delete_partial = False):
|
||||
# Clean up temporary files left behind by old gPodder versions
|
||||
if delete_partial:
|
||||
temporary_files = glob( '%s/*/.tmp-*' % ( self.downloaddir, ))
|
||||
temporary_files = glob.glob( '%s/*/.tmp-*' % ( self.downloaddir, ))
|
||||
for tempfile in temporary_files:
|
||||
util.delete_file( tempfile)
|
||||
|
||||
# Clean up empty download folders
|
||||
download_dirs = glob( '%s/*' % ( self.downloaddir, ))
|
||||
download_dirs = glob.glob( '%s/*' % ( self.downloaddir, ))
|
||||
for ddir in download_dirs:
|
||||
if isdir( ddir):
|
||||
globr = glob( '%s/*' % ( ddir, ))
|
||||
if not globr and ddir != self.torrentdir:
|
||||
log( 'Stale download directory found: %s', basename( ddir))
|
||||
if os.path.isdir( ddir):
|
||||
globr = glob.glob( '%s/*' % ( ddir, ))
|
||||
if not globr and ddir != self.config.bittorrent_dir:
|
||||
log( 'Stale download directory found: %s', os.path.basename( ddir))
|
||||
try:
|
||||
rmdir( ddir)
|
||||
os.rmdir( ddir)
|
||||
log( 'Successfully removed %s.', ddir)
|
||||
except:
|
||||
log( 'Could not remove %s.', ddir)
|
||||
|
||||
def saveConfig( self):
|
||||
parser = ConfigParser()
|
||||
self.write_to_parser( parser, 'http_proxy', self.http_proxy)
|
||||
self.write_to_parser( parser, 'ftp_proxy', self.ftp_proxy)
|
||||
self.write_to_parser( parser, 'player', self.open_app)
|
||||
self.write_to_parser( parser, 'proxy_use_env', self.proxy_use_environment)
|
||||
self.write_to_parser( parser, 'ipod_mount', self.ipod_mount)
|
||||
self.write_to_parser( parser, 'update_on_startup', self.update_on_startup)
|
||||
self.write_to_parser( parser, 'download_after_update', self.download_after_update)
|
||||
self.write_to_parser( parser, 'limit_rate', self.limit_rate)
|
||||
self.write_to_parser( parser, 'limit_rate_value', self.limit_rate_value)
|
||||
self.write_to_parser( parser, 'update_tags', self.update_tags)
|
||||
self.write_to_parser( parser, 'opml_url', self.opml_url)
|
||||
self.write_to_parser( parser, 'download_dir', self.downloaddir)
|
||||
self.write_to_parser( parser, 'bittorrent_dir', self.torrentdir)
|
||||
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, 'custom_sync_name', self.custom_sync_name)
|
||||
self.write_to_parser( parser, 'custom_sync_name_enabled', self.custom_sync_name_enabled)
|
||||
self.write_to_parser( parser, 'default_new', self.default_new)
|
||||
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)
|
||||
self.write_to_parser( parser, 'paned_position', self.paned_position)
|
||||
self.write_to_parser( parser, 'mp3_player_folder', self.mp3_player_folder)
|
||||
self.write_to_parser( parser, 'only_sync_not_played', self.only_sync_not_played)
|
||||
fn = self.getConfigFilename()
|
||||
fp = open( fn, "w")
|
||||
parser.write( fp)
|
||||
fp.close()
|
||||
|
||||
def get_download_dir( self):
|
||||
util.make_directory( self.__download_dir)
|
||||
return self.__download_dir
|
||||
util.make_directory( self.config.download_dir)
|
||||
return self.config.download_dir
|
||||
|
||||
def set_download_dir( self, new_downloaddir):
|
||||
if self.__download_dir and self.__download_dir != new_downloaddir:
|
||||
log( 'Moving downloads from %s to %s', self.__download_dir, new_downloaddir)
|
||||
if self.config.download_dir != new_downloaddir:
|
||||
log( 'Moving downloads from %s to %s', self.config.download_dir, new_downloaddir)
|
||||
try:
|
||||
# Fix error when moving over disk boundaries
|
||||
if isdir( new_downloaddir) and not listdir( new_downloaddir):
|
||||
rmdir( new_downloaddir)
|
||||
if os.path.isdir( new_downloaddir) and not os.listdir( new_downloaddir):
|
||||
os.rmdir( new_downloaddir)
|
||||
|
||||
shutil.move( self.__download_dir, new_downloaddir)
|
||||
shutil.move( self.config.download_dir, new_downloaddir)
|
||||
except:
|
||||
log( 'Error while moving %s to %s.', self.__download_dir, new_downloaddir)
|
||||
log( 'Error while moving %s to %s.', self.config.download_dir, new_downloaddir)
|
||||
return
|
||||
|
||||
self.__download_dir = new_downloaddir
|
||||
self.config.download_dir = new_downloaddir
|
||||
|
||||
downloaddir = property(fget=get_download_dir,fset=set_download_dir)
|
||||
|
||||
|
@ -261,133 +137,21 @@ class gPodderLibClass( object):
|
|||
def history_is_played( self, url):
|
||||
return (url in self.__playback_history)
|
||||
|
||||
def get_from_parser( self, parser, option, default = ''):
|
||||
try:
|
||||
result = parser.get( self.gpodderconf_section, option)
|
||||
return result
|
||||
except:
|
||||
return default
|
||||
|
||||
def get_int_from_parser( self, parser, option, default = 0):
|
||||
try:
|
||||
result = int(parser.get( self.gpodderconf_section, option))
|
||||
return result
|
||||
except:
|
||||
return default
|
||||
|
||||
def get_float_from_parser( self, parser, option, default = 1.0):
|
||||
try:
|
||||
result = float(parser.get( self.gpodderconf_section, option))
|
||||
return result
|
||||
except:
|
||||
return default
|
||||
|
||||
def get_boolean_from_parser( self, parser, option, default = False):
|
||||
try:
|
||||
result = parser.getboolean( self.gpodderconf_section, option)
|
||||
return result
|
||||
except:
|
||||
return default
|
||||
|
||||
def write_to_parser( self, parser, option, value = ''):
|
||||
if not parser.has_section( self.gpodderconf_section):
|
||||
parser.add_section( self.gpodderconf_section)
|
||||
try:
|
||||
parser.set( self.gpodderconf_section, option, str(value))
|
||||
except:
|
||||
log( 'write_to_parser: could not write config (option=%s, value=%s)', option, value)
|
||||
|
||||
def loadConfig( self):
|
||||
was_oldstyle = False
|
||||
try:
|
||||
fn = self.getConfigFilename()
|
||||
if open(fn,'r').read(1) != '[':
|
||||
log( 'seems like old-style config. trying to read it anyways..')
|
||||
fp = open( fn, 'r')
|
||||
http = fp.readline()
|
||||
ftp = fp.readline()
|
||||
app = fp.readline()
|
||||
fp.close()
|
||||
was_oldstyle = True
|
||||
else:
|
||||
parser = ConfigParser()
|
||||
parser.read( fn)
|
||||
if parser.has_section( self.gpodderconf_section):
|
||||
http = self.get_from_parser( parser, 'http_proxy')
|
||||
ftp = self.get_from_parser( parser, 'ftp_proxy')
|
||||
app = self.get_from_parser( parser, 'player', 'gnome-open')
|
||||
opml_url = self.get_from_parser( parser, 'opml_url', default_opml_directory)
|
||||
if opml_url == 'http://share.opml.org/opml/topPodcasts.opml':
|
||||
opml_url = 'http://gpodder.berlios.de/directory.opml'
|
||||
self.proxy_use_environment = self.get_boolean_from_parser( parser, 'proxy_use_env', True)
|
||||
self.ipod_mount = self.get_from_parser( parser, 'ipod_mount', '/media/ipod')
|
||||
self.update_on_startup = self.get_boolean_from_parser(parser, 'update_on_startup', default=False)
|
||||
self.download_after_update = self.get_boolean_from_parser(parser, 'download_after_update', default=False)
|
||||
self.limit_rate = self.get_boolean_from_parser(parser, 'limit_rate', default=False)
|
||||
self.limit_rate_value = self.get_float_from_parser(parser, 'limit_rate_value', default=4.0)
|
||||
self.update_tags = self.get_boolean_from_parser(parser, 'update_tags', default=False)
|
||||
self.downloaddir = self.get_from_parser( parser, 'download_dir', expanduser('~/gpodder-downloads'))
|
||||
self.torrentdir = self.get_from_parser( parser, 'bittorrent_dir', expanduser('~/gpodder-downloads/torrents'))
|
||||
self.use_gnome_bittorrent = self.get_boolean_from_parser( parser, 'use_gnome_bittorrent', default=True)
|
||||
self.device_type = self.get_from_parser( parser, 'device_type', 'none')
|
||||
self.main_window_width = self.get_int_from_parser( parser, 'main_window_width', 600)
|
||||
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.paned_position = self.get_int_from_parser( parser, 'paned_position', 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.custom_sync_name = self.get_from_parser( parser, 'custom_sync_name', '')
|
||||
self.custom_sync_name_enabled = self.get_boolean_from_parser(parser, 'custom_sync_name_enabled', default=False)
|
||||
self.default_new = self.get_int_from_parser( parser, 'default_new', 1)
|
||||
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:
|
||||
log( 'config file %s has no section %s', fn, gpodderconf_section)
|
||||
if not self.proxy_use_environment:
|
||||
self.http_proxy = http.strip()
|
||||
self.ftp_proxy = ftp.strip()
|
||||
if app.strip():
|
||||
self.open_app = app.strip()
|
||||
else:
|
||||
self.open_app = 'gnome-open'
|
||||
if opml_url.strip():
|
||||
self.opml_url = opml_url.strip()
|
||||
else:
|
||||
self.opml_url = default_opml_directory
|
||||
except:
|
||||
# TODO: well, well.. (http + ftp?)
|
||||
self.open_app = 'gnome-open'
|
||||
self.ipod_mount = '/media/ipod'
|
||||
self.device_type = 'none'
|
||||
self.main_window_width = 600
|
||||
self.main_window_height = 450
|
||||
self.main_window_x = 0
|
||||
self.main_window_y = 0
|
||||
self.paned_position = 150
|
||||
self.mp3_player_folder = '/media/usbdisk'
|
||||
self.opml_url = default_opml_directory
|
||||
self.downloaddir = expanduser('~/gpodder-downloads')
|
||||
self.torrentdir = expanduser('~/gpodder-downloads/torrents')
|
||||
self.use_gnome_bittorrent = True
|
||||
if was_oldstyle:
|
||||
self.saveConfig()
|
||||
|
||||
def playback_episode( self, channel, episode):
|
||||
self.history_mark_played( episode.url)
|
||||
filename = episode.local_filename()
|
||||
|
||||
command_line = shlex.split( dotdesktop_command( self.open_app, filename).encode('utf-8'))
|
||||
command_line = shlex.split( util.format_desktop_command( self.config.player, filename).encode('utf-8'))
|
||||
log( 'Command line: [ %s ]', ', '.join( [ '"%s"' % p for p in command_line ]), sender = self)
|
||||
try:
|
||||
Popen( command_line)
|
||||
subprocess.Popen( command_line)
|
||||
except:
|
||||
return ( False, command_line[0] )
|
||||
return ( True, command_line[0] )
|
||||
|
||||
def open_folder( self, folder):
|
||||
try:
|
||||
Popen( [ 'xdg-open', folder ])
|
||||
subprocess.Popen( [ 'xdg-open', folder ])
|
||||
# FIXME: Win32-specific "open" code needed here
|
||||
# as fallback when xdg-open not available
|
||||
except:
|
||||
|
@ -396,13 +160,13 @@ class gPodderLibClass( object):
|
|||
def image_download_thread( self, url, callback_pixbuf = None, callback_status = None, callback_finished = None, cover_file = None):
|
||||
if callback_status != None:
|
||||
gobject.idle_add( callback_status, _('Downloading channel cover...'))
|
||||
pixbuf = PixbufLoader()
|
||||
pixbuf = gtk.gdk.PixbufLoader()
|
||||
|
||||
if cover_file == None:
|
||||
log( 'Downloading %s', url)
|
||||
pixbuf.write( urllib.urlopen(url).read())
|
||||
|
||||
if cover_file != None and not exists( cover_file):
|
||||
if cover_file != None and not os.path.exists( cover_file):
|
||||
log( 'Downloading cover to %s', cover_file)
|
||||
cachefile = open( cover_file, "w")
|
||||
cachefile.write( urllib.urlopen(url).read())
|
||||
|
@ -445,20 +209,20 @@ class gPodderLibClass( object):
|
|||
def invoke_torrent( self, url, torrent_filename, target_filename):
|
||||
self.history_mark_played( url)
|
||||
|
||||
if self.use_gnome_bittorrent:
|
||||
command = 'gnome-btdownload "%s" --saveas "%s"' % ( torrent_filename, join( self.torrentdir, target_filename))
|
||||
if self.config.use_gnome_bittorrent:
|
||||
command = 'gnome-btdownload "%s" --saveas "%s"' % ( torrent_filename, os.path.join( self.config.bittorrent_dir, target_filename))
|
||||
log( command, sender = self)
|
||||
system( '%s &' % command)
|
||||
os.system( '%s &' % command)
|
||||
else:
|
||||
# Simply copy the .torrent with a suitable name
|
||||
try:
|
||||
target_filename = join( self.torrentdir, splitext( target_filename)[0] + '.torrent')
|
||||
target_filename = os.path.join( self.config.bittorrent_dir, os.path.splitext( target_filename)[0] + '.torrent')
|
||||
shutil.copyfile( torrent_filename, target_filename)
|
||||
except:
|
||||
log( 'Torrent copy failed: %s => %s.', torrent_filename, target_filename)
|
||||
|
||||
|
||||
class DownloadHistory( ListType):
|
||||
class HistoryStore( types.ListType):
|
||||
def __init__( self, filename):
|
||||
self.filename = filename
|
||||
try:
|
||||
|
@ -480,7 +244,7 @@ class DownloadHistory( ListType):
|
|||
|
||||
def add_item( self, data, autosave = True):
|
||||
affected = 0
|
||||
if data and type( data) is ListType:
|
||||
if data and type( data) is types.ListType:
|
||||
# Support passing a list of urls to this function
|
||||
for url in data:
|
||||
affected = affected + self.add_item( url, autosave = False)
|
||||
|
@ -497,7 +261,7 @@ class DownloadHistory( ListType):
|
|||
|
||||
def del_item( self, data, autosave = True):
|
||||
affected = 0
|
||||
if data and type( data) is ListType:
|
||||
if data and type( data) is types.ListType:
|
||||
# Support passing a list of urls to this function
|
||||
for url in data:
|
||||
affected = affected + self.del_item( url, autosave = False)
|
||||
|
@ -513,6 +277,3 @@ class DownloadHistory( ListType):
|
|||
return affected
|
||||
|
||||
|
||||
class PlaybackHistory( DownloadHistory):
|
||||
pass
|
||||
|
||||
|
|
|
@ -201,7 +201,7 @@ class gPodder_iPodSync( gPodderSyncMethod):
|
|||
if not ipod_supported():
|
||||
log( '(ipodsync) iPod functions not supported. (libgpod + eyed3 needed)')
|
||||
gl = libgpodder.gPodderLib()
|
||||
self.ipod_mount = gl.ipod_mount
|
||||
self.ipod_mount = gl.config.ipod_mount
|
||||
gPodderSyncMethod.__init__( self, callback_progress, callback_status, callback_done)
|
||||
|
||||
def open( self):
|
||||
|
@ -507,7 +507,7 @@ class gPodder_FSSync( gPodderSyncMethod):
|
|||
|
||||
def __init__( self, callback_progress = None, callback_status = None, callback_done = None):
|
||||
gl = libgpodder.gPodderLib()
|
||||
self.destination = gl.mp3_player_folder
|
||||
self.destination = gl.config.mp3_player_folder
|
||||
gPodderSyncMethod.__init__( self, callback_progress, callback_status, callback_done)
|
||||
self.can_cancel = True
|
||||
|
||||
|
|
|
@ -109,25 +109,3 @@ class UserAppsReader(object):
|
|||
return result
|
||||
# end of UserAppsReader
|
||||
|
||||
|
||||
def dotdesktop_command( command, filename):
|
||||
# the following flags are specified in the FDO standards for ".desktop" files:
|
||||
# http://standards.freedesktop.org/desktop-entry-spec/desktop-entry-spec-0.9.4.html
|
||||
if command.find( '%U') != -1:
|
||||
# A list of URLs. (we only need one, anyway..)
|
||||
return command.replace( '%U', ( '"file://%s"' % (filename) ) )
|
||||
if command.find( '%u') != -1:
|
||||
# A single URL.
|
||||
return command.replace( '%u', ( '"file://%s"' % (filename) ) )
|
||||
if command.find( '%F') != -1:
|
||||
# A list of files. (we only need one...)
|
||||
return command.replace( '%F', filename )
|
||||
if command.find( '%f') != -1:
|
||||
# A single file name, even if multiple files are selected.
|
||||
return command.replace( '%f', filename )
|
||||
|
||||
# default known-good variant: 1st parameter = filename
|
||||
return '%s "%s"' % ( command, filename )
|
||||
# end dotdesktop_command
|
||||
|
||||
|
||||
|
|
|
@ -51,6 +51,7 @@ import sys
|
|||
import urllib
|
||||
import urlparse
|
||||
import time
|
||||
import threading
|
||||
|
||||
from datetime import datetime
|
||||
|
||||
|
@ -74,6 +75,8 @@ import string
|
|||
|
||||
import shelve
|
||||
|
||||
global_lock = threading.RLock()
|
||||
|
||||
class ChannelSettings(object):
|
||||
storage = shelve.open( libgpodder.gPodderLib().channel_settings_file)
|
||||
|
||||
|
@ -257,7 +260,7 @@ class podcastChannel(ListType):
|
|||
gl = libgpodder.gPodderLib()
|
||||
|
||||
if not last_pubdate:
|
||||
return self[0:min(len(self),gl.default_new)]
|
||||
return self[0:min(len(self),gl.config.default_new)]
|
||||
|
||||
new_episodes = []
|
||||
|
||||
|
@ -290,7 +293,7 @@ class podcastChannel(ListType):
|
|||
|
||||
def addDownloadedItem( self, item):
|
||||
# no multithreaded access
|
||||
libgpodder.getLock()
|
||||
global_lock.acquire()
|
||||
|
||||
downloaded_episodes = self.load_downloaded_episodes()
|
||||
already_in_list = item.url in [ episode.url for episode in downloaded_episodes ]
|
||||
|
@ -301,7 +304,7 @@ class podcastChannel(ListType):
|
|||
self.save_downloaded_episodes( downloaded_episodes)
|
||||
|
||||
# Update metadata on file (if possible and wanted)
|
||||
if libgpodder.gPodderLib().update_tags and tagging_supported():
|
||||
if libgpodder.gPodderLib().config.update_tags and tagging_supported():
|
||||
filename = item.local_filename()
|
||||
try:
|
||||
update_metadata_on_file( filename, title = item.title, artist = self.title)
|
||||
|
@ -315,7 +318,7 @@ class podcastChannel(ListType):
|
|||
destination_filename = util.torrent_filename( torrent_filename)
|
||||
libgpodder.gPodderLib().invoke_torrent( item.url, torrent_filename, destination_filename)
|
||||
|
||||
libgpodder.releaseLock()
|
||||
global_lock.release()
|
||||
return not already_in_list
|
||||
|
||||
def is_played(self, item):
|
||||
|
@ -439,7 +442,7 @@ class podcastChannel(ListType):
|
|||
cover_file = property(fget=get_cover_file)
|
||||
|
||||
def delete_episode_by_url(self, url):
|
||||
libgpodder.getLock()
|
||||
global_lock.acquire()
|
||||
downloaded_episodes = self.load_downloaded_episodes()
|
||||
|
||||
for episode in self.get_all_episodes():
|
||||
|
@ -449,7 +452,7 @@ class podcastChannel(ListType):
|
|||
downloaded_episodes.remove( episode)
|
||||
|
||||
self.save_downloaded_episodes( downloaded_episodes)
|
||||
libgpodder.releaseLock()
|
||||
global_lock.release()
|
||||
|
||||
class podcastItem(object):
|
||||
"""holds data for one object in a channel"""
|
||||
|
@ -523,8 +526,8 @@ class podcastItem(object):
|
|||
return os.path.join( self.channel.save_dir, md5.new( self.url).hexdigest() + extension)
|
||||
|
||||
def sync_filename( self):
|
||||
if libgpodder.gPodderLib().custom_sync_name_enabled:
|
||||
return util.object_string_formatter( libgpodder.gPodderLib().custom_sync_name, episode = self, channel = self.channel)
|
||||
if libgpodder.gPodderLib().config.custom_sync_name_enabled:
|
||||
return util.object_string_formatter( libgpodder.gPodderLib().config.custom_sync_name, episode = self, channel = self.channel)
|
||||
else:
|
||||
return self.title
|
||||
|
||||
|
|
|
@ -44,7 +44,7 @@ class DownloadStatusManager( object):
|
|||
|
||||
self.last_progress_status = ( 0, 0 )
|
||||
|
||||
self.max_downloads = libgpodder.gPodderLib().max_downloads
|
||||
self.max_downloads = libgpodder.gPodderLib().config.max_downloads
|
||||
self.semaphore = threading.Semaphore( self.max_downloads)
|
||||
|
||||
self.tree_model = gtk.ListStore( *self.COLUMN_TYPES)
|
||||
|
@ -87,16 +87,16 @@ class DownloadStatusManager( object):
|
|||
self.last_progress_status = now
|
||||
|
||||
def s_acquire( self):
|
||||
if not libgpodder.gPodderLib().max_downloads_enabled:
|
||||
if not libgpodder.gPodderLib().config.max_downloads_enabled:
|
||||
return False
|
||||
|
||||
# Release queue slots if user has enabled more slots
|
||||
while self.max_downloads < libgpodder.gPodderLib().max_downloads:
|
||||
while self.max_downloads < libgpodder.gPodderLib().config.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:
|
||||
while self.max_downloads > libgpodder.gPodderLib().config.max_downloads:
|
||||
self.semaphore.acquire()
|
||||
self.max_downloads -= 1
|
||||
|
||||
|
|
|
@ -362,3 +362,27 @@ def object_string_formatter( s, **kwargs):
|
|||
|
||||
return result
|
||||
|
||||
|
||||
def format_desktop_command( command, filename):
|
||||
"""
|
||||
Formats a command template from the "Exec=" line of a .desktop
|
||||
file to a string that can be invoked in a shell.
|
||||
|
||||
Handled format strings: %U, %u, %F, %f and a fallback that
|
||||
appends the filename as first parameter of the command.
|
||||
|
||||
See http://standards.freedesktop.org/desktop-entry-spec/1.0/ar01s06.html
|
||||
"""
|
||||
items = {
|
||||
'%U': 'file://%s' % filename,
|
||||
'%u': 'file://%s' % filename,
|
||||
'%F': filename,
|
||||
'%f': filename,
|
||||
}
|
||||
|
||||
for key, value in items.items():
|
||||
if command.find( key) >= 0:
|
||||
return command.replace( key, value)
|
||||
|
||||
return '%s "%s"' % ( command, filename )
|
||||
|
||||
|
|
Loading…
Reference in New Issue