/jsonfeed-to-rss

📡Convert a jsonfeed to an RSS 2.0 feed with iTunes extensions

Primary LanguageJavaScriptMIT LicenseMIT

jsonfeed-to-rss

npm version build status downloads js-standard-style

Convert a JSON feed to an rss feed (RSS 2.0.11). Supports the @xmlns:itunes iTunes RSS extensions and best practices for podcasts, xmlns:dc Dublin Core author names, and the xmlns:content RDF Site Summary 1.0 Modules: Content encoded content extension.

JSON feed icon

Installation

$ npm install jsonfeed-to-rss

Usage

const jsonfeedToRSS = require('jsonfeed-to-rss')
const someJSONFeed = require('./load-some-json-feed-data.json')

const rssFeed = jsonfeedToRSS(someJSONFeed) // Returns an rss 2.0.11 formatted json feed

Example input:

{
  "version":"https://jsonfeed.org/version/1",
  "title":"bret.io log",
  "home_page_url":"https://jsonfeed-to-rss.netlify.com",
  "feed_url":"https://jsonfeed-to-rss.netlify.com/snapshots/readme-feed.json",
  "description": "A simple summary that describes the podcast.  It can have a few sentences.\n\nIf there is more than one paragraph, it gets truncated in some contexts.",
  "next_url":"https://jsonfeed-to-rss.netlify.com/snapshots/2017.json",
  "icon":"https://jsonfeed-to-rss.netlify.com/icon-512x512.png",
  "author":{
     "name":"Bret Comnes",
     "url":"https://bret.io",
     "avatar":"https://gravatar.com/avatar/8d8b82740cb7ca994449cccd1dfdef5f?size=512"
  },
  "_itunes":{
     "about":"https://github.com/bcomnes/jsonfeed-to-rss#itunes",
     "owner": {
       "email": "bcomnes@gmail.com"
     },
     "image": "https://jsonfeed-to-rss.netlify.com/icon-3000x3000.png",
     "category": "Sports & Recreation",
     "subcategory": "Outdoor"
  },
  "items":[
     {
        "date_published":"2018-04-07T20:48:02.000Z",
        "content_html":"<h1>Curam ad aut hactenus dentes cedere vigil</h1>\n<h2>Non Clitorio vertitur cavatur</h2>\n<p>Lorem markdownum edendi, non ad clamant solacia septem ambierantque. Scelus te\nmihi arcum fore nitidam; in dixit de simul.</p>",
        "url":"https://jsonfeed-to-rss.netlify.com/a-url-to-a-post",
        "id":"https://jsonfeed-to-rss.netlify.com/a-url-to-a-post-2018-04-07T20:48:02.000Z",
        "image": "https://jsonfeed-to-rss.netlify.com/a-url-to-a-post/episode-3000x3000.png",
        "_itunes": {
          "episode": 12
        },
        "attachments":[
           {
              "url":"https://jsonfeed-to-rss.netlify.com/a-url-to-a-post/attatchment.mp4",
              "mime_type":"audio/mpeg",
              "title":"Hey this is a podcast episode",
              "duration_in_seconds":12345,
              "size_in_bytes":1234
           }
        ]
     }
  ]
}

Example output:

<?xml version="1.0" encoding="utf-8"?>
<rss version="2.0" xmlns:atom="http://www.w3.org/2005/Atom" xmlns:dc="http://purl.org/dc/elements/1.1/" xmlns:content="http://purl.org/rss/1.0/modules/content/" xmlns:itunes="http://www.itunes.com/dtds/podcast-1.0.dtd">
  <channel>
    <atom:link href="https://jsonfeed-to-rss.netlify.com/snapshots/readme-feed-rss.xml" rel="self" type="application/rss+xml"/>
    <title>bret.io log</title>
    <link>https://jsonfeed-to-rss.netlify.com</link>
    <description>A simple summary that describes the podcast.  It can have a few sentences.

If there is more than one paragraph, it gets truncated in some contexts.</description>
    <language>en-us</language>
    <copyright>© 2018 Bret Comnes</copyright>
    <pubDate>Sat, 07 Apr 2018 20:48:02 GMT</pubDate>
    <category>Sports &amp; Recreation</category>
    <category>Outdoor</category>
    <generator>jsonfeed-to-rss 1.1.1 (https://github.com/bcomnes/jsonfeed-to-rss#readme)</generator>
    <docs>http://www.rssboard.org/rss-specification</docs>
    <image>
      <url>https://jsonfeed-to-rss.netlify.com/icon-512x512.png</url>
      <link>https://jsonfeed-to-rss.netlify.com</link>
      <title>bret.io log</title>
    </image>
    <itunes:author>Bret Comnes</itunes:author>
    <itunes:summary>A simple summary that describes the podcast.  It can have a few sentences.</itunes:summary>
    <itunes:subtitle>A simple summary that describes the podcast.</itunes:subtitle>
    <itunes:type>episodic</itunes:type>
    <itunes:owner>
      <itunes:name>Bret Comnes</itunes:name>
      <itunes:email>bcomnes@gmail.com</itunes:email>
    </itunes:owner>
    <itunes:image href="https://jsonfeed-to-rss.netlify.com/icon-3000x3000.png"/>
    <itunes:category text="Sports &amp; Recreation">
      <itunes:category text="Outdoor"/>
    </itunes:category>
    <item>
      <title>Curam ad aut hactenus dentes cedere vigil</title>
      <link>https://jsonfeed-to-rss.netlify.com/a-url-to-a-post</link>
      <dc:creator>Bret Comnes</dc:creator>
      <description>Curam ad aut hactenus dentes cedere vigil
Non Clitorio vertitur cavatur
Lorem markdownum edendi, non ad clamant solacia septem ambierantque. Scelus te
mihi arcum fore nitidam; in dixit de simul.</description>
      <content:encoded>
        <![CDATA[<h1>Curam ad aut hactenus dentes cedere vigil</h1>
<h2>Non Clitorio vertitur cavatur</h2>
<p>Lorem markdownum edendi, non ad clamant solacia septem ambierantque. Scelus te
mihi arcum fore nitidam; in dixit de simul.</p>]]>
      </content:encoded>
      <guid isPermaLink="false">https://jsonfeed-to-rss.netlify.com/a-url-to-a-post-2018-04-07T20:48:02.000Z</guid>
      <pubDate>Sat, 07 Apr 2018 20:48:02 GMT</pubDate>
      <enclosure type="audio/mpeg" url="https://jsonfeed-to-rss.netlify.com/a-url-to-a-post/attatchment.mp4" length="1234"/>
      <itunes:episodeType>full</itunes:episodeType>
      <itunes:title>Curam ad aut hactenus dentes cedere vigil</itunes:title>
      <itunes:author>Bret Comnes</itunes:author>
      <itunes:episode>12</itunes:episode>
      <itunes:subtitle>Curam ad aut hactenus dentes cedere vigil</itunes:subtitle>
      <itunes:summary>Curam ad aut hactenus dentes cedere vigil</itunes:summary>
      <itunes:image>https://jsonfeed-to-rss.netlify.com/a-url-to-a-post/episode-3000x3000.png</itunes:image>
      <itunes:duration>3:25:45</itunes:duration>
    </item>
  </channel>
</rss>

API

jsonfeedToRSS(parsedJsonfeed, opts)

Coverts a parsed JSON feed into an RSS feed. Returns the string of the rss feed.

Opts include:

{
  // a function that returns the rss feed url
  feedURLFn: (feedURL, jf) => feedURL.replace(/\.json\b/, '-rss.xml'),
  language: 'en-us',
  copyright: ${now.getFullYear()} ${jf.author && jf.author.name ? jf.author.name : ''}`,
  managingEditor,
  webMaster,
  idIsPermalink: false, // if guid is the permalink, you can set this true
  category, // array of categories.. will attempt to use iTunes categories if available
  ttl,
  skipHours,
  skipDays,
  itunes: !!jf._itunes // generate RSS feed with iTunes extensions
}

There is only one mapping implemented between jsonfeed and RSS:

Items

  • item.author.name || jf.author.name (recommended) maps to dc:creator.

The content:encoded field is used to store an html representation of content, and RSS's default description field is for a plain text representation.

Items

  • item.content_html (recommended) maps to a CDATA encoded content:encoded node.
  • item.content_text || striptags(item.content_html) (recommended) maps to an escaped description node. When creating an iTunes feed, description is truncated to 4000 characters.

If the itunes option is set to true (or if the jsonfeed._itunes extension object is included in the jsonfeed) the resulting RSS feed will include as many itunes extension tags as possible. You can override/set _itunes extension fields from the opts.itunes object.

All _itunes.property map directly to the RSS itunes:property extensions, but most have default mappings to standard JSONFeed properties. Its better to rely on the default JSONFeed fields, but you can override these mappings by including explicit _itunes extension properties in your JSONFeed.

  • There are a few extension fields that SHOULD be included, but dont map well. These are marked as (recommended).
  • There are fields that dont have a mapping that are definitely optional but CAN be included. These are marked as (optional).
  • There are fields that have default and acceptable mappings. These MAY be included but probably not. These are marked as (mapped).

Top-level

  • _itunes.owner.email (recommended) maps to itunes:owner.itunes:email.
  • _itunes.image (recommended) maps to itunes:image. Defaults to icon but the icon field does not meet the minimum requirements for this field. The icon field is a 512x512 image, where iTunes recommends Artwork that must be a minimum size of 1400 x 1400 pixels and a maximum size of 3000 x 3000 pixels, in JPEG or PNG format, 72 dpi, with appropriate file extensions (.jpg, .png), and in the RGB colorspace.
  • _itunes.category (recommended) maps to itunes:category. Defaults to opts.category[0]. Must be a valid category.
  • _itunes.subcategory (recommended) maps to itunes:category:itunes:category. Defaults to opts.category[1]. Must be a valid subcategory.
  • _itunes.explicit (recommended) maps to itunes:explicit. Defaults to unset.
  • _itunes.type (optional) maps to itunes:type. Defaults to episodic (newest first). The other option is serial (oldest first). Details.
  • _itunes.complete (optional) maps to itunes:complete. Defaults to null. Tells podcast clients to stop updating this feed ️️️forever. ⚠️
  • _itunes.block (optional) maps to itunes:block. Defaults to null. Prevents the feed from being added to Apple's podcast directory. Helpful for private or customer specific feeds.
  • _itunes.new_feed_url (optional) maps to itunes:new-feed-url. Used for moving feeds from an old url to a new url. When generating next_url (the next n older feed items), you could generate the converse url for the previous (newer) n items and store it here.
  • _itunes.author (mapped) maps to itunes:author. Defaults to author.name.
  • _itunes.summary (mapped) maps to itunes:summary. Defaults to the first paragraph of the generated description rss field.
  • _itunes.subtitle (mapped) maps to itunes:subtitle. Defaults to the first sentence of the generated itunes:summary.
  • _itunes.owner.name (mapped) maps to itunes:owner.itunes:name. Defaults to author.name.

Items

  • _itunes.episode (recommended) maps to itunes:episode. No fallback. Must be an integer > 0. Its recommended you put episode numbers here, instead of in the title.
  • _itunes.season (optional) maps to itunes:season.
  • _itunes.episode_type (optional) maps to itunes:episodeType, but must be one of full, trailer, or bonus. Defaults to full.
  • _itunes.block (optional) maps to itunes:block. Defaults to null. Prevents the item from being added to Apple's podcast directory. "For example, you might want to block a specific episode if you know that its content would otherwise cause the entire podcast to be removed from Apple Podcasts."
  • _itunes.is_closed_captioned (optional) maps to itunes:isClosedCaptioned.
  • _itunes.explicit (optional) maps to itunes:explicit. Defaults to null.
  • _itunes.title (mapped) maps to itunes:title. Falls back to item.title and then the generateTitle function.
  • _itunes.author (mapped) maps to itunes:author. Falls back to author.name || jf._itunes.author || jf.author.name.
  • _itunes.subtitle (mapped) maps to itunes:subtitle. Defaults to the first sentence of the generated _itunes.summary.
  • _itunes.summary (mapped) maps to itunes:summary. Defaults to the first paragraph of the generated plaintext description of the item.
  • _itunes.duration (mapped) maps to itunes:duration. Defaults to attachment.duration_in_seconds formatted as HH:MM:SS.
  • _itunes.image (mapped) maps to itunes:image. Defaults to image. Artwork must be a minimum size of 1400 x 1400 pixels and a maximum size of 3000 x 3000 pixels, in JPEG or PNG format, 72 dpi, with appropriate file extensions (.jpg, .png), and in the RGB colorspace. JSONFeed has no defined image restrictions on the image field, so it can be safely used for this purpose.

See also

Related projects

More iTunes RSS feed information

Reference RSS feeds

Snapshots

License

MIT