Win32-specific changes and bugfixes (bug 247, 442)
This patch merges all the win32-specific changes that have been done to gPodder so far and also adds some generic bugfixes that will benefit other versions of gPodder, too. Thanks to Stefan Koegl and David Greenbaum for testing.
This commit is contained in:
parent
952ea28548
commit
de3750e190
|
@ -25,6 +25,7 @@ __licence__ = 'GNU General Public License, version 3 or later'
|
|||
__url__ = 'http://gpodder.org/'
|
||||
|
||||
import sys
|
||||
import platform
|
||||
import gettext
|
||||
|
||||
# Check if real hard dependencies are available
|
||||
|
@ -66,3 +67,6 @@ del t
|
|||
ui_folder = None
|
||||
icon_file = None
|
||||
|
||||
# Set "win32" to True if we are on Windows
|
||||
win32 = (platform.system() == 'Windows')
|
||||
|
||||
|
|
|
@ -42,7 +42,7 @@ _ = gpodder.gettext
|
|||
if gpodder.interface == gpodder.MAEMO:
|
||||
default_download_dir = '/media/mmc2/gpodder'
|
||||
else:
|
||||
default_download_dir = os.path.expanduser('~/gpodder-downloads')
|
||||
default_download_dir = os.path.join(os.path.expanduser('~'), 'gpodder-downloads')
|
||||
|
||||
gPodderSettings = {
|
||||
# General settings
|
||||
|
|
|
@ -30,10 +30,6 @@ import time
|
|||
import urllib
|
||||
import urllib2
|
||||
import datetime
|
||||
import dbus
|
||||
import dbus.service
|
||||
import dbus.mainloop
|
||||
import dbus.glib
|
||||
|
||||
from xml.sax import saxutils
|
||||
|
||||
|
@ -43,6 +39,33 @@ from threading import Semaphore
|
|||
from string import strip
|
||||
|
||||
import gpodder
|
||||
|
||||
if gpodder.win32:
|
||||
# Mock the required D-Bus interfaces with no-ops
|
||||
class dbus:
|
||||
class SessionBus:
|
||||
def __init__(self, *args, **kwargs):
|
||||
pass
|
||||
class glib:
|
||||
class DBusGMainLoop:
|
||||
pass
|
||||
class service:
|
||||
@staticmethod
|
||||
def method(interface):
|
||||
return lambda x: x
|
||||
class BusName:
|
||||
def __init__(self, *args, **kwargs):
|
||||
pass
|
||||
class Object:
|
||||
def __init__(self, *args, **kwargs):
|
||||
pass
|
||||
else:
|
||||
import dbus
|
||||
import dbus.service
|
||||
import dbus.mainloop
|
||||
import dbus.glib
|
||||
|
||||
|
||||
from gpodder import libtagupdate
|
||||
from gpodder import util
|
||||
from gpodder import opml
|
||||
|
@ -436,6 +459,10 @@ class gPodder(BuilderWidget, dbus.service.Object):
|
|||
self.gPodder.connect('key-press-event', self.on_key_press)
|
||||
self.treeChannels.connect('size-allocate', self.on_tree_channels_resize)
|
||||
|
||||
if gpodder.win32:
|
||||
# FIXME: Implement e-mail sending of list in win32
|
||||
self.item_email_subscriptions.set_sensitive(False)
|
||||
|
||||
if gl.config.show_url_entry_in_podcast_list:
|
||||
self.hboxAddChannel.show()
|
||||
|
||||
|
@ -2207,6 +2234,9 @@ class gPodder(BuilderWidget, dbus.service.Object):
|
|||
|
||||
self.gPodder.hide()
|
||||
|
||||
if self.tray_icon is not None:
|
||||
self.tray_icon.set_visible(False)
|
||||
|
||||
# Notify all tasks to to carry out any clean-up actions
|
||||
self.download_status_manager.tell_all_tasks_to_quit()
|
||||
|
||||
|
@ -4130,7 +4160,7 @@ class gPodderOpmlLister(BuilderWidget):
|
|||
self.notification(_('There are no YouTube channels that would match this query.'), _('No channels found'))
|
||||
else:
|
||||
url = self.entryURL.get_text()
|
||||
if not url.lower().startswith('http://'):
|
||||
if not os.path.isfile(url) and not url.lower().startswith('http://'):
|
||||
log('Using podcast.de search')
|
||||
url = 'http://api.podcast.de/opml/podcasts/suche/%s' % (urllib.quote(url),)
|
||||
model = opml.Importer(url).get_model()
|
||||
|
|
|
@ -0,0 +1,66 @@
|
|||
#!/usr/bin/env python
|
||||
# -*- coding: utf-8 -*-
|
||||
|
||||
#
|
||||
# gPodder - A media aggregator and podcast client
|
||||
# Copyright (c) 2005-2009 Thomas Perl and the gPodder Team
|
||||
#
|
||||
# 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/>.
|
||||
#
|
||||
|
||||
"""Win32 Launcher script for gPodder
|
||||
|
||||
This is only used for the Win32 version of gPodder
|
||||
and will set up the environment to find all files
|
||||
and then start up the gPodder GUI.
|
||||
|
||||
Thomas Perl <thpinfo.com>; 2009-05-09
|
||||
"""
|
||||
|
||||
import sys
|
||||
import os
|
||||
import os.path
|
||||
import platform
|
||||
|
||||
import gettext
|
||||
|
||||
if __name__ == '__main__':
|
||||
prefix = os.path.abspath(os.path.normpath('.'))
|
||||
data_dir = os.path.join(prefix, 'data')
|
||||
|
||||
locale_dir = os.path.join(data_dir, 'locale')
|
||||
ui_folder = os.path.join(data_dir, 'ui')
|
||||
icon_file = os.path.join(data_dir, 'gpodder.svg')
|
||||
|
||||
# Set up the path to translation files
|
||||
gettext.bindtextdomain('gpodder', locale_dir)
|
||||
|
||||
import gpodder
|
||||
|
||||
if not gpodder.win32:
|
||||
print >>sys.stderr, 'This launcher is only for Win32.'
|
||||
sys.exit(1)
|
||||
|
||||
# Enable i18n for gPodder translations
|
||||
_ = gpodder.gettext
|
||||
|
||||
# Set up paths to folder with GtkBuilder files and gpodder.svg
|
||||
gpodder.ui_folder = ui_folder
|
||||
gpodder.icon_file = icon_file
|
||||
gpodder.interface = gpodder.GUI
|
||||
|
||||
from gpodder import gui
|
||||
|
||||
gui.main()
|
||||
|
|
@ -66,12 +66,14 @@ _ = gpodder.gettext
|
|||
if gpodder.interface == gpodder.MAEMO:
|
||||
ICON_AUDIO_FILE = 'gnome-mime-audio-mp3'
|
||||
ICON_VIDEO_FILE = 'gnome-mime-video-mp4'
|
||||
ICON_GENERIC_FILE = 'text-x-generic'
|
||||
ICON_DOWNLOADING = 'qgn_toolb_messagin_moveto'
|
||||
ICON_DELETED = 'qgn_toolb_gene_deletebutton'
|
||||
ICON_NEW = 'qgn_list_gene_favor'
|
||||
else:
|
||||
ICON_AUDIO_FILE = 'audio-x-generic'
|
||||
ICON_VIDEO_FILE = 'video-x-generic'
|
||||
ICON_GENERIC_FILE = 'text-x-generic'
|
||||
ICON_DOWNLOADING = gtk.STOCK_GO_DOWN
|
||||
ICON_DELETED = gtk.STOCK_DELETE
|
||||
ICON_NEW = gtk.STOCK_ABOUT
|
||||
|
@ -431,7 +433,7 @@ class PodcastChannel(PodcastModelObject):
|
|||
return db.load_episodes(self, factory=self.episode_factory)
|
||||
|
||||
def iter_set_downloading_columns(self, model, iter, episode=None, downloading=None):
|
||||
global ICON_AUDIO_FILE, ICON_VIDEO_FILE
|
||||
global ICON_AUDIO_FILE, ICON_VIDEO_FILE, ICON_GENERIC_FILE
|
||||
global ICON_DOWNLOADING, ICON_DELETED, ICON_NEW
|
||||
|
||||
if episode is None:
|
||||
|
@ -465,7 +467,7 @@ class PodcastChannel(PodcastModelObject):
|
|||
elif file_type == 'video':
|
||||
status_icon = util.get_tree_icon(ICON_VIDEO_FILE, not episode.is_played, episode.is_locked, not episode.file_exists(), self.icon_cache, icon_size)
|
||||
else:
|
||||
status_icon = util.get_tree_icon('unknown', not episode.is_played, episode.is_locked, not episode.file_exists(), self.icon_cache, icon_size)
|
||||
status_icon = util.get_tree_icon(ICON_GENERIC_FILE, not episode.is_played, episode.is_locked, not episode.file_exists(), self.icon_cache, icon_size)
|
||||
elif episode.state == db.STATE_DELETED or episode.state == db.STATE_DOWNLOADED:
|
||||
status_icon = util.get_tree_icon(ICON_DELETED, not episode.is_played, icon_cache=self.icon_cache, icon_size=icon_size)
|
||||
else:
|
||||
|
|
|
@ -48,6 +48,8 @@ import urllib
|
|||
import urllib2
|
||||
import os.path
|
||||
import os
|
||||
import platform
|
||||
import shutil
|
||||
|
||||
from email.Utils import formatdate
|
||||
import gpodder
|
||||
|
@ -76,15 +78,10 @@ class Importer(object):
|
|||
"""
|
||||
self.items = []
|
||||
try:
|
||||
if url.startswith('/'):
|
||||
# assume local filename
|
||||
if os.path.exists(url):
|
||||
doc = xml.dom.minidom.parse( url)
|
||||
else:
|
||||
log('Empty/non-existing OPML file', sender=self)
|
||||
return
|
||||
if os.path.exists(url):
|
||||
doc = xml.dom.minidom.parse(url)
|
||||
else:
|
||||
doc = xml.dom.minidom.parseString( self.read_url( url))
|
||||
doc = xml.dom.minidom.parseString(self.read_url(url))
|
||||
|
||||
for outline in doc.getElementsByTagName('outline'):
|
||||
if outline.getAttribute('type') in self.VALID_TYPES and outline.getAttribute('xmlUrl') or outline.getAttribute('url'):
|
||||
|
@ -206,15 +203,21 @@ class Exporter(object):
|
|||
# try to save the new file, but keep the old one so we
|
||||
# don't end up with a clobbed, empty opml file.
|
||||
FREE_DISK_SPACE_AFTER = 1024*512
|
||||
if util.get_free_disk_space(os.path.dirname(self.filename)) < 2*len(data)+FREE_DISK_SPACE_AFTER:
|
||||
available = util.get_free_disk_space(os.path.dirname(self.filename))
|
||||
if available < 2*len(data)+FREE_DISK_SPACE_AFTER and not gpodder.win32:
|
||||
# FIXME: get_free_disk_space still unimplemented for win32
|
||||
log('Not enough free disk space to save channel list to %s', self.filename, sender = self)
|
||||
return False
|
||||
fp = open(self.filename+'.tmp', 'w')
|
||||
fp.write(data)
|
||||
fp.close()
|
||||
os.rename(self.filename+'.tmp', self.filename)
|
||||
if gpodder.win32:
|
||||
# Win32 does not support atomic rename with os.rename
|
||||
shutil.move(self.filename+'.tmp', self.filename)
|
||||
else:
|
||||
os.rename(self.filename+'.tmp', self.filename)
|
||||
except:
|
||||
log( 'Could not open file for writing: %s', self.filename, sender = self)
|
||||
log('Could not open file for writing: %s', self.filename, sender=self, traceback=True)
|
||||
return False
|
||||
|
||||
return True
|
||||
|
|
|
@ -37,6 +37,7 @@ import gobject
|
|||
|
||||
import os
|
||||
import os.path
|
||||
import platform
|
||||
import glob
|
||||
import stat
|
||||
|
||||
|
@ -321,6 +322,10 @@ def get_free_disk_space(path):
|
|||
function returns zero.
|
||||
"""
|
||||
|
||||
if gpodder.win32:
|
||||
# FIXME: Implement for win32
|
||||
return 0
|
||||
|
||||
if not os.path.exists(path):
|
||||
return 0
|
||||
|
||||
|
@ -1018,12 +1023,14 @@ def get_episode_info_from_url(url, proxy=None):
|
|||
def gui_open(filename):
|
||||
"""
|
||||
Open a file or folder with the default application set
|
||||
by the Desktop environment. This uses "xdg-open".
|
||||
by the Desktop environment. This uses "xdg-open" on all
|
||||
systems except Win32, which uses os.startfile().
|
||||
"""
|
||||
try:
|
||||
subprocess.Popen(['xdg-open', filename])
|
||||
# FIXME: Win32-specific "open" code needed here
|
||||
# as fallback when xdg-open not available
|
||||
if gpodder.win32:
|
||||
os.startfile(filename)
|
||||
else:
|
||||
subprocess.Popen(['xdg-open', filename])
|
||||
return True
|
||||
except:
|
||||
log('Cannot open file/folder: "%s"', filename, traceback=True)
|
||||
|
|
Loading…
Reference in New Issue