diff --git a/web/src/rss.js b/web/src/rss.js
index 691721911..d5f6d3077 100644
--- a/web/src/rss.js
+++ b/web/src/rss.js
@@ -42,27 +42,36 @@ async function getClaimsFromChannel(claimId, count) {
return await doClaimSearch(options);
}
-async function getFeed(channelClaim) {
- const replaceLineFeeds = (str) => str.replace(/(?:\r\n|\r|\n)/g, '
');
+async function getFeed(channelClaim, feedLink) {
+ const replaceLineFeeds = (str) => str.replace(/(?:\r\n|\r|\n)/g, '
');
+ const fmtDescription = (description) => replaceLineFeeds(description);
+ const sanitizeThumbsUrl = (url) => {
+ if (typeof url === 'string' && url.startsWith('https://')) {
+ return encodeURI(url).replace(/&/g, '%26');
+ }
+ return '';
+ };
const value = channelClaim.value;
const title = value ? value.title : channelClaim.name;
const options = {
- title: title + ' on ' + SITE_NAME,
- description: value && value.description ? replaceLineFeeds(value.description) : '',
- link: `${URL}/${channelClaim.name}:${channelClaim.claim_id}`,
favicon: URL + '/public/favicon.png',
generator: SITE_NAME + ' RSS Feed',
- image: value && value.thumbnail ? value.thumbnail.url : '',
+ title: title + ' on ' + SITE_NAME,
+ description: fmtDescription(value && value.description ? value.description : ''),
+ link: encodeURI(`${URL}/${channelClaim.name}:${channelClaim.claim_id}`),
+ image: sanitizeThumbsUrl(value && value.thumbnail ? value.thumbnail.url : ''),
+ feedLinks: {
+ rss: encodeURI(feedLink),
+ },
author: {
- name: channelClaim.name,
- link: URL + '/' + channelClaim.name + ':' + channelClaim.claim_id,
+ name: encodeURI(channelClaim.name),
+ link: encodeURI(URL + '/' + channelClaim.name + ':' + channelClaim.claim_id),
},
};
const feed = new Feed(options);
-
const latestClaims = await getClaimsFromChannel(channelClaim.claim_id, NUM_ENTRIES);
latestClaims.forEach((c) => {
@@ -70,12 +79,12 @@ async function getFeed(channelClaim) {
const value = c.value;
feed.addItem({
- guid: c.claim_id,
id: c.claim_id,
- title: value ? value.title : c.name,
- description: value && value.description ? replaceLineFeeds(value.description) : '',
- image: value && value.thumbnail ? value.thumbnail.url : '',
- link: URL + '/' + c.name + ':' + c.claim_id,
+ guid: encodeURI(URL + '/' + c.name + ':' + c.claim_id),
+ title: value && value.title ? value.title : c.name,
+ description: fmtDescription(value && value.description ? value.description : ''),
+ image: sanitizeThumbsUrl(value && value.thumbnail ? value.thumbnail.url : ''),
+ link: encodeURI(URL + '/' + c.name + ':' + c.claim_id),
date: new Date(meta ? meta.creation_timestamp * 1000 : null),
});
});
@@ -83,6 +92,12 @@ async function getFeed(channelClaim) {
return feed;
}
+function postProcess(feed) {
+ // Handle 'Feed' creating an invalid MIME type when trying to guess
+ // from 'https://thumbnails.lbry.com/UCgQ8eREJzR1dO' style of URLs.
+ return feed.replace(/type="image\/\/.*"\/>/g, 'type="image/*"/>');
+}
+
async function getRss(ctx) {
if (!ctx.params.claimName || !ctx.params.claimId) {
return 'Invalid URL';
@@ -93,8 +108,8 @@ async function getRss(ctx) {
return channelClaim;
}
- const feed = await getFeed(channelClaim);
- return feed.rss2();
+ const feed = await getFeed(channelClaim, `${URL}/$/rss/${ctx.params.claimName}/${ctx.params.claimId}`);
+ return postProcess(feed.rss2());
}
module.exports = { getRss };