2005-11-21 19:21:25 +01:00
|
|
|
|
2006-04-07 22:22:30 +02:00
|
|
|
|
|
|
|
#
|
|
|
|
# gPodder (a media aggregator / podcast client)
|
2006-12-29 16:52:52 +01:00
|
|
|
# Copyright (C) 2005-2007 Thomas Perl <thp at perli.net>
|
2006-04-07 22:22:30 +02:00
|
|
|
#
|
|
|
|
# This program 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 2
|
|
|
|
# of the License, or (at your option) any later version.
|
|
|
|
#
|
|
|
|
# This program 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.
|
2005-11-21 19:21:25 +01:00
|
|
|
#
|
2006-04-07 22:22:30 +02:00
|
|
|
# You should have received a copy of the GNU General Public License
|
|
|
|
# along with this program; if not, write to the Free Software
|
|
|
|
# Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston,
|
|
|
|
# MA 02110-1301, USA.
|
2005-11-21 19:21:25 +01:00
|
|
|
#
|
|
|
|
|
|
|
|
#
|
|
|
|
# libgpodder.py -- gpodder configuration
|
|
|
|
# thomas perl <thp@perli.net> 20051030
|
|
|
|
#
|
|
|
|
#
|
|
|
|
|
|
|
|
import gtk
|
2007-07-05 23:07:16 +02:00
|
|
|
import gobject
|
2006-03-19 15:21:48 +01:00
|
|
|
import thread
|
2006-03-24 20:08:59 +01:00
|
|
|
import threading
|
2006-03-31 18:20:18 +02:00
|
|
|
import urllib
|
2006-12-06 21:25:26 +01:00
|
|
|
import shutil
|
2005-11-21 19:21:25 +01:00
|
|
|
|
|
|
|
from xml.sax.saxutils import DefaultHandler
|
|
|
|
from xml.sax import make_parser
|
|
|
|
from string import strip
|
|
|
|
from os.path import expanduser
|
|
|
|
from os.path import exists
|
2007-04-09 21:40:36 +02:00
|
|
|
from os.path import splitext
|
2007-02-05 17:50:25 +01:00
|
|
|
from liblogger import log
|
2006-12-06 21:25:26 +01:00
|
|
|
try:
|
|
|
|
from os.path import lexists
|
|
|
|
except:
|
|
|
|
log( 'lexists() not found in module os.path - (using Python < 2.4?) - will fallback to exists()')
|
2005-11-21 19:21:25 +01:00
|
|
|
from os.path import dirname
|
2006-12-03 19:11:14 +01:00
|
|
|
from os.path import basename
|
2006-11-30 23:15:17 +01:00
|
|
|
from os.path import isfile
|
2006-12-03 19:11:14 +01:00
|
|
|
from os.path import isdir
|
|
|
|
from os.path import islink
|
2006-12-20 17:38:36 +01:00
|
|
|
from os.path import getsize
|
|
|
|
from os.path import join
|
2005-11-21 19:21:25 +01:00
|
|
|
from os import mkdir
|
2006-12-03 19:11:14 +01:00
|
|
|
from os import rmdir
|
2006-04-11 18:54:49 +02:00
|
|
|
from os import makedirs
|
2006-01-09 00:52:40 +01:00
|
|
|
from os import environ
|
2006-02-04 18:29:17 +01:00
|
|
|
from os import system
|
2006-03-24 20:08:59 +01:00
|
|
|
from os import unlink
|
2006-12-20 17:38:36 +01:00
|
|
|
from os import listdir
|
2007-03-03 14:10:21 +01:00
|
|
|
from os import access
|
|
|
|
from os import W_OK
|
2006-12-03 19:11:14 +01:00
|
|
|
from glob import glob
|
2005-11-21 19:21:25 +01:00
|
|
|
|
2006-03-29 15:24:44 +02:00
|
|
|
# for the desktop symlink stuff:
|
|
|
|
from os import symlink
|
|
|
|
from os import stat
|
|
|
|
from stat import S_ISLNK
|
|
|
|
from stat import ST_MODE
|
|
|
|
|
2005-11-21 19:21:25 +01:00
|
|
|
from librssreader import rssReader
|
2006-03-03 21:04:25 +01:00
|
|
|
from libpodcasts import podcastChannel
|
2006-12-08 21:58:30 +01:00
|
|
|
from libpodcasts import DownloadHistory
|
2007-04-03 13:21:12 +02:00
|
|
|
from libpodcasts import PlaybackHistory
|
2006-06-13 20:52:25 +02:00
|
|
|
from libplayers import dotdesktop_command
|
2005-11-21 19:21:25 +01:00
|
|
|
|
2006-03-31 18:20:18 +02:00
|
|
|
from gtk.gdk import PixbufLoader
|
|
|
|
|
2006-04-05 21:07:05 +02:00
|
|
|
from ConfigParser import ConfigParser
|
|
|
|
|
2006-06-09 00:02:55 +02:00
|
|
|
from xml.sax import saxutils
|
|
|
|
|
2007-01-28 10:21:39 +01:00
|
|
|
|
2006-03-24 20:08:59 +01:00
|
|
|
# global recursive lock for thread exclusion
|
|
|
|
globalLock = threading.RLock()
|
2006-03-19 15:21:48 +01:00
|
|
|
|
2006-04-05 21:07:05 +02:00
|
|
|
# my gpodderlib variable
|
|
|
|
g_podder_lib = None
|
|
|
|
|
2006-06-13 23:00:31 +02:00
|
|
|
# default url to use for opml directory on the web
|
|
|
|
default_opml_directory = 'http://share.opml.org/opml/topPodcasts.opml'
|
|
|
|
|
2006-03-19 15:21:48 +01:00
|
|
|
def getLock():
|
|
|
|
globalLock.acquire()
|
|
|
|
|
|
|
|
def releaseLock():
|
|
|
|
globalLock.release()
|
|
|
|
|
2006-04-05 21:07:05 +02:00
|
|
|
# some awkward kind of "singleton" ;)
|
|
|
|
def gPodderLib():
|
|
|
|
global g_podder_lib
|
|
|
|
if g_podder_lib == None:
|
|
|
|
g_podder_lib = gPodderLibClass()
|
|
|
|
return g_podder_lib
|
|
|
|
|
|
|
|
class gPodderLibClass( object):
|
|
|
|
gpodderconf_section = 'gpodder-conf-1'
|
2005-11-21 19:21:25 +01:00
|
|
|
|
|
|
|
def __init__( self):
|
|
|
|
self.gpodderdir = expanduser( "~/.config/gpodder/")
|
|
|
|
self.createIfNecessary( self.gpodderdir)
|
2007-01-06 15:34:05 +01:00
|
|
|
self.__download_dir = None
|
2005-11-21 19:21:25 +01:00
|
|
|
self.cachedir = self.gpodderdir + "cache/"
|
|
|
|
self.createIfNecessary( self.cachedir)
|
2006-01-09 00:52:40 +01:00
|
|
|
try:
|
|
|
|
self.http_proxy = environ['http_proxy']
|
|
|
|
except:
|
|
|
|
self.http_proxy = ''
|
|
|
|
try:
|
|
|
|
self.ftp_proxy = environ['ftp_proxy']
|
|
|
|
except:
|
|
|
|
self.ftp_proxy = ''
|
2006-12-06 21:25:26 +01:00
|
|
|
self.proxy_use_environment = False
|
|
|
|
self.open_app = ""
|
|
|
|
self.ipod_mount = ""
|
|
|
|
self.opml_url = ""
|
|
|
|
self.update_on_startup = False
|
2007-03-08 15:04:05 +01:00
|
|
|
self.download_after_update = False
|
2007-04-09 21:40:36 +02:00
|
|
|
self.torrentdir = expanduser('~/gpodder-downloads/torrents')
|
|
|
|
self.use_gnome_bittorrent = True
|
|
|
|
self.limit_rate = False
|
|
|
|
self.limit_rate_value = 4.0
|
2007-04-03 13:21:12 +02:00
|
|
|
self.show_played = False
|
2007-03-15 22:33:23 +01:00
|
|
|
self.update_tags = False
|
2006-12-06 21:25:26 +01:00
|
|
|
self.desktop_link = _("gPodder downloads")
|
|
|
|
self.device_type = None
|
2007-04-01 19:53:04 +02:00
|
|
|
self.main_window_width = 600
|
|
|
|
self.main_window_height = 450
|
|
|
|
self.main_window_x = 0
|
|
|
|
self.main_window_y = 0
|
2007-07-05 23:07:16 +02:00
|
|
|
self.paned_position = 0
|
2007-05-01 22:01:51 +02:00
|
|
|
self.max_downloads = 3
|
|
|
|
self.max_downloads_enabled = False
|
2007-07-05 23:07:16 +02:00
|
|
|
self.default_new = 1
|
2006-12-06 21:25:26 +01:00
|
|
|
self.mp3_player_folder = ""
|
2007-04-23 17:18:31 +02:00
|
|
|
self.only_sync_not_played = False
|
2006-12-08 21:58:30 +01:00
|
|
|
self.__download_history = DownloadHistory( self.get_download_history_filename())
|
2007-04-03 13:21:12 +02:00
|
|
|
self.__playback_history = PlaybackHistory( self.get_playback_history_filename())
|
2006-01-09 00:52:40 +01:00
|
|
|
self.loadConfig()
|
2005-11-21 19:21:25 +01:00
|
|
|
|
|
|
|
def createIfNecessary( self, path):
|
|
|
|
if not exists( path):
|
2006-04-14 14:56:16 +02:00
|
|
|
try:
|
|
|
|
makedirs( path)
|
|
|
|
return True
|
|
|
|
except:
|
2006-11-17 15:26:10 +01:00
|
|
|
log( 'Could not create %s', path)
|
2006-04-14 14:56:16 +02:00
|
|
|
return False
|
|
|
|
|
|
|
|
return True
|
2005-11-21 19:21:25 +01:00
|
|
|
|
|
|
|
def getConfigFilename( self):
|
2006-01-09 00:52:40 +01:00
|
|
|
return self.gpodderdir + "gpodder.conf"
|
2006-04-05 21:07:05 +02:00
|
|
|
|
2005-11-21 19:21:25 +01:00
|
|
|
def getChannelsFilename( self):
|
|
|
|
return self.gpodderdir + "channels.xml"
|
2006-02-04 18:29:17 +01:00
|
|
|
|
2006-12-08 21:58:30 +01:00
|
|
|
def get_download_history_filename( self):
|
|
|
|
return self.gpodderdir + 'download-history.txt'
|
|
|
|
|
2007-04-03 13:21:12 +02:00
|
|
|
def get_playback_history_filename( self):
|
|
|
|
return self.gpodderdir + 'playback-history.txt'
|
|
|
|
|
2006-01-09 00:52:40 +01:00
|
|
|
def propertiesChanged( self):
|
2006-04-05 21:07:05 +02:00
|
|
|
# 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
|
2006-01-09 00:52:40 +01:00
|
|
|
# save settings for next startup
|
|
|
|
self.saveConfig()
|
|
|
|
|
2007-02-03 11:48:32 +01:00
|
|
|
def clean_up_downloads( self, delete_partial = False):
|
2006-12-03 19:11:14 +01:00
|
|
|
# Clean up temporary files left behind by old gPodder versions
|
2007-02-03 11:48:32 +01:00
|
|
|
if delete_partial:
|
|
|
|
temporary_files = glob( '%s/*/.tmp-*' % ( self.downloaddir, ))
|
|
|
|
for tempfile in temporary_files:
|
|
|
|
self.deleteFilename( tempfile)
|
2006-12-03 19:11:14 +01:00
|
|
|
|
|
|
|
# Clean up empty download folders
|
|
|
|
download_dirs = glob( '%s/*' % ( self.downloaddir, ))
|
|
|
|
for ddir in download_dirs:
|
|
|
|
if isdir( ddir):
|
|
|
|
globr = glob( '%s/*' % ( ddir, ))
|
2007-04-09 21:40:36 +02:00
|
|
|
if not globr and ddir != self.torrentdir:
|
2006-12-03 19:11:14 +01:00
|
|
|
log( 'Stale download directory found: %s', basename( ddir))
|
|
|
|
try:
|
|
|
|
rmdir( ddir)
|
|
|
|
log( 'Successfully removed %s.', ddir)
|
|
|
|
except:
|
|
|
|
log( 'Could not remove %s.', ddir)
|
|
|
|
|
2006-01-09 00:52:40 +01:00
|
|
|
def saveConfig( self):
|
2006-04-05 21:07:05 +02:00
|
|
|
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)
|
2006-04-07 20:11:31 +02:00
|
|
|
self.write_to_parser( parser, 'ipod_mount', self.ipod_mount)
|
2006-05-01 23:12:34 +02:00
|
|
|
self.write_to_parser( parser, 'update_on_startup', self.update_on_startup)
|
2007-03-08 15:04:05 +01:00
|
|
|
self.write_to_parser( parser, 'download_after_update', self.download_after_update)
|
2007-04-09 21:40:36 +02:00
|
|
|
self.write_to_parser( parser, 'limit_rate', self.limit_rate)
|
|
|
|
self.write_to_parser( parser, 'limit_rate_value', self.limit_rate_value)
|
2007-04-03 13:21:12 +02:00
|
|
|
self.write_to_parser( parser, 'show_played', self.show_played)
|
2007-03-15 22:33:23 +01:00
|
|
|
self.write_to_parser( parser, 'update_tags', self.update_tags)
|
2006-06-13 23:00:31 +02:00
|
|
|
self.write_to_parser( parser, 'opml_url', self.opml_url)
|
2006-12-06 21:25:26 +01:00
|
|
|
self.write_to_parser( parser, 'download_dir', self.downloaddir)
|
2007-04-09 21:40:36 +02:00
|
|
|
self.write_to_parser( parser, 'bittorrent_dir', self.torrentdir)
|
|
|
|
self.write_to_parser( parser, 'use_gnome_bittorrent', self.use_gnome_bittorrent)
|
2006-12-06 21:25:26 +01:00
|
|
|
self.write_to_parser( parser, 'device_type', self.device_type)
|
2007-04-01 19:53:04 +02:00
|
|
|
self.write_to_parser( parser, 'main_window_width', self.main_window_width)
|
2007-05-01 22:01:51 +02:00
|
|
|
self.write_to_parser( parser, 'max_downloads', self.max_downloads)
|
|
|
|
self.write_to_parser( parser, 'max_downloads_enabled', self.max_downloads_enabled)
|
2007-07-05 23:07:16 +02:00
|
|
|
self.write_to_parser( parser, 'default_new', self.default_new)
|
2007-04-01 19:53:04 +02:00
|
|
|
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)
|
2007-07-05 23:07:16 +02:00
|
|
|
self.write_to_parser( parser, 'paned_position', self.paned_position)
|
2006-12-06 21:25:26 +01:00
|
|
|
self.write_to_parser( parser, 'mp3_player_folder', self.mp3_player_folder)
|
2007-04-23 17:18:31 +02:00
|
|
|
self.write_to_parser( parser, 'only_sync_not_played', self.only_sync_not_played)
|
2006-01-09 00:52:40 +01:00
|
|
|
fn = self.getConfigFilename()
|
|
|
|
fp = open( fn, "w")
|
2006-04-05 21:07:05 +02:00
|
|
|
parser.write( fp)
|
2006-01-09 00:52:40 +01:00
|
|
|
fp.close()
|
2006-04-05 21:07:05 +02:00
|
|
|
|
2007-03-07 15:53:05 +01:00
|
|
|
def sanitize_feed_url( self, url):
|
2007-03-09 20:08:43 +01:00
|
|
|
if not url or len(url) < 7:
|
|
|
|
return None
|
|
|
|
|
|
|
|
if url[:4] == 'feed':
|
2007-03-07 15:53:05 +01:00
|
|
|
url = 'http' + url[4:]
|
|
|
|
|
2007-03-09 20:08:43 +01:00
|
|
|
if url[:4] == 'http' or result[:3] == 'ftp':
|
2007-03-07 15:53:05 +01:00
|
|
|
return url
|
2007-03-09 20:08:43 +01:00
|
|
|
|
|
|
|
return None
|
2007-03-07 15:53:05 +01:00
|
|
|
|
2007-05-21 11:54:48 +02:00
|
|
|
def escape_html( self, s):
|
|
|
|
return s.replace( '&', '&').replace( '<', '<').replace( '>', '>')
|
|
|
|
|
2006-12-06 21:25:26 +01:00
|
|
|
def get_download_dir( self):
|
2007-01-15 19:11:44 +01:00
|
|
|
self.createIfNecessary( self.__download_dir)
|
2006-12-06 21:25:26 +01:00
|
|
|
return self.__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)
|
|
|
|
try:
|
|
|
|
# Save state of Symlink on Desktop
|
|
|
|
generate_symlink = False
|
|
|
|
if self.getDesktopSymlink():
|
|
|
|
log( 'Desktop symlink exists before move.')
|
|
|
|
generate_symlink = True
|
|
|
|
|
2006-12-20 17:38:36 +01:00
|
|
|
# Fix error when moving over disk boundaries
|
|
|
|
if isdir( new_downloaddir) and not listdir( new_downloaddir):
|
|
|
|
rmdir( new_downloaddir)
|
|
|
|
|
2006-12-06 21:25:26 +01:00
|
|
|
shutil.move( self.__download_dir, new_downloaddir)
|
|
|
|
|
|
|
|
if generate_symlink:
|
|
|
|
# Re-generate Symlink on Desktop
|
|
|
|
log( 'Will re-generate desktop symlink to %s.', new_downloaddir)
|
|
|
|
self.removeDesktopSymlink()
|
|
|
|
self.__download_dir = new_downloaddir
|
|
|
|
self.createDesktopSymlink()
|
|
|
|
except:
|
|
|
|
log( 'Error while moving %s to %s.', self.__download_dir, new_downloaddir)
|
|
|
|
return
|
|
|
|
|
|
|
|
self.__download_dir = new_downloaddir
|
|
|
|
|
|
|
|
downloaddir = property(fget=get_download_dir,fset=set_download_dir)
|
|
|
|
|
2006-12-08 21:58:30 +01:00
|
|
|
def history_mark_downloaded( self, url):
|
2007-04-03 13:21:12 +02:00
|
|
|
self.__download_history.add_item( url)
|
|
|
|
|
|
|
|
def history_mark_played( self, url):
|
|
|
|
self.__playback_history.add_item( url)
|
2006-12-08 21:58:30 +01:00
|
|
|
|
2007-03-03 14:10:21 +01:00
|
|
|
def can_write_directory( self, directory):
|
|
|
|
return isdir( directory) and access( directory, W_OK)
|
|
|
|
|
2006-12-08 21:58:30 +01:00
|
|
|
def history_is_downloaded( self, url):
|
|
|
|
return (url in self.__download_history)
|
|
|
|
|
2007-04-03 13:21:12 +02:00
|
|
|
def history_is_played( self, url):
|
|
|
|
return (url in self.__playback_history)
|
|
|
|
|
2006-04-05 21:07:05 +02:00
|
|
|
def get_from_parser( self, parser, option, default = ''):
|
|
|
|
try:
|
|
|
|
result = parser.get( self.gpodderconf_section, option)
|
|
|
|
return result
|
|
|
|
except:
|
|
|
|
return default
|
|
|
|
|
2007-04-01 19:53:04 +02:00
|
|
|
def get_int_from_parser( self, parser, option, default = 0):
|
|
|
|
try:
|
|
|
|
result = int(parser.get( self.gpodderconf_section, option))
|
|
|
|
return result
|
|
|
|
except:
|
|
|
|
return default
|
|
|
|
|
2007-04-09 21:40:36 +02:00
|
|
|
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
|
|
|
|
|
2006-04-05 21:07:05 +02:00
|
|
|
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:
|
2006-11-17 15:26:10 +01:00
|
|
|
log( 'write_to_parser: could not write config (option=%s, value=%s)', option, value)
|
2006-01-09 00:52:40 +01:00
|
|
|
|
|
|
|
def loadConfig( self):
|
2006-04-05 21:07:05 +02:00
|
|
|
was_oldstyle = False
|
2006-01-09 00:52:40 +01:00
|
|
|
try:
|
|
|
|
fn = self.getConfigFilename()
|
2006-04-05 21:07:05 +02:00
|
|
|
if open(fn,'r').read(1) != '[':
|
2006-11-17 15:26:10 +01:00
|
|
|
log( 'seems like old-style config. trying to read it anyways..')
|
2006-04-05 21:07:05 +02:00
|
|
|
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')
|
2006-06-13 23:00:31 +02:00
|
|
|
opml_url = self.get_from_parser( parser, 'opml_url', default_opml_directory)
|
2006-04-05 21:10:35 +02:00
|
|
|
self.proxy_use_environment = self.get_boolean_from_parser( parser, 'proxy_use_env', True)
|
2006-12-06 21:25:26 +01:00
|
|
|
self.ipod_mount = self.get_from_parser( parser, 'ipod_mount', '/media/ipod')
|
2006-05-01 23:12:34 +02:00
|
|
|
self.update_on_startup = self.get_boolean_from_parser(parser, 'update_on_startup', default=False)
|
2007-03-08 15:04:05 +01:00
|
|
|
self.download_after_update = self.get_boolean_from_parser(parser, 'download_after_update', default=False)
|
2007-04-09 21:40:36 +02:00
|
|
|
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)
|
2007-04-03 13:21:12 +02:00
|
|
|
self.show_played = self.get_boolean_from_parser(parser, 'show_played', default=False)
|
2007-03-15 22:33:23 +01:00
|
|
|
self.update_tags = self.get_boolean_from_parser(parser, 'update_tags', default=False)
|
2007-01-15 19:11:44 +01:00
|
|
|
self.downloaddir = self.get_from_parser( parser, 'download_dir', expanduser('~/gpodder-downloads'))
|
2007-04-09 21:40:36 +02:00
|
|
|
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)
|
2006-12-06 21:25:26 +01:00
|
|
|
self.device_type = self.get_from_parser( parser, 'device_type', 'none')
|
2007-04-01 19:53:04 +02:00
|
|
|
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)
|
2007-07-05 23:07:16 +02:00
|
|
|
self.paned_position = self.get_int_from_parser( parser, 'paned_position', 0)
|
2007-05-01 22:01:51 +02:00
|
|
|
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)
|
2007-07-05 23:07:16 +02:00
|
|
|
self.default_new = self.get_int_from_parser( parser, 'default_new', 1)
|
2006-12-06 21:25:26 +01:00
|
|
|
self.mp3_player_folder = self.get_from_parser( parser, 'mp3_player_folder', '/media/usbdisk')
|
2007-04-23 17:18:31 +02:00
|
|
|
self.only_sync_not_played = self.get_boolean_from_parser(parser, 'only_sync_not_played', default=False)
|
2006-04-05 21:07:05 +02:00
|
|
|
else:
|
2006-11-17 15:26:10 +01:00
|
|
|
log( 'config file %s has no section %s', fn, gpodderconf_section)
|
2006-04-05 21:07:05 +02:00
|
|
|
if not self.proxy_use_environment:
|
2006-01-09 00:52:40 +01:00
|
|
|
self.http_proxy = strip( http)
|
|
|
|
self.ftp_proxy = strip( ftp)
|
2006-04-05 21:07:05 +02:00
|
|
|
if strip( app) != '':
|
2006-02-04 18:29:17 +01:00
|
|
|
self.open_app = strip( app)
|
|
|
|
else:
|
2006-04-05 21:07:05 +02:00
|
|
|
self.open_app = 'gnome-open'
|
2006-06-13 23:00:31 +02:00
|
|
|
if strip( opml_url) != '':
|
|
|
|
self.opml_url = strip( opml_url)
|
|
|
|
else:
|
|
|
|
self.opml_url = default_opml_directory
|
2006-01-09 00:52:40 +01:00
|
|
|
except:
|
2006-02-04 18:29:17 +01:00
|
|
|
# TODO: well, well.. (http + ftp?)
|
2006-04-05 21:07:05 +02:00
|
|
|
self.open_app = 'gnome-open'
|
2006-12-06 21:25:26 +01:00
|
|
|
self.ipod_mount = '/media/ipod'
|
|
|
|
self.device_type = 'none'
|
2007-04-01 19:53:04 +02:00
|
|
|
self.main_window_width = 600
|
|
|
|
self.main_window_height = 450
|
|
|
|
self.main_window_x = 0
|
|
|
|
self.main_window_y = 0
|
2007-07-05 23:07:16 +02:00
|
|
|
self.paned_position = 0
|
2006-12-06 21:25:26 +01:00
|
|
|
self.mp3_player_folder = '/media/usbdisk'
|
2006-06-13 23:00:31 +02:00
|
|
|
self.opml_url = default_opml_directory
|
2007-01-15 19:11:44 +01:00
|
|
|
self.downloaddir = expanduser('~/gpodder-downloads')
|
2007-04-09 21:40:36 +02:00
|
|
|
self.torrentdir = expanduser('~/gpodder-downloads/torrents')
|
|
|
|
self.use_gnome_bittorrent = True
|
2006-04-05 21:07:05 +02:00
|
|
|
if was_oldstyle:
|
|
|
|
self.saveConfig()
|
2006-02-04 18:29:17 +01:00
|
|
|
|
2007-04-03 13:21:12 +02:00
|
|
|
def playback_episode( self, channel, episode):
|
|
|
|
self.history_mark_played( episode.url)
|
|
|
|
filename = channel.getPodcastFilename( episode.url)
|
|
|
|
|
2006-11-17 15:26:10 +01:00
|
|
|
log( 'Opening %s (with %s)', filename, self.open_app)
|
2006-06-13 20:52:25 +02:00
|
|
|
|
|
|
|
# use libplayers to create a commandline out of open_app plus filename, then exec in background ('&')
|
|
|
|
system( '%s &' % dotdesktop_command( self.open_app, filename))
|
2006-03-03 21:04:25 +01:00
|
|
|
|
2006-03-29 15:24:44 +02:00
|
|
|
def getDesktopSymlink( self):
|
2006-03-31 18:20:18 +02:00
|
|
|
symlink_path = expanduser( "~/Desktop/%s" % self.desktop_link)
|
2006-12-06 21:25:26 +01:00
|
|
|
try:
|
|
|
|
return lexists( symlink_path)
|
|
|
|
except:
|
|
|
|
return exists( symlink_path)
|
2006-03-29 15:24:44 +02:00
|
|
|
|
2006-12-20 17:38:36 +01:00
|
|
|
def get_size( self, filename):
|
2007-04-02 14:14:38 +02:00
|
|
|
if dirname( filename) == '/':
|
|
|
|
return 0L
|
2006-12-20 17:38:36 +01:00
|
|
|
if isfile( filename):
|
|
|
|
return getsize( filename)
|
|
|
|
elif isdir( filename):
|
|
|
|
sum = getsize( filename)
|
|
|
|
for item in listdir( filename):
|
2007-04-02 14:14:38 +02:00
|
|
|
try:
|
|
|
|
sum = sum + self.get_size( join( filename, item))
|
|
|
|
except:
|
|
|
|
return 0L
|
2006-12-20 17:38:36 +01:00
|
|
|
return sum
|
|
|
|
else:
|
|
|
|
log( 'Cannot get size for %s' % ( filename, ))
|
|
|
|
return 0L
|
|
|
|
|
|
|
|
def size_to_string( self, size, method = None):
|
|
|
|
methods = {
|
|
|
|
'GB': 1073741824.0,
|
|
|
|
'MB': 1048576.0,
|
|
|
|
'KB': 1024.0,
|
|
|
|
'B': 1.0,
|
|
|
|
}
|
|
|
|
|
|
|
|
size = float(size)
|
|
|
|
|
|
|
|
if method not in methods:
|
|
|
|
method = 'B'
|
|
|
|
for trying in ( 'KB', 'MB', 'GB'):
|
|
|
|
if size >= methods[trying]:
|
|
|
|
method = trying
|
|
|
|
|
|
|
|
return '%.2f %s' % ( size / methods[method], method, )
|
|
|
|
|
2006-03-29 15:24:44 +02:00
|
|
|
def createDesktopSymlink( self):
|
|
|
|
if not self.getDesktopSymlink():
|
|
|
|
downloads_path = expanduser( "~/Desktop/")
|
|
|
|
self.createIfNecessary( downloads_path)
|
2006-03-31 18:20:18 +02:00
|
|
|
symlink( self.downloaddir, "%s%s" % (downloads_path, self.desktop_link))
|
2006-03-29 15:24:44 +02:00
|
|
|
|
|
|
|
def removeDesktopSymlink( self):
|
|
|
|
if self.getDesktopSymlink():
|
2006-03-31 18:20:18 +02:00
|
|
|
unlink( expanduser( "~/Desktop/%s" % self.desktop_link))
|
|
|
|
|
|
|
|
def image_download_thread( self, url, callback_pixbuf = None, callback_status = None, callback_finished = None, cover_file = None):
|
|
|
|
if callback_status != None:
|
2007-07-05 23:07:16 +02:00
|
|
|
gobject.idle_add( callback_status, _('Downloading channel cover...'))
|
2006-03-31 18:20:18 +02:00
|
|
|
pixbuf = PixbufLoader()
|
|
|
|
|
|
|
|
if cover_file == None:
|
2006-11-17 15:26:10 +01:00
|
|
|
log( 'Downloading %s', url)
|
2006-03-31 18:20:18 +02:00
|
|
|
pixbuf.write( urllib.urlopen(url).read())
|
|
|
|
|
|
|
|
if cover_file != None and not exists( cover_file):
|
2006-11-17 15:26:10 +01:00
|
|
|
log( 'Downloading cover to %s', cover_file)
|
2006-03-31 18:20:18 +02:00
|
|
|
cachefile = open( cover_file, "w")
|
|
|
|
cachefile.write( urllib.urlopen(url).read())
|
|
|
|
cachefile.close()
|
|
|
|
|
|
|
|
if cover_file != None:
|
2006-11-17 15:26:10 +01:00
|
|
|
log( 'Reading cover from %s', cover_file)
|
2006-03-31 18:20:18 +02:00
|
|
|
pixbuf.write( open( cover_file, "r").read())
|
|
|
|
|
|
|
|
try:
|
|
|
|
pixbuf.close()
|
|
|
|
except:
|
|
|
|
# data error, delete temp file
|
|
|
|
self.deleteFilename( cover_file)
|
|
|
|
|
2007-07-05 23:07:16 +02:00
|
|
|
MAX_SIZE = 400
|
2006-03-31 18:20:18 +02:00
|
|
|
if callback_pixbuf != None:
|
2007-07-05 23:07:16 +02:00
|
|
|
pb = pixbuf.get_pixbuf()
|
|
|
|
if pb:
|
|
|
|
if pb.get_width() > MAX_SIZE:
|
|
|
|
factor = MAX_SIZE*1.0/pb.get_width()
|
|
|
|
pb = pb.scale_simple( int(pb.get_width()*factor), int(pb.get_height()*factor), gtk.gdk.INTERP_BILINEAR)
|
|
|
|
if pb.get_height() > MAX_SIZE:
|
|
|
|
factor = MAX_SIZE*1.0/pb.get_height()
|
|
|
|
pb = pb.scale_simple( int(pb.get_width()*factor), int(pb.get_height()*factor), gtk.gdk.INTERP_BILINEAR)
|
|
|
|
gobject.idle_add( callback_pixbuf, pb)
|
2006-03-31 18:20:18 +02:00
|
|
|
if callback_status != None:
|
2007-07-05 23:07:16 +02:00
|
|
|
gobject.idle_add( callback_status, '')
|
2006-03-31 18:20:18 +02:00
|
|
|
if callback_finished != None:
|
2007-07-05 23:07:16 +02:00
|
|
|
gobject.idle_add( callback_finished)
|
2006-03-31 18:20:18 +02:00
|
|
|
|
|
|
|
def get_image_from_url( self, url, callback_pixbuf = None, callback_status = None, callback_finished = None, cover_file = None):
|
2007-07-05 23:07:16 +02:00
|
|
|
if not url:
|
|
|
|
return
|
|
|
|
|
2006-03-31 18:20:18 +02:00
|
|
|
args = ( url, callback_pixbuf, callback_status, callback_finished, cover_file )
|
|
|
|
thread = threading.Thread( target = self.image_download_thread, args = args)
|
|
|
|
thread.start()
|
2006-03-29 15:24:44 +02:00
|
|
|
|
2006-03-24 20:08:59 +01:00
|
|
|
def deleteFilename( self, filename):
|
2006-11-17 15:26:10 +01:00
|
|
|
log( 'deleteFilename: %s', filename)
|
2006-03-29 13:51:25 +02:00
|
|
|
try:
|
|
|
|
unlink( filename)
|
2006-11-30 23:15:17 +01:00
|
|
|
# if libipodsync extracted the cover file, remove it here
|
|
|
|
cover_filename = filename + '.cover.jpg'
|
|
|
|
if isfile( cover_filename):
|
|
|
|
unlink( cover_filename)
|
2006-03-29 13:51:25 +02:00
|
|
|
except:
|
|
|
|
# silently ignore
|
|
|
|
pass
|
2007-04-09 21:40:36 +02:00
|
|
|
|
|
|
|
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))
|
|
|
|
log( command, sender = self)
|
|
|
|
system( '%s &' % command)
|
|
|
|
else:
|
|
|
|
# Simply copy the .torrent with a suitable name
|
|
|
|
try:
|
|
|
|
target_filename = join( self.torrentdir, splitext( target_filename)[0] + '.torrent')
|
|
|
|
shutil.copyfile( torrent_filename, target_filename)
|
|
|
|
except:
|
|
|
|
log( 'Torrent copy failed: %s => %s.', torrent_filename, target_filename)
|
2006-03-24 20:08:59 +01:00
|
|
|
|
2005-11-21 19:21:25 +01:00
|
|
|
class gPodderChannelWriter( object):
|
|
|
|
def write( self, channels):
|
|
|
|
filename = gPodderLib().getChannelsFilename()
|
|
|
|
fd = open( filename, "w")
|
2006-03-31 18:20:18 +02:00
|
|
|
print >> fd, '<!-- '+_('gPodder channel list')+' -->'
|
2006-03-03 21:04:25 +01:00
|
|
|
print >> fd, '<channels>'
|
2005-11-21 19:21:25 +01:00
|
|
|
for chan in channels:
|
2006-12-13 14:00:55 +01:00
|
|
|
try:
|
|
|
|
print >> fd, " <channel>\n <url>%s</url>\n </channel>\n" % saxutils.escape( chan.url)
|
|
|
|
except:
|
|
|
|
log( 'Could not write channels to file.')
|
2006-03-03 21:04:25 +01:00
|
|
|
print >> fd, '</channels>'
|
2005-11-21 19:21:25 +01:00
|
|
|
fd.close()
|
|
|
|
|
|
|
|
class gPodderChannelReader( DefaultHandler):
|
|
|
|
def __init__( self):
|
2007-01-06 14:48:46 +01:00
|
|
|
self.channels = []
|
|
|
|
self.current_item = None
|
|
|
|
self.current_element_data = ''
|
2007-03-10 16:57:56 +01:00
|
|
|
self.is_cancelled = False
|
|
|
|
|
|
|
|
def cancel( self):
|
|
|
|
self.is_cancelled = True
|
|
|
|
|
|
|
|
def callback_is_cancelled( self):
|
|
|
|
return self.is_cancelled
|
2005-11-21 19:21:25 +01:00
|
|
|
|
2007-03-08 11:48:09 +01:00
|
|
|
def read( self, force_update = False, callback_proc = None, callback_url = None, callback_error = None):
|
2006-12-06 21:25:26 +01:00
|
|
|
"""Read channels from a file into gPodder's cache
|
|
|
|
|
|
|
|
force_update: When true, re-download even if the cache file
|
|
|
|
already exists locally
|
|
|
|
|
|
|
|
callback_proc: A function that takes two integer parameters,
|
|
|
|
the first being the number of the currently
|
|
|
|
processed item and the second being the count
|
|
|
|
of the items that will be read/updated.
|
2007-03-07 15:53:05 +01:00
|
|
|
|
|
|
|
callback_url: A function that takes one string parameter
|
|
|
|
that contains the URL of the channel that
|
|
|
|
is being updated at the moment. Will be
|
|
|
|
called for every channel to be updated.
|
2007-03-08 11:48:09 +01:00
|
|
|
|
|
|
|
callback_error: A function that takes one string parameter
|
|
|
|
that contains a error message to be displayed.
|
2006-12-06 21:25:26 +01:00
|
|
|
"""
|
|
|
|
|
2005-11-21 19:21:25 +01:00
|
|
|
self.channels = []
|
2006-12-06 21:25:26 +01:00
|
|
|
|
2005-11-21 19:21:25 +01:00
|
|
|
parser = make_parser()
|
|
|
|
parser.setContentHandler( self)
|
2006-12-06 21:25:26 +01:00
|
|
|
|
2005-11-21 19:21:25 +01:00
|
|
|
if exists( gPodderLib().getChannelsFilename()):
|
|
|
|
parser.parse( gPodderLib().getChannelsFilename())
|
|
|
|
else:
|
|
|
|
return []
|
2006-12-06 21:25:26 +01:00
|
|
|
|
2005-11-21 19:21:25 +01:00
|
|
|
reader = rssReader()
|
|
|
|
input_channels = []
|
|
|
|
|
2006-07-14 22:09:00 +02:00
|
|
|
channel_count = len( self.channels)
|
|
|
|
position = 0
|
2005-11-21 19:21:25 +01:00
|
|
|
for channel in self.channels:
|
2007-03-07 15:53:05 +01:00
|
|
|
if callback_proc:
|
2006-07-14 22:09:00 +02:00
|
|
|
callback_proc( position, channel_count)
|
|
|
|
|
2007-03-07 15:53:05 +01:00
|
|
|
if callback_url:
|
|
|
|
callback_url( channel.url)
|
|
|
|
|
2007-03-10 16:57:56 +01:00
|
|
|
cachefile = channel.downloadRss( force_update, callback_error = callback_error, callback_is_cancelled = self.callback_is_cancelled)
|
2006-03-29 13:51:25 +02:00
|
|
|
# check if download was a success
|
|
|
|
if cachefile != None:
|
2006-12-06 21:25:26 +01:00
|
|
|
reader.parseXML( channel.url, cachefile)
|
2007-01-06 14:48:46 +01:00
|
|
|
if reader.channel != None:
|
2007-03-08 13:11:10 +01:00
|
|
|
reader.channel.set_metadata_from_localdb()
|
2007-01-06 14:48:46 +01:00
|
|
|
input_channels.append( reader.channel)
|
2006-07-14 22:09:00 +02:00
|
|
|
|
|
|
|
position = position + 1
|
|
|
|
|
|
|
|
# the last call sets everything to 100% (hopefully ;)
|
|
|
|
if callback_proc != None:
|
|
|
|
callback_proc( position, channel_count)
|
2005-11-21 19:21:25 +01:00
|
|
|
|
|
|
|
return input_channels
|
|
|
|
|
|
|
|
def startElement( self, name, attrs):
|
|
|
|
self.current_element_data = ""
|
|
|
|
|
2006-12-06 21:25:26 +01:00
|
|
|
if name == 'channel':
|
2006-03-03 21:04:25 +01:00
|
|
|
self.current_item = podcastChannel()
|
2005-11-21 19:21:25 +01:00
|
|
|
|
|
|
|
def endElement( self, name):
|
|
|
|
if self.current_item != None:
|
2006-12-06 21:25:26 +01:00
|
|
|
if name == 'url':
|
2005-11-21 19:21:25 +01:00
|
|
|
self.current_item.url = self.current_element_data
|
2006-12-06 21:25:26 +01:00
|
|
|
if name == 'channel':
|
2005-11-21 19:21:25 +01:00
|
|
|
self.channels.append( self.current_item)
|
|
|
|
self.current_item = None
|
|
|
|
|
|
|
|
def characters( self, ch):
|
|
|
|
self.current_element_data = self.current_element_data + ch
|
|
|
|
|
|
|
|
|