diff --git a/lib/middleware/parameter.js b/lib/middleware/parameter.js
index 0c98d0a559..d35dc65147 100644
--- a/lib/middleware/parameter.js
+++ b/lib/middleware/parameter.js
@@ -6,6 +6,18 @@ const config = require('@/config').value;
let mercury_parser;
+const resolveRelativeLink = ($, elem, attr, baseUrl) => {
+ const $elem = $(elem);
+
+ if (baseUrl) {
+ try {
+ $elem.attr(attr, new URL($elem.attr(attr), baseUrl).href);
+ } catch (e) {
+ // no-empty
+ }
+ }
+};
+
module.exports = async (ctx, next) => {
await next();
@@ -76,50 +88,46 @@ module.exports = async (ctx, next) => {
$('script').remove();
- $('a').each((_, ele) => {
- const $ele = $(ele);
-
- // absolute link
- if (baseUrl) {
- try {
- $ele.attr('href', new URL($ele.attr('href'), baseUrl).href);
- } catch (e) {
- // no-empty
- }
- }
- });
-
$('img').each((_, ele) => {
const $ele = $(ele);
// fix lazyload
if (!$ele.attr('src')) {
- for (const key in ele.attribs) {
- const value = ele.attribs[key].trim();
- if (['.gif', '.png', '.jpg', '.webp'].some((suffix) => value.includes(suffix))) {
- $ele.attr('src', value);
- break;
+ const lazySrc = $ele.attr('data-src') || $ele.attr('data-original');
+ if (lazySrc) {
+ $ele.attr('src', lazySrc);
+ } else {
+ for (const key in ele.attribs) {
+ const value = ele.attribs[key].trim();
+ if (['.gif', '.png', '.jpg', '.webp'].some((suffix) => value.includes(suffix))) {
+ $ele.attr('src', value);
+ break;
+ }
}
}
}
- // absolute link
- if (baseUrl) {
- try {
- $ele.attr('src', new URL($ele.attr('src'), baseUrl).href);
- } catch (e) {
- // no-empty
- }
- }
-
- // referrerpolicy
- $ele.attr('referrerpolicy', 'no-referrer');
-
// redundant attributes
['onclick', 'onerror', 'onload'].forEach((e) => {
$ele.removeAttr(e);
});
});
+
+ // resolve relative link & fix referrer policy
+ // https://developer.mozilla.org/en-US/docs/Web/HTTP/Headers/Referrer-Policy
+ // https://www.w3schools.com/tags/att_href.asp
+ $('a, area').each((_, elem) => {
+ resolveRelativeLink($, elem, 'href', baseUrl);
+ // $(elem).attr('rel', 'noreferrer'); // currently no such a need
+ });
+ // https://www.w3schools.com/tags/att_src.asp
+ $('img, video, audio, source, iframe, embed, track').each((_, elem) => {
+ resolveRelativeLink($, elem, 'src', baseUrl);
+ });
+ $('img, iframe').each((_, elem) => {
+ $(elem).attr('referrerpolicy', 'no-referrer');
+ });
+
item.description = $('body').html() + '' + (config.suffix || '');
}
return item;
diff --git a/lib/v2/test/index.js b/lib/v2/test/index.js
index ceb94229a5..5535264a0b 100644
--- a/lib/v2/test/index.js
+++ b/lib/v2/test/index.js
@@ -98,6 +98,21 @@ module.exports = async (ctx) => {
link: `https://mock.com/DIYgod/RSSHub`,
author: `DIYgod`,
});
+ } else if (ctx.params.id === 'multimedia') {
+ item.push({
+ title: `Multimedia Title`,
+ description: `
+
+
+
+`,
+ pubDate: new Date(`2019-3-1`).toUTCString(),
+ link: `https://mock.com/DIYgod/RSSHub`,
+ author: `DIYgod`,
+ });
} else if (ctx.params.id === 'sort') {
item.push({
title: `Sort Title 0`,
@@ -187,6 +202,6 @@ module.exports = async (ctx) => {
link: 'https://github.com/DIYgod/RSSHub',
item,
allowEmpty: ctx.params.id === 'allow_empty',
- description: ctx.params.id === 'complicated' ? '
' : 'A test route for RSSHub',
+ description: ctx.params.id === 'complicated' ? '
' : ctx.params.id === 'multimedia' ? '' : 'A test route for RSSHub',
};
};
diff --git a/test/middleware/parameter.js b/test/middleware/parameter.js
index 24234fa1cc..e8afb7df20 100644
--- a/test/middleware/parameter.js
+++ b/test/middleware/parameter.js
@@ -280,6 +280,22 @@ describe('complicated_description', () => {
});
});
+describe('multimedia_description', () => {
+ it(`multimedia_description`, async () => {
+ const response = await request.get('/test/multimedia');
+ expect(response.status).toBe(200);
+ const parsed = await parser.parseString(response.text);
+ expect(parsed.items[0].content).toBe(`
+
+
+
+`);
+ });
+});
+
describe('sort', () => {
it(`sort`, async () => {
const response = await request.get('/test/sort');