2 # -*- coding: utf-8 -*-
5 # gPodder - A media aggregator and podcast client
6 # Copyright (c) 2005-2010 Thomas Perl and the gPodder Team
8 # gPodder is free software; you can redistribute it and/or modify
9 # it under the terms of the GNU General Public License as published by
10 # the Free Software Foundation; either version 3 of the License, or
11 # (at your option) any later version.
13 # gPodder is distributed in the hope that it will be useful,
14 # but WITHOUT ANY WARRANTY; without even the implied warranty of
15 # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
16 # GNU General Public License for more details.
18 # You should have received a copy of the GNU General Public License
19 # along with this program. If not, see <http://www.gnu.org/licenses/>.
23 # gpo - A better command-line interface to gPodder using the gPodder API
24 # by Thomas Perl <thp@gpodder.org>; 2009-05-07
28 Usage: gpo [COMMAND] [params...]
30 Subscription management
31 -----------------------
33 subscribe URL [TITLE] Subscribe to a new feed at URL (as TITLE)
34 rename URL TITLE Rename feed at URL to TITLE
35 unsubscribe URL Unsubscribe from feed at URL
37 info URL Show information about feed at URL
38 list List all subscribed podcasts
39 update Refresh all feeds (check for new episodes)
40 update URL Refresh the feed at URL
45 download [URL] Download all new (=pending) episodes; if
46 URL is an episode URL, download only one
47 episode; if it's a channel URL, download
48 all pending episodes from that channel
49 pending [URL] Show episodes that are marked as new; if
50 URL is given, show only pending downloads
51 from the channel at this URL
52 queue URL Add episode at URL to pending episodes
53 skip URL Remove episode at URL from pending episodes
55 details URL Show information about episode at URL
56 episodes [URL] Show a list of all episodes; if URL is given
57 it should be a channel URL and only episodes
58 from that channel will be displayed
60 delete URL Delete the downloaded episode at URL
62 disable URL Mark the feed as disabled
63 enable URL Mark the feed as enabled
65 Portable device synchronization
66 -------------------------------
68 device Show information about your device
69 sync Synchronize downloaded episodes to device
74 youtube resolve [URL] Resolve the YouTube URL to a download URL
75 youtube download [URL] Download a video from YouTube via its URL
83 gpodder_script
= sys
.argv
[0]
84 if os
.path
.islink(gpodder_script
):
85 gpodder_script
= os
.readlink(gpodder_script
)
86 gpodder_dir
= os
.path
.join(os
.path
.dirname(gpodder_script
), '..')
87 prefix
= os
.path
.abspath(os
.path
.normpath(gpodder_dir
))
89 src_dir
= os
.path
.join(prefix
, 'src')
90 data_dir
= os
.path
.join(prefix
, 'data')
92 if os
.path
.exists(src_dir
) and os
.path
.exists(data_dir
) and \
93 not prefix
.startswith('/usr'):
94 # Run gPodder from local source folder (not installed)
95 sys
.path
.insert(0, src_dir
)
101 # Use only the gPodder API here, so this serves both as an example
102 # and as a motivation to provide all functionality in the API :)
103 from gpodder
import api
107 class gPodderCli(object):
109 self
.client
= api
.PodcastClient()
111 # -------------------------------------------------------------------
113 def subscribe(self
, url
, title
=None):
114 if self
.client
.get_podcast(url
) is not None:
115 self
._info
(_('You are already subscribed to %s.' % url
))
118 if self
.client
.create_podcast(url
, title
) is None:
119 self
._error
(_('Cannot download feed for %s.') % url
)
124 self
._info
(_('Successfully added %s.' % url
))
127 def rename(self
, url
, title
):
128 podcast
= self
.client
.get_podcast(url
)
131 self
._error
(_('You are not subscribed to %s.') % url
)
133 old_title
= podcast
.title
134 podcast
.rename(title
)
136 self
._info
(_('Renamed %s to %s.') % (old_title
, title
))
140 def unsubscribe(self
, url
):
141 podcast
= self
.client
.get_podcast(url
)
144 self
._error
(_('You are not subscribed to %s.') % url
)
148 self
._error
(_('Unsubscribed from %s.') % url
)
152 def _episodesList(self
, podcast
):
153 def status_str(episode
):
156 if episode
.is_downloaded
:
158 if episode
.is_deleted
:
163 episodes
= ('%3d. %s %s' % (i
+1, status_str(e
), e
.title
) for i
, e
in enumerate(podcast
.get_episodes()))
167 podcast
= self
.client
.get_podcast(url
)
170 self
._error
(_('You are not subscribed to %s.') % url
)
172 title
, url
, status
= podcast
.title
, podcast
.url
, podcast
.feed_update_status_msg()
173 episodes
= self
._episodesList
(podcast
)
174 episodes
= '\n '.join(episodes
)
175 print >>sys
.stdout
, """
178 Feed update is %(status)s
186 def episodes(self
, url
=None):
187 for podcast
in self
.client
.get_podcasts():
188 podcast_printed
= False
189 if url
is None or podcast
.url
== url
:
190 episodes
= self
._episodesList
(podcast
)
191 episodes
= '\n '.join(episodes
)
192 print >>sys
.stdout
, """
195 """ % (podcast
.url
, episodes
)
199 for podcast
in self
.client
.get_podcasts():
204 def update(self
, url
=None):
205 for podcast
in self
.client
.get_podcasts():
206 if url
is None and podcast
.update_enabled():
207 print 'Updating', podcast
.title
210 elif podcast
.url
== url
:
211 # Don't need to check for update_enabled()
212 print 'Updating', podcast
.title
218 def pending(self
, url
=None):
220 for podcast
in self
.client
.get_podcasts():
221 podcast_printed
= False
222 if url
is None or podcast
.url
== url
:
223 for episode
in podcast
.get_episodes():
225 if not podcast_printed
:
227 podcast_printed
= True
228 print ' ', episode
.title
231 print count
, 'episodes pending.'
234 def download(self
, url
=None):
236 for podcast
in self
.client
.get_podcasts():
237 podcast_printed
= False
238 if url
is None or podcast
.url
== url
:
239 for episode
in podcast
.get_episodes():
241 if not podcast_printed
:
243 podcast_printed
= True
244 print ' ', episode
.title
248 print count
, 'episodes downloaded.'
251 def disable(self
, url
):
252 podcast
= self
.client
.get_podcast(url
)
255 self
._error
(_('You are not subscribed to %s.') % url
)
259 self
._error
(_('Disabling feed update from %s.') % url
)
263 def enable(self
, url
):
264 podcast
= self
.client
.get_podcast(url
)
267 self
._error
(_('You are not subscribed to %s.') % url
)
271 self
._error
(_('Enabling feed update from %s.') % url
)
278 self
.client
.synchronize_device()
281 def youtube_resolve(self
, url
):
282 yurl
= self
.client
.youtube_url_resolver(url
)
283 print "Youtube URL %s resolved to %s" % (url
, yurl
)
286 # -------------------------------------------------------------------
288 def _error(self
, *args
):
289 print >>sys
.stderr
, ' '.join(args
)
291 def _info(self
, *args
):
292 print >>sys
.stdout
, ' '.join(args
)
294 def _checkargs(self
, func
, command_line
):
295 args
, varargs
, keywords
, defaults
= inspect
.getargspec(func
)
296 args
.pop(0) # Remove "self" from args
297 defaults
= defaults
or ()
298 minarg
, maxarg
= len(args
)-len(defaults
), len(args
)
300 if len(command_line
) < minarg
or len(command_line
) > maxarg
:
301 self
._error
('Wrong argument count for %s.' % func
.__name
__)
304 return func(*command_line
)
307 def _parse(self
, command_line
):
311 command
= command_line
.pop(0)
312 if command
.startswith('_'):
313 self
._error
(_('This command is not available.'))
316 for name
, func
in inspect
.getmembers(self
):
317 if inspect
.ismethod(func
) and name
== command
:
318 return self
._checkargs
(func
, command_line
)
320 self
._error
(_('The requested function is not available.'))
324 if __name__
== '__main__':
326 cli
._parse
(sys
.argv
[1:]) or sys
.stderr
.write(__doc__
)