Deprecate the old-style command-line interface

Add a interim "sync" command to the "gpo" utility
to replace all the functionality of the old "gpodder"
CLI parameters (which had a "--sync" switch).
This commit is contained in:
Thomas Perl 2009-08-13 21:03:01 +02:00
parent c854935fc9
commit 806c719c4b
4 changed files with 47 additions and 209 deletions

View file

@ -62,6 +62,7 @@
-------------------------------
device Show information about your device
sync Synchronize downloaded episodes to device
Helper commands
---------------
@ -93,6 +94,8 @@ if os.path.exists(src_dir) and os.path.exists(data_dir) and \
import gpodder
_ = gpodder.gettext
# This is the command-line interface to gPodder
gpodder.interface = gpodder.CLI
# Use only the gPodder API here, so this serves both as an example
# and as a motivation to provide all functionality in the API :)
@ -216,6 +219,9 @@ class gPodderCli(object):
print count, 'episodes downloaded.'
return True
def sync(self):
api.synchronize_device()
return True
# -------------------------------------------------------------------

View file

@ -21,10 +21,13 @@
"""
gPodder enables you to subscribe to RSS feeds and download
podcast episodes from these feeds. gPodder can operate in
GUI mode and in CLI mode. Downloaded podcasts can either
be synchronized to portable MP3 players (including iPods)
or played back on the user's desktop.
podcast episodes from these feeds.
Downloaded podcasts can either be synchronized to portable
MP3 players (including iPods) or played back on the user's
desktop.
See gpo(1) for the command-line interface.
"""
import sys
@ -91,53 +94,17 @@ if __name__ == '__main__':
action="store_true", dest="verbose", default=False,
help=_("Print debugging output to stdout"))
parser.add_option("-t", "--local",
action="store_true", dest="local", default=False,
help='Deprecated.')
parser.add_option("-m", "--maemo",
action="store_true", dest="maemo", default=False,
help=_("Start the Maemo user interface of gPodder"))
parser.add_option("-l", "--list",
action="store_true", dest="list", default=False,
help=_("List all channel subscriptions"))
parser.add_option("-r", "--run",
action="store_true", dest="run", default=False,
help=_("Update channel list, download new podcasts"))
parser.add_option("-u", "--update",
action="store_true", dest="update", default=False,
help=_("Update channel list and exit"))
parser.add_option("-s", "--sync",
action="store_true", dest="sync", default=False,
help=_("Synchronize channels to configured device"))
parser.add_option("-a", "--add", dest="add",
help=_("Subscribe to channel from URL"), metavar="URL")
parser.add_option("-d", "--delete", dest="delete",
help=_("Delete channel specified by URL"), metavar="URL")
parser.add_option("-S", "--stats",
action="store_true", dest="stats", default=False,
help=_("Get sync statistics"))
(options, args) = parser.parse_args(sys.argv)
if options.maemo:
gpodder.interface = gpodder.MAEMO
elif options.list or options.run or options.update or \
options.sync or options.add or options.delete:
gpodder.interface = gpodder.CLI
else:
gpodder.interface = gpodder.GUI
if options.local:
print >>sys.stderr, 'Ignoring deprecated option --local.'
if options.verbose:
from gpodder.liblogger import enable_verbose
enable_verbose()
@ -155,22 +122,7 @@ if __name__ == '__main__':
# No D-Bus available :/
remote_object = None
from gpodder import console
if options.list:
console.list_channels()
elif options.run:
console.run()
elif options.update:
console.update()
elif options.sync:
console.sync_device()
elif options.add:
console.add_channel( options.add)
elif options.delete:
console.del_channel( options.delete)
elif options.stats:
console.sync_stats()
elif remote_object is not None:
if remote_object is not None:
# An instance of GUI is already running
remote_object.show_gui_window(dbus_interface=gpodder.dbus_interface)
else:

View file

@ -30,6 +30,7 @@ from gpodder.libpodcasts import PodcastChannel
from gpodder.libgpodder import db
from gpodder.libgpodder import gl
from gpodder import download
from gpodder import console
class Podcast(object):
"""API interface of gPodder podcasts
@ -152,6 +153,13 @@ def create_podcast(url, title=None):
return None
def synchronize_device():
"""Synchronize episodes to a device
WARNING: API subject to change.
"""
console.synchronize_device(db, gl.config)
def finish():
"""Persist changed data to the database file

View file

@ -17,170 +17,42 @@
# along with this program. If not, see <http://www.gnu.org/licenses/>.
#
import gpodder
from gpodder import util
from gpodder import download
from gpodder import sync
from gpodder import opml
from gpodder.libgpodder import gl
from gpodder.libgpodder import db
from gpodder.liblogger import msg
from libpodcasts import PodcastChannel
import time
import urllib
import sys
import gpodder
from gpodder import sync
from gpodder.libpodcasts import PodcastChannel
_ = gpodder.gettext
def list_channels():
for channel in PodcastChannel.load_from_db(db, gl.config.download_dir):
msg('podcast', urllib.unquote(channel.url))
def add_channel( url):
callback_error = lambda s: msg( 'error', s)
url = util.normalize_feed_url(url)
channels = PodcastChannel.load_from_db(db, gl.config.download_dir)
if url in (c.url for c in channels):
msg('error', _('Already added: %s'), urllib.unquote(url))
return
try:
channel = PodcastChannel.load(db, url, create=True, max_episodes=gl.config.max_episodes_per_feed, download_dir=gl.config.download_dir)
except:
msg( 'error', _('Could not load feed from URL: %s'), urllib.unquote( url))
return
if channel:
channels.append(channel)
exporter = opml.Exporter(gpodder.subscription_file)
exporter.write(channels)
db.commit()
msg('add', urllib.unquote(url))
else:
msg('error', _('Could not add podcast.'))
def del_channel( url):
url = util.normalize_feed_url( url)
channels = PodcastChannel.load_from_db(db, gl.config.download_dir)
keep_channels = []
for channel in channels:
if channel.url == url:
msg( 'delete', urllib.unquote( channel.url))
channel.remove_downloaded()
channel.delete()
else:
keep_channels.append( channel)
if len(keep_channels) < len(channels):
exporter = opml.Exporter(gpodder.subscription_file)
exporter.write(keep_channels)
db.commit()
else:
msg('error', _('Could not remove podcast.'))
def update():
sys.stdout.write(_('Updating podcast feeds...'))
sys.stdout.flush()
channels = PodcastChannel.load_from_db(db, gl.config.download_dir)
for channel in channels:
channel.update(gl.config.max_episodes_per_feed)
print _('done.')
db.commit()
return channels
def run():
channels = update()
new_episodes = 0
for channel in channels:
for episode in channel.get_new_episodes():
msg( 'downloading', urllib.unquote( episode.url))
task = download.DownloadTask(episode)
task.status = download.DownloadTask.QUEUED
task.run()
if task.status == task.DONE:
msg('done', 'Finished.')
elif task.status == task.FAILED:
msg('failed', 'Download error: %s' % task.error_message)
new_episodes += 1
if new_episodes == 0:
print _('No new episodes to download.')
elif new_episodes == 1:
print _('Downloaded one new episode.')
else:
print _('Downloaded %d new episodes.') % new_episodes
db.commit()
def sync_device():
device = sync.open_device(gl.config)
def synchronize_device(db, config):
device = sync.open_device(config)
if device is None:
msg('error', _('No device configured. Please use the GUI.'))
print >>sys.stderr, _('No device configured.')
return False
callback_status = lambda s: msg('status', '%s', s)
device.register('status', callback_status)
callback_done = lambda: msg('done', _('Synchronization finished.'))
device.register('done', callback_done)
callback_progress = lambda i, n: msg('progress', _('Synchronizing: %d of %d') % (i, n))
def msg(s):
print >>sys.stderr, s
device.register('status', msg)
callback_progress = lambda i, n: msg(_('Synchronizing: %d of %d') % (i, n))
device.register('progress', callback_progress)
if not device.open():
msg('error', _('Cannot open device.'))
return False
if device.open():
channels = [c for c in PodcastChannel.load_from_db(db, \
config.download_dir) if c.sync_to_devices]
for channel in PodcastChannel.load_from_db(db, gl.config.download_dir):
if not channel.sync_to_devices:
msg('info', _('Skipping podcast: %s') % channel.title)
continue
episodes_to_sync = []
for episode in channel.get_all_episodes():
if episode.was_downloaded(and_exists=True):
episodes_to_sync.append(episode)
device.add_tracks(episodes_to_sync)
for channel in channels:
episodes = [e for e in channel.get_downloaded_episodes() \
if e.was_downloaded(and_exists=True)]
device.add_tracks(episodes)
db.commit()
if not device.close():
msg('error', _('Cannot close device.'))
return False
def sync_stats():
size = 0
device = sync.open_device(gl.config)
if device is None:
msg('error', _('No device configured. Please use the GUI.'))
return False
for channel in PodcastChannel.load_from_db(db, gl.config.download_dir):
if not channel.sync_to_devices:
continue
for episode in channel.get_all_episodes():
if episode.was_downloaded(and_exists=True):
episode.calculate_filesize()
size += episode.length
msg('info', _('Free space on device: %s') % (util.format_filesize(device.get_free_space())))
msg('info', _('Size of episodes to sync: %s') % util.format_filesize(size))
difference = device.get_free_space() - size
if difference < 0:
msg('error', _('Need to free at least %s more') % util.format_filesize(abs(difference)))
return False
db.commit()
device.close()
print >>sys.stderr, _('Device synchronized successfully.')
return True
else:
msg('info', _('Free space after sync: %s') % util.format_filesize(abs(difference)))
if not device.close():
msg('error', _('Cannot close device.'))
print >>sys.stderr, _('Error: Cannot open device!')
return False
return True