11 KiB
The "podcast:recommendations" Specification
Version 1.0 by Benjamin Bellamy - 2021.08.31
Purpose
Podcasting is a tremendous ecosystem brimming with tons of stories and ideas that go freely from any platform to any application. That comes with a huge drawback: finding and being found can be harsh. Podcast creators struggle to be found while podcast listeners struggle to find content.
Several platforms are now implementing recommendation engines, but these features are expensive and unattainable for small players. Moreover they are slowly creating closed silos and removing power from content creators. This specification is about giving control to content creators on the content they want to recommend, and at the same time providing a free recommendation system to all players.
Specification
<podcast:recommendations
url="[url to json file(string)]"
type="application/json"
language="[language code(string)]"
/>
[Optionnal comments(string)]
</podcast:recommendations>
Channel (optional | multiple)
Item (optional | multiple)
This element allows a podcaster to specify a list of recommended content for a podcast or an episode.
The recommended content can be a web page, a podcast, a podcast episode or a soundbite, so that listeners can eventually subscribe to a podcast, add an episode to playlist, add a soundbite to playlist, etc.
There may be several occurences of this tag for the same element (one per language, one per topic, one per provider).
Attributes
url
(required): This is the url to the json file.type
(required): Mime type, must be json.language
(optional): The language of the recommended episodes (two-letter language codes, with some possible modifiers, such as "en-us"). If there is no language attribute given, the linked file is assumed to be the same language that is specified by the RSS<language>
element.
Examples
<podcast:recommendations url="https://domain.tld/recommendation?guid=1234" type="application/json" />
<podcast:recommendations url="https://domain.tld/recommendation?guid=1234" type="application/json" language="en" />
JSON File Specification
The recommendations file contains a simple JSON object with 2 required properties and a few optional properties. This top-level object
is simply a container for the main payload, which is an array of recommendation
objects contained in the recommendations
property.
Required Attributes
version
(required - string) The version number of the format being used.recommendations
(required - array) An array ofrecommendations
objects defined below.
Optional Attributes
comment
(optional - string) A comment on this file.title
(optional - string) The name of the source podcast or source podcast episode. Applies to both Channel and Item.feed
(optional - string) The RSS URL of the source podcast. Applies to both podcast Channel and podcast Item.guid
(optional - string) The GUID of the source element. Applies to both podcast Channel and podcast Item.url
(optionnal - string) The enclosure URL of the source medium.
Example
{
"version": "1.0",
"title": "Podnews podcasting news",
"feed": "https://podnews.net/rss",
"guid": "9b024349-ccf0-5f69-a609-6b82873eab3c",
"recommendations": [
...
]
}
The "recommendations" Array
Each recommendation is defined in a recommendation
object that resides within the recommendations
array. It is meant to structure data
that might otherwise be present - buried within shownotes HTML.
Required attributes:
linkType
(required - string) The link type of this recommended content, it can be:- 'generic',
- 'feed',
- 'item',
- 'none'
medium
(required - string) The medium type. It can be:podcast
,music
,video
,film
,audiobook
,newsletter
,blog
title
(required - string) The title for this recommended content.
Optional Attributes:
url
(optional - string) The URL for this recommended content. If recommended content type is "feed" this is the home page of the podcast/medium. If recommended content type is "feed-item" this is the enclosure URL.image
(optional - string) The image URL for this recommended content. Image must have a 1:1 ratio (square).displayStartTime
(optional - float) The start time (in seconds) that tells when this recommended content should start being displayed. IfdisplayStartTime
is omitted, recommendation will be displayed from the beginning. Applies only when called from an Item (not from the Channel).displayDuration
(optional - float) The duration (in seconds) that tells when this recommended content should stop being displayed. IfdisplayDuration
is omitted, recommendation will be displayed until the end. Applies only when called from an Item (not from the Channel).feed
(optional - string) The RSS URL of this recommended content. Applies to "feed", "feed-item" types.guid
(optional - string) The GUID of this recommended content. Applies to "feed" and "feed-item" types.startTime
(optional - float) The start time (in seconds) of this recommended content. Applies to "feed-item" type only.duration
(optional - float) The duration (in seconds) of this recommended content. Applies to "feed-item" type only.motive
(optional - string) The reason why this content is recommended. It can be:references
(content that was used when creating this podcast, similar to the Wikipedia References paragraph),additional content
(content that provides extra information),acknowledgment
(thanking people),advertising
(sponsored content),audience exchange
(exchanging audiences between podcasts),content-based recommendation
(content related thanks to semantic indexation),audience-based recommendation
(people who liked this also liked…),made by the same people
(the creators of this podcast also made that…)
relevance
(optional - float) The relevance of this recommended content regarding this Channel or Item. Number must be in [0…1]. 0 is for irrelevant content, 1 is for contents that match perfectly.
Example of Structure
{
"linkType": "generic",
"title": "History of podcasting",
"image": "https://upload.wikimedia.org/wikipedia/commons/thumb/e/e7/Podcasts_%28iOS%29.svg/440px-Podcasts_%28iOS%29.svg.png",
"url": "https://en.wikipedia.org/wiki/History_of_podcasting"
}
Basic example
Here is what a very basic recommendations file may look like:
{
"version": "1.0",
"recommendations":
[
{
"linkType": "none",
"medium": "text",
"title": "Eat five vegetables every day.",
"motive": "advertising"
},
{
"linkType": "generic",
"medium": "html",
"title": "History of podcasting",
"image": "https://upload.wikimedia.org/wikipedia/commons/thumb/e/e7/Podcasts_%28iOS%29.svg/440px-Podcasts_%28iOS%29.svg.png",
"url": "https://en.wikipedia.org/wiki/History_of_podcasting",
"motive": "additional content"
},
{
"linkType": "feed",
"medium": "podcast",
"title": "Podcasting 2.0",
"image": "https://noagendaassets.com/enc/1601061118.678_pciavatar.jpg",
"url": "https://podcastindex.org/podcast/920666",
"feed": "http://mp3s.nashownotes.com/pc20rss.xml",
"motive": "audience exchange"
},
{
"linkType": "item",
"medium": "podcast",
"title": "Episode 26: Manning Battlestations",
"image": "https://noagendaassets.com/enc/1601061118.678_pciavatar.jpg",
"url": "https://mp3s.nashownotes.com/PC20-26-2021-02-26-Final.mp3",
"feed": "http://mp3s.nashownotes.com/pc20rss.xml",
"guid": "PC2026"
},
{
"linkType": "item",
"medium": "podcast",
"title": "GO PODCASTING!!!",
"image": "https://noagendaassets.com/enc/1601061118.678_pciavatar.jpg",
"url": "https://mp3s.nashownotes.com/PC20-26-2021-02-26-Final.mp3",
"feed": "http://mp3s.nashownotes.com/pc20rss.xml",
"guid": "PC2026",
"startTime": 4737.0,
"duration": 5.0
}
]
}
More complex example
{
"version": "1.0",
"title": "Podnews podcasting news",
"feed": "https://podnews.net/rss",
"guid": "9b024349-ccf0-5f69-a609-6b82873eab3c",
"recommendations":
[
{
"linkType": "none",
"medium": "text",
"title": "Eat five vegetables every day.",
"motive": "advertising"
},
{
"displayStartTime": 0.0,
"displayDuration": 120.0,
"linkType": "generic",
"medium": "html",
"title": "History of podcasting",
"image": "https://upload.wikimedia.org/wikipedia/commons/thumb/e/e7/Podcasts_%28iOS%29.svg/440px-Podcasts_%28iOS%29.svg.png",
"url": "https://en.wikipedia.org/wiki/History_of_podcasting",
"motive": "additional content",
"relevance": 0.8
},
{
"displayStartTime": 120.50,
"displayDuration": 60.0,
"linkType": "feed",
"medium": "podcast",
"title": "Podcasting 2.0",
"image": "https://noagendaassets.com/enc/1601061118.678_pciavatar.jpg",
"url": "https://podcastindex.org/podcast/920666",
"feed": "http://mp3s.nashownotes.com/pc20rss.xml",
"motive": "audience exchange",
"relevance": 0.7
},
{
"displayStartTime": 240.60,
"displayDuration": 180.0,
"linkType": "feed-item",
"medium": "podcast",
"title": "Episode 26: Manning Battlestations",
"image": "https://noagendaassets.com/enc/1601061118.678_pciavatar.jpg",
"url": "https://mp3s.nashownotes.com/PC20-26-2021-02-26-Final.mp3",
"feed": "http://mp3s.nashownotes.com/pc20rss.xml",
"guid": "PC2026",
"relevance": 0.5
},
{
"displayStartTime": 3600.10,
"displayDuration": 60.0,
"linkType": "item",
"medium": "podcast",
"title": "GO PODCASTING!!!",
"image": "https://noagendaassets.com/enc/1601061118.678_pciavatar.jpg",
"url": "https://mp3s.nashownotes.com/PC20-26-2021-02-26-Final.mp3",
"feed": "http://mp3s.nashownotes.com/pc20rss.xml",
"guid": "PC2026",
"startTime": 4737.0,
"duration": 5.0,
"motive": "additional content",
"relevance": 0.9
}
]
}
Privacy
When pulling in web based data there is the chance that this functionality could be used for tracking. As a safeguard against that, apps should:
- Block all cookies.
- Allow users to ignore
displayStartTime
anddisplayDuration
if they want to. - Fetch all recommendations at the same time disregarding
displayStartTime
so that HTTP requests cannot be used as a way of measuring who listens to what.
Discussion here: