diff --git a/docs/multimedia.md b/docs/multimedia.md
index 852477256a0f95..44ec929c9ea7d0 100644
--- a/docs/multimedia.md
+++ b/docs/multimedia.md
@@ -1211,11 +1211,17 @@ JavDB 有多个备用域名,本路由默认使用永久域名
+
-### 动漫
+### 剧集
+
+
+
+::: tip 提示
+可抓取內容根据服务器所在地区而定
+:::
-
+
## 哔嘀影视
diff --git a/docs/other.md b/docs/other.md
index 174456d1a512c0..c512f080ec838f 100644
--- a/docs/other.md
+++ b/docs/other.md
@@ -396,7 +396,7 @@ type 为 all 时,category 参数不支持 cost 和 free
### 发现用户
-
+
分类
| 推荐 | 最热 |
@@ -413,7 +413,7 @@ type 为 all 时,category 参数不支持 cost 和 free
### 用户动态
-
+
## 澳門特別行政區政府各公共部門獎助貸學金服務平台
@@ -427,15 +427,15 @@ type 为 all 时,category 参数不支持 cost 和 free
-## 百度搜索风云榜
+## 百度热搜
### 榜单
-
+
-| 实时热点 | 今日热点 | 七日热点 | 民生热点 | 娱乐热点 | 体育热点 |
-| ---- | ---- | ---- | ---- | ---- | ---- |
-| 1 | 341 | 42 | 342 | 344 | 11 |
+| 热搜榜 | 小说榜 | 电影榜 | 电视剧榜 | 汽车榜 | 游戏榜 |
+| -------- | ----- | ----- | -------- | --- | ---- |
+| realtime | novel | movie | teleplay | car | game |
diff --git a/docs/social-media.md b/docs/social-media.md
index 4d7443535900c7..cd7a3ea13e6a0f 100644
--- a/docs/social-media.md
+++ b/docs/social-media.md
@@ -1183,11 +1183,11 @@ YouTube 官方亦有提供频道 RSS,形如
+
### 用户个人文章
-
+
## 即刻
diff --git a/lib/middleware/parameter.js b/lib/middleware/parameter.js
index ac7674ab68926c..1a89e63e0ce22f 100644
--- a/lib/middleware/parameter.js
+++ b/lib/middleware/parameter.js
@@ -140,9 +140,11 @@ module.exports = async (ctx, next) => {
item.description = $('body').html() + '' + (config.suffix || '');
- const quote = item._extra?.links?.find((e) => e.type === 'quote');
- if (quote && $('.rsshub-quote').length) {
- quote.content_html = $.html($('.rsshub-quote'));
+ if (item._extra?.links && $('.rsshub-quote').length) {
+ item._extra?.links?.map((e) => {
+ e.content_html = $.html($('.rsshub-quote'));
+ return e;
+ });
}
}
return item;
@@ -271,7 +273,7 @@ module.exports = async (ctx, next) => {
});
item.author = author || (parsed_result ? parsed_result.author : '');
- item.description = parsed_result ? entities.decodeXML(parsed_result.content) : description;
+ item.description = parsed_result && parsed_result.content.length > 40 ? entities.decodeXML(parsed_result.content) : description;
});
await Promise.all(tasks);
}
diff --git a/lib/router.js b/lib/router.js
index 3343e3fc2c9def..84d59ee055921d 100644
--- a/lib/router.js
+++ b/lib/router.js
@@ -176,8 +176,8 @@ router.get('/geektime/news', lazyloadRouteHandler('./routes/geektime/news'));
router.get('/qdaily/:type/:id', lazyloadRouteHandler('./routes/qdaily/index'));
// 爱奇艺
-router.get('/iqiyi/dongman/:id', lazyloadRouteHandler('./routes/iqiyi/dongman'));
-router.get('/iqiyi/user/video/:uid', lazyloadRouteHandler('./routes/iqiyi/video'));
+// router.get('/iqiyi/dongman/:id', lazyloadRouteHandler('./routes/iqiyi/dongman'));
+// router.get('/iqiyi/user/video/:uid', lazyloadRouteHandler('./routes/iqiyi/video'));
// 南方周末
router.get('/infzm/:id', lazyloadRouteHandler('./routes/infzm/news'));
@@ -950,7 +950,7 @@ router.get('/geekpark/breakingnews', lazyloadRouteHandler('./routes/geekpark/bre
// 百度
router.get('/baidu/doodles', lazyloadRouteHandler('./routes/baidu/doodles'));
-router.get('/baidu/topwords/:boardId?', lazyloadRouteHandler('./routes/baidu/topwords'));
+// router.get('/baidu/topwords/:boardId?', lazyloadRouteHandler('./routes/baidu/topwords'));
router.get('/baidu/daily', lazyloadRouteHandler('./routes/baidu/daily'));
// 搜狗
@@ -1505,8 +1505,8 @@ router.get('/bupt/news', lazyloadRouteHandler('./routes/universities/bupt/news')
router.get('/bupt/funbox', lazyloadRouteHandler('./routes/universities/bupt/funbox'));
// VOCUS 方格子
-router.get('/vocus/publication/:id', lazyloadRouteHandler('./routes/vocus/publication'));
-router.get('/vocus/user/:id', lazyloadRouteHandler('./routes/vocus/user'));
+// router.get('/vocus/publication/:id', lazyloadRouteHandler('./routes/vocus/publication'));
+// router.get('/vocus/user/:id', lazyloadRouteHandler('./routes/vocus/user'));
// 一亩三分地 1point3acres
router.get('/1point3acres/blog/:category?', lazyloadRouteHandler('./routes/1point3acres/blog'));
diff --git a/lib/routes/baidu/topwords.js b/lib/routes/baidu/topwords.js
deleted file mode 100644
index cebab5f6dafd73..00000000000000
--- a/lib/routes/baidu/topwords.js
+++ /dev/null
@@ -1,38 +0,0 @@
-const got = require('@/utils/got');
-
-module.exports = async (ctx) => {
- const { boardId = 1 } = ctx.params;
- const response = await got({
- method: 'get',
- url: `http://top.baidu.com/mobile_v2/buzz?b=${boardId}`,
- });
-
- const { board, topwords, descs } = response.data.result;
- const items = topwords.map((item, index) => {
- const title = item.keyword;
- const content = descs[index].content;
- const desc = content
- ? content.data[0]
- : {
- originlink: `https://www.baidu.com/s?ie=utf-8&wd=${encodeURIComponent(title)}`,
- title,
- description: title,
- pubDate: Date.now(),
- };
-
- return {
- title,
- description: `
- ${desc.title}
- ${desc.description || ''}
- `,
- link: desc.originlink,
- pubDate: new Date(desc.pubDate).toUTCString(),
- };
- });
-
- ctx.state.data = {
- title: `百度搜索风云榜-${board.boardname}`,
- item: items,
- };
-};
diff --git a/lib/routes/iqiyi/dongman.js b/lib/routes/iqiyi/dongman.js
deleted file mode 100644
index d7f7de0fdaa094..00000000000000
--- a/lib/routes/iqiyi/dongman.js
+++ /dev/null
@@ -1,42 +0,0 @@
-const got = require('@/utils/got');
-const cheerio = require('cheerio');
-
-module.exports = async (ctx) => {
- const id = ctx.params.id;
-
- const response = await got({
- method: 'get',
- url: `http://www.iqiyi.com/${id}.html`,
- headers: {
- Host: 'www.iqiyi.com',
- Referer: `http://www.iqiyi.com/${id}.html`,
- },
- });
-
- const data = response.data;
- const $ = cheerio.load(data);
- const description = $('.episodeIntro-brief').text();
- const list = $('li[data-albumlist-elem="playItem"]');
-
- ctx.state.data = {
- title: $('title').text().split('-')[0],
- link: `http://www.iqiyi.com/${id}.html`,
- description,
- item:
- list &&
- list
- .map((index, item) => {
- const episode = $(item).find('p.site-piclist_info_title a').text().trim();
- const describe = $(item).find('p.site-piclist_info_describe a').text();
- const title = `${episode}-${describe}`;
-
- return {
- title,
- description: ``,
- link: $(item).find('.site-piclist_pic .site-piclist_pic_link').attr('href'),
- };
- })
- .get()
- .reverse(),
- };
-};
diff --git a/lib/routes/vocus/publication.js b/lib/routes/vocus/publication.js
deleted file mode 100644
index 222d0b6346af4d..00000000000000
--- a/lib/routes/vocus/publication.js
+++ /dev/null
@@ -1,19 +0,0 @@
-const got = require('@/utils/got');
-const { ProcessFeed } = require('./utils');
-
-module.exports = async (ctx) => {
- const { id } = ctx.params;
- const link = `https://vocus.cc/${id}/home`;
- const configs = { headers: { Referer: link } };
-
- const { _id, title, abstract } = (await got.get(`https://api.sosreader.com/api/publication/${id}`, configs)).data;
- const { articles } = (await got.get(`https://api.sosreader.com/api/articles?publicationId=${_id}&status=2&num=10&page=1`, configs)).data;
- const items = await ProcessFeed(articles, `https://vocus.cc/${id}`, ctx.cache);
-
- ctx.state.data = {
- title: `${title} - 方格子`,
- link,
- description: abstract,
- item: items,
- };
-};
diff --git a/lib/routes/vocus/utils.js b/lib/routes/vocus/utils.js
deleted file mode 100644
index 48cdc8e685fa83..00000000000000
--- a/lib/routes/vocus/utils.js
+++ /dev/null
@@ -1,29 +0,0 @@
-const got = require('@/utils/got');
-
-const load = async (link, configs) => ({
- description: (await got.get(link, configs)).data.article.content,
-});
-
-const ProcessFeed = (list, host, caches) => {
- const configs = { headers: { Referer: host } };
-
- return Promise.all(
- list.map(async (item) => {
- const itemUrl = `https://api.sosreader.com/api/article/${item._id}`;
-
- const single = {
- title: item.title,
- author: item.user.fullname,
- pubDate: new Date(item.updatedAt).toUTCString(),
- link: `${host}/${item._id}`,
- };
-
- const other = await caches.tryGet(itemUrl, () => load(itemUrl, configs));
- return Promise.resolve(Object.assign({}, single, other));
- })
- );
-};
-
-module.exports = {
- ProcessFeed,
-};
diff --git a/lib/v2/baidu/maintainer.js b/lib/v2/baidu/maintainer.js
index b63e79ea64109d..8e0f88c0fd9a37 100644
--- a/lib/v2/baidu/maintainer.js
+++ b/lib/v2/baidu/maintainer.js
@@ -5,4 +5,5 @@ module.exports = {
'/tieba/post/:id': ['u3u'],
'/tieba/post/lz/:id': ['u3u'],
'/tieba/user/:uid': ['igxlin', 'nczitzk'],
+ '/top/:board?': ['xyqfer'],
};
diff --git a/lib/v2/baidu/radar.js b/lib/v2/baidu/radar.js
index 96e5ff46f4634a..9803ecbcc7722d 100644
--- a/lib/v2/baidu/radar.js
+++ b/lib/v2/baidu/radar.js
@@ -56,5 +56,13 @@ module.exports = {
},
},
],
+ top: [
+ {
+ title: '热搜榜单',
+ docs: 'https://docs.rsshub.app/other.html#bai-du-re-sou',
+ source: ['/board'],
+ target: (_, url) => `/baidu/top/${new URL(url).searchParams.get('tab')}`,
+ },
+ ],
},
};
diff --git a/lib/v2/baidu/router.js b/lib/v2/baidu/router.js
index 585f674c7606eb..f01ef64f9c7d75 100644
--- a/lib/v2/baidu/router.js
+++ b/lib/v2/baidu/router.js
@@ -5,4 +5,5 @@ module.exports = (router) => {
router.get('/tieba/post/:id', require('./tieba/post'));
router.get('/tieba/post/lz/:id', require('./tieba/post'));
router.get('/tieba/user/:uid', require('./tieba/user'));
+ router.get('/top/:board?', require('./top'));
};
diff --git a/lib/v2/baidu/templates/top.art b/lib/v2/baidu/templates/top.art
new file mode 100644
index 00000000000000..c7f4b680bf85b8
--- /dev/null
+++ b/lib/v2/baidu/templates/top.art
@@ -0,0 +1,9 @@
+{{ if item.img }}
+
+{{ /if }}
+{{ if item.show }}
+ {{ each item.show s }}
+ {{ s }}
+ {{ /each }}
+{{ /if }}
+{{ item.desc }}
diff --git a/lib/v2/baidu/top.js b/lib/v2/baidu/top.js
new file mode 100644
index 00000000000000..2dfb374cf7fc64
--- /dev/null
+++ b/lib/v2/baidu/top.js
@@ -0,0 +1,34 @@
+const got = require('@/utils/got');
+const cheerio = require('cheerio');
+const { art } = require('@/utils/render');
+const path = require('path');
+
+module.exports = async (ctx) => {
+ const { board = 'realtime' } = ctx.params;
+ const link = `https://top.baidu.com/board?tab=${board}`;
+ const { data: response } = await got(link);
+
+ const $ = cheerio.load(response);
+
+ const { data } = JSON.parse(
+ $('#sanRoot')
+ .contents()
+ .filter((e) => e.nodeType === 8)
+ .prevObject[0].data.match(/s-data:(.*)/)[1]
+ );
+
+ const items = data.cards[0].content.map((item) => ({
+ title: item.word,
+ description: art(path.join(__dirname, 'templates/top.art'), {
+ item,
+ }),
+ link: item.rawUrl,
+ }));
+
+ ctx.state.data = {
+ title: `${data.curBoardName} - 百度热搜`,
+ description: $('meta[name="description"]').attr('content'),
+ link,
+ item: items,
+ };
+};
diff --git a/lib/v2/iqiyi/album.js b/lib/v2/iqiyi/album.js
new file mode 100644
index 00000000000000..a928bd50dde8ee
--- /dev/null
+++ b/lib/v2/iqiyi/album.js
@@ -0,0 +1,62 @@
+const got = require('@/utils/got');
+const cheerio = require('cheerio');
+const { parseDate } = require('@/utils/parse-date');
+const { art } = require('@/utils/render');
+const path = require('path');
+
+module.exports = async (ctx) => {
+ const { id } = ctx.params;
+
+ const { data: response } = await got(`https://www.iq.com/album/${id}`);
+
+ const $ = cheerio.load(response);
+ const nextData = JSON.parse($('#__NEXT_DATA__').text());
+ const { album } = nextData.props.initialState;
+
+ const {
+ data: { data: baseInfo },
+ } = await got(`https://pcw-api.iqiyi.com/album/album/baseinfo/${album.videoAlbumInfo.albumId}`);
+
+ if (Object.keys(album.cacheAlbumList).length === 0) {
+ throw Error(`${baseInfo.name} is not available in this server region.`);
+ }
+
+ let pos = 1;
+ let hasMore = false;
+ let epgs = [];
+ do {
+ const {
+ data: { data },
+ // eslint-disable-next-line no-await-in-loop
+ } = await got(`https://pcw-api.iq.com/api/v2/episodeListSource/${album.videoAlbumInfo.albumId}`, {
+ searchParams: {
+ platformId: 3,
+ modeCode: 'intl',
+ langCode: 'zh_cn',
+ endOrder: album.videoAlbumInfo.maxOrder,
+ startOrder: pos,
+ },
+ });
+ epgs = [...epgs, ...data.epg];
+ pos = data.pos;
+ hasMore = data.hasMore;
+ } while (hasMore);
+
+ const items = epgs.map((item) => ({
+ title: item.name,
+ description: art(path.join(__dirname, 'templates/album.art'), {
+ item,
+ }),
+ link: `https://www.iq.com/play/${item.playLocSuffix}`,
+ pubDate: parseDate(item.initIssueTime),
+ }));
+
+ ctx.state.data = {
+ title: baseInfo.name,
+ description: baseInfo.description,
+ image: album.videoAlbumInfo.albumFocus1024,
+ link: `https://www.iq.com/album/${album.videoAlbumInfo.albumLocSuffix}`,
+ item: items,
+ allowEmpty: true,
+ };
+};
diff --git a/lib/v2/iqiyi/maintainer.js b/lib/v2/iqiyi/maintainer.js
new file mode 100644
index 00000000000000..c664168821add6
--- /dev/null
+++ b/lib/v2/iqiyi/maintainer.js
@@ -0,0 +1,4 @@
+module.exports = {
+ '/album/:id': ['TonyRL'],
+ '/user/video/:uid': ['talengu'],
+};
diff --git a/lib/v2/iqiyi/radar.js b/lib/v2/iqiyi/radar.js
new file mode 100644
index 00000000000000..6bc0f95db0cbb5
--- /dev/null
+++ b/lib/v2/iqiyi/radar.js
@@ -0,0 +1,24 @@
+module.exports = {
+ 'iq.com': {
+ _name: '爱奇艺',
+ '.': [
+ {
+ title: '剧集',
+ docs: 'https://docs.rsshub.app/multimedia.html#ai-qi-yi',
+ source: ['/album/:id'],
+ target: '/iqiyi/:category/:id',
+ },
+ ],
+ },
+ 'iqiyi.com': {
+ _name: '爱奇艺',
+ '.': [
+ {
+ title: '用户视频',
+ docs: 'https://docs.rsshub.app/multimedia.html#ai-qi-yi',
+ source: ['/u/:uid/*'],
+ target: '/iqiyi/user/video/:uid',
+ },
+ ],
+ },
+};
diff --git a/lib/v2/iqiyi/router.js b/lib/v2/iqiyi/router.js
new file mode 100644
index 00000000000000..126505fcbf3461
--- /dev/null
+++ b/lib/v2/iqiyi/router.js
@@ -0,0 +1,4 @@
+module.exports = (router) => {
+ router.get('/album/:id', require('./album'));
+ router.get('/user/video/:uid', require('./video'));
+};
diff --git a/lib/v2/iqiyi/templates/album.art b/lib/v2/iqiyi/templates/album.art
new file mode 100644
index 00000000000000..14b1e8dd5e13f8
--- /dev/null
+++ b/lib/v2/iqiyi/templates/album.art
@@ -0,0 +1 @@
+
diff --git a/lib/routes/iqiyi/video.js b/lib/v2/iqiyi/video.js
similarity index 100%
rename from lib/routes/iqiyi/video.js
rename to lib/v2/iqiyi/video.js
diff --git a/lib/v2/mysql/release.js b/lib/v2/mysql/release.js
index 7997b7daf65072..b2cffdfc18db71 100644
--- a/lib/v2/mysql/release.js
+++ b/lib/v2/mysql/release.js
@@ -1,15 +1,19 @@
const got = require('@/utils/got');
+const config = require('@/config').value;
const cheerio = require('cheerio');
module.exports = async (ctx) => {
const version = ctx.params.version ?? '8.0';
const rootUrl = 'https://dev.mysql.com';
- const currentUrl = `${rootUrl}/doc/relnotes/mysql/${version}/en`;
+ const currentUrl = `${rootUrl}/doc/relnotes/mysql/${version}/en/`;
const response = await got({
method: 'get',
url: currentUrl,
+ headers: {
+ 'user-agent': config.trueUA,
+ },
});
const $ = cheerio.load(response.data);
@@ -22,7 +26,7 @@ module.exports = async (ctx) => {
return {
title: item.text(),
- link: `${currentUrl}/${item.attr('href')}`,
+ link: `${currentUrl}${item.attr('href')}`,
};
});
@@ -32,6 +36,9 @@ module.exports = async (ctx) => {
const detailResponse = await got({
method: 'get',
url: item.link,
+ headers: {
+ 'user-agent': config.trueUA,
+ },
});
const content = cheerio.load(detailResponse.data);
diff --git a/lib/v2/vocus/maintainer.js b/lib/v2/vocus/maintainer.js
new file mode 100644
index 00000000000000..f1c5f11ef798d0
--- /dev/null
+++ b/lib/v2/vocus/maintainer.js
@@ -0,0 +1,4 @@
+module.exports = {
+ '/publication/:id': ['Maecenas'],
+ '/user/:id': ['LogicJake'],
+};
diff --git a/lib/v2/vocus/publication.js b/lib/v2/vocus/publication.js
new file mode 100644
index 00000000000000..603d5b110b5f7f
--- /dev/null
+++ b/lib/v2/vocus/publication.js
@@ -0,0 +1,42 @@
+const got = require('@/utils/got');
+const { processList, ProcessFeed, baseUrl, apiUrl } = require('./utils');
+
+module.exports = async (ctx) => {
+ const { id } = ctx.params;
+ const link = `${baseUrl}/${id}/home`;
+
+ const publicationData = await ctx.cache.tryGet(`vocus:publication:${id}`, async () => {
+ const { data: publicationData } = await got(`${apiUrl}/api/publication/${id}`, {
+ headers: {
+ referer: link,
+ },
+ });
+ return {
+ _id: publicationData._id,
+ title: publicationData.title,
+ abstract: publicationData.abstract,
+ };
+ });
+
+ const {
+ data: { articles },
+ } = await got(`${apiUrl}/api/articles`, {
+ headers: {
+ referer: link,
+ },
+ searchParams: {
+ publicationId: publicationData._id,
+ },
+ });
+
+ const list = processList(articles);
+
+ const items = await ProcessFeed(list, ctx.cache.tryGet);
+
+ ctx.state.data = {
+ title: `${publicationData.title} - 文章列表|方格子 vocus`,
+ link,
+ description: publicationData.abstract,
+ item: items,
+ };
+};
diff --git a/lib/v2/vocus/radar.js b/lib/v2/vocus/radar.js
new file mode 100644
index 00000000000000..710871db3208a8
--- /dev/null
+++ b/lib/v2/vocus/radar.js
@@ -0,0 +1,19 @@
+module.exports = {
+ 'vocus.cc': {
+ _name: '方格子',
+ '.': [
+ {
+ title: '出版專題',
+ docs: 'https://docs.rsshub.app/social-media.html#fang-ge-zi',
+ source: ['/:id/home', '/:id/introduce'],
+ target: '/vocus/publication/:id',
+ },
+ {
+ title: '用户个人文章',
+ docs: 'https://docs.rsshub.app/social-media.html#fang-ge-zi',
+ source: ['/user/:id'],
+ target: (params) => `/vocus/user/${params.id.replace('@', '')}`,
+ },
+ ],
+ },
+};
diff --git a/lib/v2/vocus/router.js b/lib/v2/vocus/router.js
new file mode 100644
index 00000000000000..7767e7a3bfd28c
--- /dev/null
+++ b/lib/v2/vocus/router.js
@@ -0,0 +1,4 @@
+module.exports = (router) => {
+ router.get('/publication/:id', require('./publication'));
+ router.get('/user/:id', require('./user'));
+};
diff --git a/lib/v2/vocus/user.js b/lib/v2/vocus/user.js
new file mode 100644
index 00000000000000..ddb82d9a58e82e
--- /dev/null
+++ b/lib/v2/vocus/user.js
@@ -0,0 +1,43 @@
+const got = require('@/utils/got');
+const { processList, ProcessFeed, baseUrl, apiUrl } = require('./utils');
+
+module.exports = async (ctx) => {
+ const { id } = ctx.params;
+ const link = `${baseUrl}/user/@${id}`;
+ const userData = await ctx.cache.tryGet(`vocus:user:${id}`, async () => {
+ const { data: userData } = await got(`${apiUrl}/api/users/${id}`, {
+ headers: {
+ referer: link,
+ },
+ });
+ return {
+ _id: userData._id,
+ fullname: userData.fullname,
+ avatarUrl: userData.avatarUrl,
+ intro: userData.intro,
+ };
+ });
+
+ const {
+ data: { articles },
+ } = await got(`${apiUrl}/api/articles`, {
+ headers: {
+ referer: link,
+ },
+ searchParams: {
+ userId: userData._id,
+ },
+ });
+
+ const list = processList(articles);
+
+ const items = await ProcessFeed(list, ctx.cache.tryGet);
+
+ ctx.state.data = {
+ title: `${userData.fullname}|方格子 vocus`,
+ link,
+ description: userData.intro,
+ image: userData.avatarUrl,
+ item: items,
+ };
+};
diff --git a/lib/v2/vocus/utils.js b/lib/v2/vocus/utils.js
new file mode 100644
index 00000000000000..4821a71e8e856b
--- /dev/null
+++ b/lib/v2/vocus/utils.js
@@ -0,0 +1,51 @@
+const got = require('@/utils/got');
+const cheerio = require('cheerio');
+const { parseDate } = require('@/utils/parse-date');
+
+const baseUrl = 'https://vocus.cc';
+const apiUrl = 'https://api.vocus.cc';
+
+const processList = (articleData) =>
+ articleData.map((item) => ({
+ title: item.title,
+ description: item.abstract,
+ pubDate: parseDate(item.createdAt),
+ link: `${baseUrl}/article/${item._id}`,
+ author: item.user.fullname,
+ _id: item._id,
+ }));
+
+const ProcessFeed = (list, tryGet) =>
+ Promise.all(
+ list.map((item) =>
+ tryGet(item.link, async () => {
+ const {
+ data: { article },
+ } = await got(`${apiUrl}/api/article/${item._id}`, {
+ headers: {
+ referer: item.link,
+ },
+ });
+
+ const $ = cheerio.load(article.content, null, false);
+
+ $('div.draft--imgNormal').each((_, elem) => (elem.name = 'figure'));
+ $('.image-block-prerender').each((_, elem) => {
+ elem.name = 'img';
+ elem.attribs.src = elem.attribs['data-src'].split('?')[0];
+ });
+
+ item.description = $.html();
+ item.category = article.tags?.map((tag) => tag.title);
+
+ return item;
+ })
+ )
+ );
+
+module.exports = {
+ processList,
+ ProcessFeed,
+ baseUrl,
+ apiUrl,
+};
diff --git a/lib/v2/youtube/user.js b/lib/v2/youtube/user.js
index d722dbd0819b3d..6164e4c92da564 100644
--- a/lib/v2/youtube/user.js
+++ b/lib/v2/youtube/user.js
@@ -1,6 +1,8 @@
const utils = require('./utils');
const config = require('@/config').value;
const { parseDate } = require('@/utils/parse-date');
+const got = require('@/utils/got');
+const cheerio = require('cheerio');
module.exports = async (ctx) => {
if (!config.youtube || !config.youtube.key) {
@@ -9,13 +11,23 @@ module.exports = async (ctx) => {
const username = ctx.params.username;
const embed = !ctx.params.embed;
- const playlistId = (await utils.getChannelWithUsername(username, 'contentDetails', ctx.cache)).data.items[0].contentDetails.relatedPlaylists.uploads;
+ let playlistId;
+ let channelName;
+ if (username.startsWith('@')) {
+ const link = `https://www.youtube.com/${username}`;
+ const response = await got(link);
+ const $ = cheerio.load(response.data);
+ const channelId = $('meta[itemprop="channelId"]').attr('content');
+ channelName = $('meta[itemprop="name"]').attr('content');
+ playlistId = (await utils.getChannelWithId(channelId, 'contentDetails', ctx.cache)).data.items[0].contentDetails.relatedPlaylists.uploads;
+ }
+ playlistId = playlistId || (await utils.getChannelWithUsername(username, 'contentDetails', ctx.cache)).data.items[0].contentDetails.relatedPlaylists.uploads;
const data = (await utils.getPlaylistItems(playlistId, 'snippet', ctx.cache)).data.items;
ctx.state.data = {
- title: `${username} - YouTube`,
- link: `https://www.youtube.com/user/${username}`,
+ title: `${channelName || username} - YouTube`,
+ link: username.startsWith('@') ? `https://www.youtube.com/${username}` : `https://www.youtube.com/user/${username}`,
description: `YouTube user ${username}`,
item: data
.filter((d) => d.snippet.title !== 'Private video' && d.snippet.title !== 'Deleted video')
diff --git a/package.json b/package.json
index bba3ffdfced612..49d4c8a6bf61f1 100644
--- a/package.json
+++ b/package.json
@@ -91,7 +91,7 @@
"dependencies": {
"@koa/router": "12.0.0",
"@postlight/parser": "2.2.3",
- "@sentry/node": "7.34.0",
+ "@sentry/node": "7.35.0",
"aes-js": "3.1.2",
"art-template": "4.13.2",
"bbcodejs": "0.0.4",
@@ -131,7 +131,7 @@
"pidusage": "3.0.2",
"plist": "3.0.6",
"proxy-chain": "2.2.0",
- "puppeteer": "19.6.2",
+ "puppeteer": "19.6.3",
"puppeteer-extra": "3.3.4",
"puppeteer-extra-plugin-stealth": "2.11.1",
"query-string": "7.1.3",
diff --git a/yarn.lock b/yarn.lock
index 53537d09bcf6f9..38287f8431f126 100644
--- a/yarn.lock
+++ b/yarn.lock
@@ -1546,39 +1546,39 @@
domhandler "^5.0.3"
selderee "^0.10.0"
-"@sentry/core@7.34.0":
- version "7.34.0"
- resolved "https://registry.yarnpkg.com/@sentry/core/-/core-7.34.0.tgz#bfda8d386cf7343200aa9fb7a7a26e99b839fc0c"
- integrity sha512-J1oxsYZX1N0tkEcaHt/uuDqk6zOnaivyampp+EvBsUMCdemjg7rwKvawlRB0ZtBEQu3HAhi8zecm03mlpWfCDw==
+"@sentry/core@7.35.0":
+ version "7.35.0"
+ resolved "https://registry.yarnpkg.com/@sentry/core/-/core-7.35.0.tgz#2d6d3ebb3224bd3a1321da3afa4a7e2900b9bb1a"
+ integrity sha512-j+UJaWDUyLCWOTKMrDFivy/rH5QuSvPK9TsOmYOIFctSKfp+e9Ap0cPRPXNObwim2YTpN4wpl7TqDGDANTKhuQ==
dependencies:
- "@sentry/types" "7.34.0"
- "@sentry/utils" "7.34.0"
+ "@sentry/types" "7.35.0"
+ "@sentry/utils" "7.35.0"
tslib "^1.9.3"
-"@sentry/node@7.34.0":
- version "7.34.0"
- resolved "https://registry.yarnpkg.com/@sentry/node/-/node-7.34.0.tgz#acf51e40b1ecbd91d7bf2df55c47ae1b30c39b40"
- integrity sha512-VM4XeydRdgeaNTRe8kwqYg2oNPddVyY74PlCFEFnPEN1NccycNuwiFno68kNrApeqxxLlTTmzkJy0BWo16x2Yg==
+"@sentry/node@7.35.0":
+ version "7.35.0"
+ resolved "https://registry.yarnpkg.com/@sentry/node/-/node-7.35.0.tgz#5ba48d4c4271c0304f65f0a94d429bfea49e01c2"
+ integrity sha512-uenomjlwSk1zX4gyNV6DdJFQXgDzzdLUcTCFWoO2D3sDqCGiJO6fmRXX+kVVanYcRXfKg14ko5uelfCj6pq9BQ==
dependencies:
- "@sentry/core" "7.34.0"
- "@sentry/types" "7.34.0"
- "@sentry/utils" "7.34.0"
+ "@sentry/core" "7.35.0"
+ "@sentry/types" "7.35.0"
+ "@sentry/utils" "7.35.0"
cookie "^0.4.1"
https-proxy-agent "^5.0.0"
lru_map "^0.3.3"
tslib "^1.9.3"
-"@sentry/types@7.34.0":
- version "7.34.0"
- resolved "https://registry.yarnpkg.com/@sentry/types/-/types-7.34.0.tgz#e0dc6a927dd13e4cacbca7bfee67a088885e8309"
- integrity sha512-K+OeHIrl35PSYn6Zwqe4b8WWyAJQoI5NeWxHVkM7oQTGJ1YLG4BvLsR+UiUXnKdR5krE4EDtEA5jLsDlBEyPvw==
+"@sentry/types@7.35.0":
+ version "7.35.0"
+ resolved "https://registry.yarnpkg.com/@sentry/types/-/types-7.35.0.tgz#08bd28b03dcecdb52928c604da9b2160702926b5"
+ integrity sha512-gy1PhwYvER/F80N+ZI06PjMk55xAZ4P+r3jomsMnOXQBWzx2VEEpc2fS/3B21wymxSl+mjh+5sUlk/JpxxOQvQ==
-"@sentry/utils@7.34.0":
- version "7.34.0"
- resolved "https://registry.yarnpkg.com/@sentry/utils/-/utils-7.34.0.tgz#32fb6db8b352477d219ddff8200372959c68b445"
- integrity sha512-VIHHXEBw0htzqxnU8A7WkXKvmsG2pZVqHlAn0H9W/yyFQtXMuP1j1i0NsjADB/3JXUKK83kTNWGzScXvp0o+Jg==
+"@sentry/utils@7.35.0":
+ version "7.35.0"
+ resolved "https://registry.yarnpkg.com/@sentry/utils/-/utils-7.35.0.tgz#e139e2edc0a11c3b7ff429159412782e9ae0a0f3"
+ integrity sha512-xB/uVNXrfSwQj5fZsYOHr70ORq9qNT+9FAoUGffAQUyVjRhXG27KxsstK1Rv2yt+FBCHY06e3vE4K9B4zwSe7Q==
dependencies:
- "@sentry/types" "7.34.0"
+ "@sentry/types" "7.35.0"
tslib "^1.9.3"
"@sinclair/typebox@^0.25.16":
@@ -11423,10 +11423,10 @@ pupa@^2.0.1:
dependencies:
escape-goat "^2.0.0"
-puppeteer-core@19.6.2:
- version "19.6.2"
- resolved "https://registry.yarnpkg.com/puppeteer-core/-/puppeteer-core-19.6.2.tgz#a873a3eb7a8f843c01c7e48e1ed595a54c751c8f"
- integrity sha512-il7uK658MNC1FlxPABvcnv1RdpDa9CaBFHzvtEsl+9Y4tbAJKZurkegpcvWeIWcRYGiuBIVo+t+ZSh3G82CCjw==
+puppeteer-core@19.6.3:
+ version "19.6.3"
+ resolved "https://registry.yarnpkg.com/puppeteer-core/-/puppeteer-core-19.6.3.tgz#e3334fbb4ccb2c1ca6f4597e2f082de5a80599da"
+ integrity sha512-8MbhioSlkDaHkmolpQf9Z7ui7jplFfOFTnN8d5kPsCazRRTNIH6/bVxPskn0v5Gh9oqOBlknw0eHH0/OBQAxpQ==
dependencies:
cross-fetch "3.1.5"
debug "4.3.4"
@@ -11486,16 +11486,16 @@ puppeteer-extra@3.3.4:
debug "^4.1.1"
deepmerge "^4.2.2"
-puppeteer@19.6.2:
- version "19.6.2"
- resolved "https://registry.yarnpkg.com/puppeteer/-/puppeteer-19.6.2.tgz#a8630207c68d6b6047763d1754d184b8a585325d"
- integrity sha512-Y5OAXXwXLfJYbl0dEFg8JKIhvCGxn+UYaBW9yra9ErmIhkVroDnYusM6oYxJCt/YIfC2pQWhvhxoZyf/E5fV6w==
+puppeteer@19.6.3:
+ version "19.6.3"
+ resolved "https://registry.yarnpkg.com/puppeteer/-/puppeteer-19.6.3.tgz#4edc7ea87f7e7e7b2885395326a6c9e5a222a10b"
+ integrity sha512-K03xTtGDwS6cBXX/EoqoZxglCUKcX2SLIl92fMnGMRjYpPGXoAV2yKEh3QXmXzKqfZXd8TxjjFww+tEttWv8kw==
dependencies:
cosmiconfig "8.0.0"
https-proxy-agent "5.0.1"
progress "2.0.3"
proxy-from-env "1.1.0"
- puppeteer-core "19.6.2"
+ puppeteer-core "19.6.3"
q@^1.1.2:
version "1.5.1"