1 # -*- coding: utf-8 -*-
3 # gPodder - A media aggregator and podcast client
4 # Copyright (c) 2005-2010 Thomas Perl and the gPodder Team
6 # gPodder is free software; you can redistribute it and/or modify
7 # it under the terms of the GNU General Public License as published by
8 # the Free Software Foundation; either version 3 of the License, or
9 # (at your option) any later version.
11 # gPodder is distributed in the hope that it will be useful,
12 # but WITHOUT ANY WARRANTY; without even the implied warranty of
13 # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14 # GNU General Public License for more details.
16 # You should have received a copy of the GNU General Public License
17 # along with this program. If not, see <http://www.gnu.org/licenses/>.
20 """Public developer API for gPodder
22 This module provides a nicely documented API for developers to
23 integrate podcast functionality into their applications.
27 from gpodder
import util
28 from gpodder
import opml
29 from gpodder
.model
import PodcastChannel
30 from gpodder
import download
31 from gpodder
import console
33 from gpodder
import dbsqlite
34 from gpodder
import config
35 from gpodder
import youtube
37 class Podcast(object):
38 """API interface of gPodder podcasts
40 This is the API specification of podcast objects that
41 are returned from API functions.
47 def __init__(self
, _podcast
, _manager
):
48 """For internal use only."""
49 self
._podcast
= _podcast
50 self
._manager
= _manager
51 self
.title
= self
._podcast
.title
52 self
.url
= self
._podcast
.url
54 def get_episodes(self
):
55 """Get all episodes that belong to this podcast
57 Returns a list of Episode objects that belong to this podcast."""
58 return [Episode(e
, self
._manager
) for e
in self
._podcast
.get_all_episodes()]
60 def rename(self
, title
):
61 """Set a new title for this podcast
63 Sets a new title for this podcast that will be available
64 as the "title" attribute of this object."""
65 self
._podcast
.set_custom_title(title
)
66 self
.title
= self
._podcast
.title
70 """Remove this podcast from the subscription list
72 Removes the subscription and all downloaded episodes.
74 self
._podcast
.remove_downloaded()
75 self
._podcast
.delete()
78 def update_enabled(self
):
79 """Check if this feed has updates enabled
81 This function will return True if the podcast has feed
82 updates enabled. If the user pauses a subscription, the
83 feed updates are disabled, and the podcast should be
84 excluded from automatic updates.
86 return self
._podcast
.feed_update_enabled
89 """Updates this podcast by downloading the feed
91 Downloads the podcast feed (using the feed cache), and
92 adds new episodes and updated information to the database.
94 self
._podcast
.update(self
._manager
._config
.max_episodes_per_feed
, \
95 self
._manager
._config
.mimetype_prefs
)
97 def feed_update_status_msg(self
):
98 """Show the feed update status
100 Display the feed update current status.
102 if self
._podcast
.feed_update_enabled
:
107 def feed_update_status(self
):
108 """Return the feed update status
110 Return the feed update current status.
112 return self
._podcast
.feed_update_enabled
115 """Toogle the feed update to disable
117 Change the feed update status to disable only if currently enable.
119 if self
._podcast
.feed_update_enabled
:
120 self
._podcast
.feed_update_enabled
= False
124 """Toogle the feed update to disable
126 Change the feed update status to disable only if currently enable.
128 if not self
._podcast
.feed_update_enabled
:
129 self
._podcast
.feed_update_enabled
= True
132 class Episode(object):
133 """API interface of gPodder episodes
135 This is the API specification of episode objects that
136 are returned from API functions.
145 def __init__(self
, _episode
, _manager
):
146 """For internal use only."""
147 self
._episode
= _episode
148 self
._manager
= _manager
149 self
.title
= self
._episode
.title
150 self
.url
= self
._episode
.url
151 self
.is_new
= (self
._episode
.state
== gpodder
.STATE_NORMAL
and \
152 not self
._episode
.is_played
)
153 self
.is_downloaded
= (self
._episode
.state
== gpodder
.STATE_DOWNLOADED
)
154 self
.is_deleted
= (self
._episode
.state
== gpodder
.STATE_DELETED
)
156 def download(self
, callback
=None):
157 """Downloads the episode to a local file
159 This will run the download in the same thread, so be sure
160 to call this method from a worker thread in case you have
161 a GUI running as a frontend."""
162 task
= download
.DownloadTask(self
._episode
, self
._manager
._config
)
163 if callback
is not None:
164 task
.add_progress_callback(callback
)
165 task
.status
= download
.DownloadTask
.QUEUED
169 class PodcastClient(object):
171 """Create a new gPodder API instance
173 Connects to the database and loads the configuration.
175 util
.make_directory(gpodder
.home
)
176 gpodder
.load_plugins()
178 self
._db
= dbsqlite
.Database(gpodder
.database_file
)
179 self
._config
= config
.Config(gpodder
.config_file
)
181 def get_podcasts(self
):
182 """Get a list of Podcast objects
184 Returns all the subscribed podcasts from gPodder.
186 return [Podcast(p
, self
) for p
in PodcastChannel
.load_from_db(self
._db
, self
._config
.download_dir
)]
188 def get_podcast(self
, url
):
189 """Get a specific podcast by URL
191 Returns a podcast object for the URL or None if
192 the podcast has not been subscribed to.
194 url
= util
.normalize_feed_url(url
)
195 channel
= PodcastChannel
.load(self
._db
, url
, create
=False, download_dir
=self
._config
.download_dir
)
199 return Podcast(channel
, self
)
201 def create_podcast(self
, url
, title
=None):
202 """Subscribe to a new podcast
204 Add a subscription for "url", optionally
205 renaming the podcast to "title" and return
206 the resulting object.
208 url
= util
.normalize_feed_url(url
)
209 podcast
= PodcastChannel
.load(self
._db
, url
, create
=True, \
210 max_episodes
=self
._config
.max_episodes_per_feed
, \
211 download_dir
=self
._config
.download_dir
, \
212 allow_empty_feeds
=self
._config
.allow_empty_feeds
, \
213 mimetype_prefs
=self
._config
.mimetype_prefs
)
214 if podcast
is not None:
215 if title
is not None:
216 podcast
.set_custom_title(title
)
218 return Podcast(podcast
, self
)
222 def synchronize_device(self
):
223 """Synchronize episodes to a device
225 WARNING: API subject to change.
227 console
.synchronize_device(self
._db
, self
._config
)
230 """Persist changed data to the database file
232 This has to be called from the API user after
233 data-changing actions have been carried out.
235 podcasts
= PodcastChannel
.load_from_db(self
._db
, self
._config
.download_dir
)
236 exporter
= opml
.Exporter(gpodder
.subscription_file
)
237 exporter
.write(podcasts
)
241 def youtube_url_resolver(self
, url
):
242 """Resolve the Youtube URL
244 WARNING: API subject to change.
246 yurl
= youtube
.get_real_download_url(url
, \
247 self
._config
.youtube_preferred_fmt_id
)