Add docs for deprecated API 1
[mygpo.git] / doc / api / api1.rst
blob8b68c2220219058cf160c9ec5070ddda63fd4fe6
1 .. _api1:
4 API 1 (Deprecated)
5 ==================
7 This page describes version 1 of the gpodder.net API which is deprecated in
8 favor of version 2.
11 There are two different APIs for different target audiences:
13 * The Simple API targets developers who want to write quick integration into
14   their existing applications
15 * The Advanced API targets developers who want tight integration into their
16   applications (with more features)
19 Reference Implementation
20 ------------------------
22 https://github.com/gpodder/mygpoclient
25 Legacy API
26 ----------
28 This API is for support of old clients (gPodder 2.1 and earlier) and should
29 never be used in new code. It's just here for reference of what the server
30 implementation should provide.
32 upload
33 ^^^^^^
35 * Request URI: ``/upload`` * Parameters: ``username`` (the e-mail address of
36   the user), ``password`` (the user password in plaintext), ``action`` (always
37   set to ``update-subscriptions``), ``protocol`` (always set to ``0``),
38   ``opml`` (a HTTP file upload field that contains the subscription list as
39   OPML file)
41 Parses the given OPML file and compares the user's default subscription list
42 with the entries from the OPML file. For every new subscription, the server
43 automatically creates a "subscribe" event, and for every removed subscription,
44 the server automatically generates a "unsubscribe" event. The user's default
45 subscription list on the server will match the uploaded OPML file after the
46 request returns ``@SUCCESS``.
48 Possible response values (these are potentially contained within surrounding
49 text, e.g. HTML):
51 * ``@GOTOMYGPODDER``: The website it opened in the web browser and the user
52   gets the message "Please have a look at the website for more information."
53 * ``@SUCCESS``: The subscription has been successfully uploaded.
54 * ``@AUTHFAIL``: The supplied username and password combination is wrong.
55 * ``@PROTOERROR``: There has been an error in the request format (wrong OPML
56   format, wrong parameters, etc..).
57 * ''None of the above'': This is an "unknown" response, and the client displays
58   an error message to the user.
60 getlist
61 ^^^^^^^
63 * Request URI: ``/getlist``
64 * Parameters: ``username`` (the e-mail address of the user), ``password`` (the
65   user password in plaintext)
67 This returns the main subscription list of the user as OPML content.
69 register
70 ^^^^^^^^
72 * Request URI: ``/register``
73 * Parameters: None
75 This web page is to be opened in a web browser if the user choses to create a
76 new user account.
79 toplist.opml
80 ^^^^^^^^^^^^
82 * Request URI: ``/toplist.opml``
83 * Parameters: None
85 This should return an OPML file with the top 50 podcasts. This is the same as
86 the Simple API endpoint ``/toplist/50.opml`` and can (obviously) utilize the
87 same code.
90 Simple API
91 ----------
93 The Simple API provides a way to upload and download subscription lists in
94 bulk. This allows developers of podcast-related applications to quickly
95 integrate support for the web service, as the only
97 * Synchronization of episode status fields is ``not`` supported
98 * This API uses more bandwith than the advanced API
99 * The client can be stateless
100 * The client can be low-powered - subscribe/unsubscribe events are calculated
101   on the server-side
103 Downloading subscription lists
104 ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
106 * Request: ``GET /subscriptions/''{username}''/''{device_id}''.opml``
107 * Request: ``GET /subscriptions/''{username}''/''{device_id}''.json``
108 * Request: ``GET /subscriptions/''{username}''/''{device_id}''.txt``
109 * Requires HTTP authentication
111 Get a list of subscribed podcasts for the given user. The first variant returns
112 the content as OPML feed, the second variant as list of feed URLs in JSON
113 format. The third variant returns the list of URLs (one per line) as simple
114 plaintext.
116 * Example: ``GET /subscriptions/bob/asdf.opml`` (Download bob's list for
117   device ID ``asdf`` as OPML)
119 In case of errors, the following HTTP status codes are used:
121 * ``401`` Invalid user
122 * ``404`` Invalid device ID
123 * ``400`` Invalid format (e.g. broken OPML)
125 Uploading subscription lists
126 ^^^^^^^^^^^^^^^^^^^^^^^^^^^^
128 * Request: ``PUT /subscriptions/''{username}''/''{device_id}''.opml``
129 * Request: ``PUT /subscriptions/''{username}''/''{device_id}''.json``
130 * Request: ``PUT /subscriptions/''{username}''/''{device_id}''.txt``
131 * Requires HTTP authentication
133 Upload the current subscription list of the given user to the server. The data
134 should be provided either in OPML, JSON or plaintext (one URL per line) format,
135 and should be uploaded just like a normal PUT request (i.e. in the body
136 of the request).
138 For successful updates, the implementation ``always`` returns the status code
139 ``200`` and the ''empty string'' (i.e. an empty HTTP body) as a result, any
140 other string should be interpreted by the client as an (undefined) error.
142 Defined errors are as follows (in this case, the body that is received from the
143 server ''might'' be a user-friendy description of the error):
145 * ``401`` Invalid user
146 * ``400`` Invalid format (cannot parse OPML or JSON)
148 In case the device does not exist for the given user, it is automatically
149 created. If clients want to determine if a device exists, you have to to a GET
150 request on the same URL first and check for a the 404 status code (see above).
152 * Example: ``PUT /subscriptions/john/e9c4ea4ae004efac40.txt`` (Upload john's
153   list for that device as text file)
156 Downloading podcast toplists
157 ^^^^^^^^^^^^^^^^^^^^^^^^^^^^
159 * Request: ``GET /toplist/''{number}''.opml``
160 * Request: ``GET /toplist/''{number}''.json``
161 * Request: ``GET /toplist/''{number}''.txt``
162 * Does ''not'' require authentication (''public content'')
164 The ``number`` field might be any value in the range 1..100 (inclusive both
165 boundaries). An example request looks like:
167 * ``GET /toplist/50.json`` - Get the top 50 list in JSON format
169 Download a list of podcasts, sorted in descending order (more popular podcasts
170 first) in different formats. The OPML and TXT formats do not add any
171 information about the (absolute and relative) popularity for each podcast, only
172 the ordering can be considered. The JSON format includes a more detailed list,
173 usable for clients that want to display a detailed toplist or post-process
174 the toplist:
177 .. code-block:: json
179      [{"url": "http://twit.tv/node/4350/feed",
180        "title": "FLOSS Weekly",
181        "description": "Free, Libre and Open Source Software with Leo.",
182        "subscribers": 4711,
183        "subscribers_last_week": 4700
184       },
185       {"url": "http://feeds.feedburner.com/LinuxOutlaws",
186        "title": "The Linux Outlaws",
187        "description": "A podcast about Linux with Dan and Fab.",
188        "subscribers": 1337,
189        "subscribers_last_week": 1330,
190       }]
192 All shown keys must be provided by the server. The ``description`` field may be
193 set to the empty string in case a description is not available. The ``title``
194 field may be set to the URL in case a title is not available. The
195 ``subscribers_last_week`` field may be set to zero if no data is available. The
196 client can use the ``subscribers_last_week`` counts to re-sort the list and get
197 a ranking for the last week. With this information, a relative "position
198 movement" can also be calculated if the developer of the client decides to do
201 Downloading podcast suggestions
202 ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
204 * Request: ``GET /suggestions/''{number}''.opml``
205 * Request: ``GET /suggestions/''{number}''.json``
206 * Request: ``GET /suggestions/''{number}''.txt``
207 * Requires HTTP authentication
209 The ``number`` field might be any value in the range 1..100 (inclusive both
210 boundaries). An example request looks like:
212 * ``GET /suggestions/10.opml`` - Get 10 suggestions in OPML format
214 Download a list of podcasts that the user has not yet subscribed to (by
215 checking ''all'' server-side subscription lists) and that might be
216 interesting to the user based on existing subscriptions (again on ''all''
217 server-side subscription lists).
219 The TXT format is a simple URL list (one URL per line), and the OPML file is a
220 "standard" OPML feed. The JSON format looks as follows:
223 .. code-block:: json
225      [{"url": "http://twit.tv/node/4350/feed",
226        "title": "FLOSS Weekly",
227        "description": "Free, Libre and Open Source Software with Leo."
228       },
229       {"url": "http://feeds.feedburner.com/LinuxOutlaws",
230        "title": "The Linux Outlaws",
231        "description": "A podcast about Linux with Dan and Fab."
232       }]
234 The server does not specify the "relevance" for the podcast suggestion, and the client application ''SHOULD'' filter out any podcasts that are already added to the client application but that the server does not know about yet (although this is just a suggestion for a good client-side UX).
237 Searching for podcasts
238 ^^^^^^^^^^^^^^^^^^^^^^
240 * Request: ``GET /search.opml?q=''{query}``''
241 * Request: ``GET /search.json?q=''{query}``''
242 * Request: ``GET /search.txt?q=''{query}``''
243 * Does ''not'' require authentication (''public content'')
245 Carries out a service-wide search for podcasts that match the given query.
246 Returns a list of podcasts.
248 The format of the search results is the same as for podcast suggestions. See
249 there for the exact format.
252 Advanced API
253 ------------
255 The Advanced API provides more flexibility and enhanced functionality for
256 applications that want a tighter integration with the web service. A reference
257 implementation will be provided as part of the gPodder source code (and gPodder
258 will make use of that reference implementation).
260 * The client has to persist the synchronization state locally
261 * Only changes to subscriptions are uploaded and downloaded
262 * Synchronization of episode status fields is supported in this API
263 * Only JSON is used as the data format to ease development
265 Add/remove subscriptions
266 ^^^^^^^^^^^^^^^^^^^^^^^^
268 * Request: ``POST /api/1/subscriptions/''{username}''/''{device_id}''.json``
269 * Requires HTTP authentication
271 Update the subscription list for a given device. Only deltas are supported
272 here. Timestamps are not supported, and are issued by the server.
274 Example JSON upload data:
277 .. code-block:: json
279       {"add": ["http://example.com/feed.rss", "http://example.org/podcast.php"],
280        "remove": ["http://example.net/foo.xml"]}
282 The server returns a timestamp/ID that can be used for requesting changes since
283 this upload in a subsequent API call (see below):
286 .. code-block:: json
288   {"timestamp": 12345, "update_urls": []}
290 ``Update 2010-01-07:`` In addition, the server MUST send any URLs that have
291 been rewritten (sanitized, see [[bug:747]]) as a list of tuples with the key
292 "update_urls". The client SHOULD parse this list and update the local
293 subscription list accordingly (the server only sanitizes the URL, so the
294 semantic "content" should stay the same and therefore the client can
295 simply update the URL value locally and use it for future updates. An
296 example result with update_urls:
299 .. code-block:: json
301   {"timestamp": 1337,
302    "update_urls": [
303     ["http://feeds2.feedburner.com/LinuxOutlaws?format=xml",
304      "http://feeds.feedburner.com/LinuxOutlaws"],
305     ["http://example.org/podcast.rss ",
306      "http://example.org/podcast.rss"]]}
308 ``Update 2010-01-17:`` URLs that are not allowed (currently all URLs that don't
309 start with either http or https) are rewritten to the empty string and are
310 ignored by the Webservice.
313 Retrieving subscription changes
314 ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
316 * Request: ``GET /api/1/subscriptions/''{username}''/''{device_id}''.json?since=''{timestamp}``''
317 * Requires HTTP authentication
319 This API call retrieves only the changes since the last upload (the last upload
320 is determined by the "since" parameter, which usually is taken from the
321 return value of a previous update call). The response format is the
322 same as the upload format, i.e. JSON: A dictionary with two keys "add" and
323 "remove" where the value for each key is a list of URLs that should be added or
324 removed. There is one additional key ("timestamp") that is provided by the
325 server that will tell the client the next value for the "since" parameter in
326 case the client wants to issue another GET request in the future without
327 uploading data.
329 In case nothing has changed, the server returns something like the following
330 JSON content (in this case, the client SHOULD store the timestamp and use it
331 for future requests):
334 .. code-block:: json
336       {"add": [], "remove": [], "timestamp": 12347}
339 Uploading episode actions
340 ^^^^^^^^^^^^^^^^^^^^^^^^^
342 * Request: ``POST /api/1/episodes/''{username}''.json``
343 * Requires HTTP authentication
345 Upload changed episode actions. As actions are saved on a per-user basis (not
346 per-device), the API endpoint is the same for every device. For logging
347 purposes, the client can send the device ID to the server, so it appears in the
348 episode action log on the website.
350 Example JSON upload data:
353 .. code-block:: json
355   [{"podcast": "http://example.com/feed.rss",
356     "episode": "http://example.com/files/s01e20.mp3",
357     "device": "gpodder_abcdef123",
358     "action": "download",
359     "timestamp": "2009-12-12T09:00:00"},
360    {"podcast": "http://example.org/podcast.php",
361     "episode": "http://ftp.example.org/foo.ogg",
362     "action": "play",
363     "position": "01:00:00"}]
365 Possible keys:
367 * ``podcast`` (required): The URL to the podcast feed the episode belongs to
368 * ``episode`` (required): The download URL/GUID of the episode
369 * ``device`` (optional): The device ID on which the action has taken place
370 * ``action`` (required): One of: download, play, delete, new
371 * ``timestamp`` (optional): An optional timestamp when the action took place,
372   in [http://en.wikipedia.org/wiki/ISO_8601 ISO 8601 format] -
373   **The timestamp MUST be in the UTC time zone**
374 * ``position`` (optional): Only valid for "play": the current play position
375   in ``HH:MM:SS`` format
377 The return value is a JSON dictionary containing the timestamp (that can be
378 used for retrieving changed episode actions later on):
381 .. code-block:: json
383     {"timestamp": 12345,
384      "update_urls": [] }
386 The client SHOULD save this timestamp if it wants to retrieve episode actions
387 in the future in order to save bandwith and CPU time on the server.
390 ``Update 2010-02-23:`` In addition, the server MUST send any URLs that have
391 been rewritten (sanitized, see [[bug:747]] and [[bug:862]]) as a list of tuples
392 with the key "update_urls". The client SHOULD parse this list and update the
393 local subscription and episode list accordingly (the server only sanitizes the
394 URL, so the semantic "content" should stay the same and therefore the
395 client can simply update the URL value locally and use it for future
396 updates. An example result with update_urls:
399 .. code-block:: json
401   {"timestamp": 1337,
402    "update_urls": [
403     ["http://feeds2.feedburner.com/LinuxOutlaws?format=xml",
404      "http://feeds.feedburner.com/LinuxOutlaws"],
405     ["http://example.org/episode.mp3 ",
406      "http://example.org/episode.mp3"]]}
408 URLs that are not allowed (currently all URLs that contain non-ASCII characters
409     or don't start with either http or https) are rewritten to the empty string
410 and are ignored by the Webservice.
413 Retrieving episode actions
414 ^^^^^^^^^^^^^^^^^^^^^^^^^^
416 * Request: ``GET /api/1/episodes/''{username}''.json``
417 * Request: ``GET /api/1/episodes/''{username}''.json?podcast=''{url}``''
418 * Request: ``GET /api/1/episodes/''{username}''.json?device=''{device-id}``''
419 * Request: ``GET /api/1/episodes/''{username}''.json?since=''{timestamp}``''
420 * Request: ``GET /api/1/episodes/''{username}''.json?podcast=''{url}''&since=''{timestamp}``''
421 * Request: ``GET /api/1/episodes/''{username}''.json?device=''{device-id}''&since=''{timestamp}``''
422 * Requires HTTP authentication
424 Download changed episode actions. The result is a list of all new episode
425 actions since the given timestamp. The timestamp is the value returned by the
426 episode upload request. The first three variants (without the "since"
427 parameter) downloads ALL episode actions for the given user. Please
428 note that this could be a potentially long list of episode actions, so clients
429 SHOULD prefer the "since" variants whenever possible (e.g. when uploads have
430 been taken place before).
432 The format of the action list is the same as with the action upload request,
433 but the format is a bit different so that the server can send the new
434 timestamp (that the client SHOULD save and use for subsequent requests):
437 .. code-block:: json
439     {"actions": ''(list of episode actions here - see above for details)'',
440      "timestamp": 12345}
443 There are two additional variants that take either a podcast URL or a device ID
444 and returns only episode actions related to the given podcast or device. In the
445 case of the device ID, all podcasts to which the device is currently subscribe
446 to, are combined, and episode actions for these are added.
448 ''Client implementation notes:'' A client can make use of the device variant of
449 this request when it is assigned a single device id. When adding a podcast to
450 the client (without synching the subscription list straight away), the variant
451 with the podcast URL can be used. The first variant (no parameters at all) can
452 be used as a kind of "burst" download of all episode actions, but should be
453 used as little as possible (e.g. after a re-install, although even then, the
454 device-id parameter could be more useful).
456 (Re)naming devices and setting the type
457 ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
459 * Request: ``POST /api/1/devices/''{username}''/''{device-id}''.json``
460 * Requires HTTP authentication
462 Set a new name for the device ID. The device ID is normally generated by the
463 client application, but for viewing the device on the web and for managing
464 subscriptions, it's easier to provide a "human-readable" name. The client
465 application should do this using this API call. It can also provide the type of
466 device, so that a special icon can be shown in the web UI. Only the keys that
467 are supplied will be updated.
470 .. code-block:: json
472   {"caption": "gPodder on my Lappy", "type": "laptop"}
474 Possible keys:
476 * ``caption``: The new label for the device
477 * ``type``: The type of the device. (Possible values: desktop, laptop, mobile,
478   server, other)
481 Getting a list of devices
482 ^^^^^^^^^^^^^^^^^^^^^^^^^
484 * Request: ``GET /api/1/devices/''{username}''.json``
485 * Requires HTTP authentication
487 Returns the list of devices that belong to a user. This can be used by the
488 client to let the user select a device from which to retrieve subscriptions,
489 etc..
492 .. code-block:: json
494   [{"id": "abcdef",
495     "caption": "gPodder on my Lappy",
496     "type": "laptop",
497     "subscriptions": 27},
498    {"id": "09jc23caf",
499     "caption": "",
500     "type": "other",
501     "subscriptions": 30},
502    {"id": "phone-au90f923023.203f9j23f",
503     "caption": "My Phone",
504     "type": "mobile",
505     "subscriptions": 5}]