For more tags, please go to [Search torrent](https://bangumi.moe/search/index)
diff --git a/lib/radar-rules.js b/lib/radar-rules.js
index befac161f..2399fe6b2 100644
--- a/lib/radar-rules.js
+++ b/lib/radar-rules.js
@@ -1672,65 +1672,6 @@ module.exports = {
},
],
},
- 'bgm.tv': {
- _name: 'Bangumi',
- '.': [
- {
- title: '小组话题',
- docs: 'https://docs.rsshub.app/anime.html#bangumi',
- source: '/group/:id',
- target: '/bangumi/group/:id',
- },
- {
- title: '小组话题的新回复',
- docs: 'https://docs.rsshub.app/anime.html#bangumi',
- source: '/group/topic/:id',
- target: '/bangumi/topic/:id',
- },
- {
- title: '现实人物的新作品',
- docs: 'https://docs.rsshub.app/anime.html#bangumi',
- source: '/person/:id',
- target: '/bangumi/person/:id',
- },
- {
- title: '用户日志',
- docs: 'https://docs.rsshub.app/anime.html#bangumi',
- source: '/user/:id',
- target: '/bangumi/user/blog/:id',
- },
- {
- title: '条目的讨论',
- docs: 'https://docs.rsshub.app/anime.html#bangumi',
- source: '/subject/:id',
- target: '/bangumi/subject/:id/topics',
- },
- {
- title: '条目的评论',
- docs: 'https://docs.rsshub.app/anime.html#bangumi',
- source: '/subject/:id',
- target: '/bangumi/subject/:id/blogs',
- },
- {
- title: '条目的章节',
- docs: 'https://docs.rsshub.app/anime.html#bangumi',
- source: '/subject/:id',
- target: '/bangumi/subject/:id',
- },
- {
- title: '条目的吐槽箱',
- docs: 'https://docs.rsshub.app/anime.html#bangumi',
- source: '/subject/:id',
- target: '/bangumi/subject/:id/comments',
- },
- {
- title: '放送列表',
- docs: 'https://docs.rsshub.app/anime.html#bangumi',
- source: '/calendar',
- target: '/bangumi/calendar/today',
- },
- ],
- },
'e-hentai.org/': {
_name: 'E-Hentai',
'.': [
diff --git a/lib/router.js b/lib/router.js
index f93cbbe19..0ea162223 100644
--- a/lib/router.js
+++ b/lib/router.js
@@ -34,13 +34,13 @@ router.get('/1draw', lazyloadRouteHandler('./routes/1draw/index'));
router.get('/benedictevans', lazyloadRouteHandler('./routes/benedictevans/recent.js'));
// bangumi
-router.get('/bangumi/calendar/today', lazyloadRouteHandler('./routes/bangumi/calendar/today'));
-router.get('/bangumi/subject/:id/:type', lazyloadRouteHandler('./routes/bangumi/subject'));
-router.get('/bangumi/person/:id', lazyloadRouteHandler('./routes/bangumi/person'));
-router.get('/bangumi/topic/:id', lazyloadRouteHandler('./routes/bangumi/group/reply'));
-router.get('/bangumi/group/:id', lazyloadRouteHandler('./routes/bangumi/group/topic'));
-router.get('/bangumi/subject/:id', lazyloadRouteHandler('./routes/bangumi/subject'));
-router.get('/bangumi/user/blog/:id', lazyloadRouteHandler('./routes/bangumi/user/blog'));
+// router.get('/bangumi/calendar/today', lazyloadRouteHandler('./routes/bangumi/calendar/today'));
+// router.get('/bangumi/subject/:id/:type', lazyloadRouteHandler('./routes/bangumi/subject'));
+// router.get('/bangumi/person/:id', lazyloadRouteHandler('./routes/bangumi/person'));
+// router.get('/bangumi/topic/:id', lazyloadRouteHandler('./routes/bangumi/group/reply'));
+// router.get('/bangumi/group/:id', lazyloadRouteHandler('./routes/bangumi/group/topic'));
+// router.get('/bangumi/subject/:id', lazyloadRouteHandler('./routes/bangumi/subject'));
+// router.get('/bangumi/user/blog/:id', lazyloadRouteHandler('./routes/bangumi/user/blog'));
// 報導者 migrated to v2
// router.get('/twreporter/newest', lazyloadRouteHandler('./routes/twreporter/newest'));
diff --git a/lib/routes/bangumi/calendar/_base.js b/lib/routes/bangumi/calendar/_base.js
deleted file mode 100644
index 8dcaf5054..000000000
--- a/lib/routes/bangumi/calendar/_base.js
+++ /dev/null
@@ -1,43 +0,0 @@
-const got = require('@/utils/got');
-
-module.exports = async (ctx) => {
- const bgmCalendarUrl = 'https://api.bgm.tv/calendar';
- const bgmDataUrl = 'https://cdn.jsdelivr.net/npm/bangumi-data/dist/data.json';
-
- const url = [bgmCalendarUrl, bgmDataUrl];
-
- const cache = await Promise.all(url.map(ctx.cache.get));
- const result = await Promise.all(
- cache.map(async (c, i) => {
- if (c) {
- return Promise.resolve(JSON.parse(c));
- } else {
- const response = await got({
- method: 'get',
- url: url[i],
- });
- const data = response.data;
-
- if (i === 1) {
- // 只保留有 bangumi id 的番剧
- const length = data.items.length;
- const items = [];
- for (let index = 0; index < length; index++) {
- const item = data.items[index];
- const bgm_site = item.sites.find((s) => s.site === 'bangumi');
- if (bgm_site) {
- item.bgm_id = bgm_site.id;
- items.push(item);
- }
- }
- data.items = items;
- }
-
- ctx.cache.set(url[i], JSON.stringify(data));
- return Promise.resolve(data);
- }
- })
- );
-
- return result;
-};
diff --git a/lib/routes/bangumi/group/topic.js b/lib/routes/bangumi/group/topic.js
deleted file mode 100644
index 502268801..000000000
--- a/lib/routes/bangumi/group/topic.js
+++ /dev/null
@@ -1,26 +0,0 @@
-const got = require('@/utils/got');
-const cheerio = require('cheerio');
-const resolve_url = require('url').resolve;
-
-const base_url = 'https://bgm.tv/';
-
-module.exports = async (ctx) => {
- const groupID = ctx.params.id;
- const link = 'https://bgm.tv/group/' + groupID + '/forum';
- const html = (await got.get(link)).data;
- const $ = cheerio.load(html);
- const title = 'Bangumi - ' + $('.SecondaryNavTitle').text();
-
- ctx.state.data = {
- title,
- link,
- item: $('.topic_list .topic')
- .map((_, elem) => ({
- link: resolve_url(base_url, $('.subject a', elem).attr('href')),
- title: $('.subject a', elem).attr('title'),
- pubDate: new Date($('.lastpost .time', elem).text()).toUTCString(),
- description: 'Author: ' + $('.author a', elem).text() + '
' + 'Reply: ' + $('.posts', elem).text(),
- }))
- .get(),
- };
-};
diff --git a/lib/routes/bangumi/subject/ep.js b/lib/routes/bangumi/subject/ep.js
deleted file mode 100644
index 41e814222..000000000
--- a/lib/routes/bangumi/subject/ep.js
+++ /dev/null
@@ -1,26 +0,0 @@
-const got = require('@/utils/got');
-
-module.exports = async (subjectID) => {
- const url = `https://api.bgm.tv/subject/${subjectID}?responseGroup=large`;
- const epsInfo = (await got.get(url)).data;
- const activeEps = [];
-
- epsInfo.eps.forEach((e) => {
- if (e.status === 'Air') {
- activeEps.push(e);
- }
- });
-
- return {
- title: epsInfo.name_cn,
- link: `https://bgm.tv/subject/${subjectID}`,
- description: epsInfo.summary,
- item: activeEps.reverse().map((e) => ({
- title: `ep.${e.sort} ${e.name_cn}`,
- description: `
${e.desc.replace(/\n+/g, '
')}
`,
- pubDate: new Date(e.airdate).toUTCString(),
- guid: e.id,
- link: e.url,
- })),
- };
-};
diff --git a/lib/v2/bangumi/maintainer.js b/lib/v2/bangumi/maintainer.js
index 52659f4b7..3c73156f9 100644
--- a/lib/v2/bangumi/maintainer.js
+++ b/lib/v2/bangumi/maintainer.js
@@ -1,5 +1,17 @@
module.exports = {
+ // bangumi.moe
+ '/moe': ['nczitzk'],
+ '/moe/:tags?': ['nczitzk'],
+ // bangumi.online
'/online': ['devinmugen'],
- '/': ['nczitzk'],
- '/:tags?': ['nczitzk'],
+ // bangumi.tv
+ '/tv/calendar/today': ['magic-akari'],
+ '/tv/group/:id': ['SettingDust'],
+ '/tv/person/:id': ['ylc395'],
+ '/tv/subject/:id': ['SettingDust'],
+ '/tv/subject/:id/blogs': ['ylc395'],
+ '/tv/subject/:id/comments': ['ylc395'],
+ '/tv/subject/:id/topics': ['ylc395'],
+ '/tv/topic/:id': ['ylc395'],
+ '/tv/user/blog/:id': ['nczitzk'],
};
diff --git a/lib/v2/bangumi/index.js b/lib/v2/bangumi/moe/index.js
similarity index 96%
rename from lib/v2/bangumi/index.js
rename to lib/v2/bangumi/moe/index.js
index 4e5bb27be..8bab84d8d 100644
--- a/lib/v2/bangumi/index.js
+++ b/lib/v2/bangumi/moe/index.js
@@ -2,7 +2,7 @@ const got = require('@/utils/got');
const { parseDate } = require('@/utils/parse-date');
module.exports = async (ctx) => {
- const isLatest = ctx.path === '/';
+ const isLatest = ctx.path === '/moe';
const rootUrl = 'https://bangumi.moe';
let response;
@@ -19,7 +19,7 @@ module.exports = async (ctx) => {
const tagUrl = `${rootUrl}/api/tag/search`;
const torrentUrl = `${rootUrl}/api/torrent/search`;
- const params = ctx.path.split('/').slice(1);
+ const params = ctx.path.split('/').slice(2);
tag_id = await Promise.all(
params.map((param) =>
diff --git a/lib/v2/bangumi/online.js b/lib/v2/bangumi/online/online.js
similarity index 89%
rename from lib/v2/bangumi/online.js
rename to lib/v2/bangumi/online/online.js
index a07e4e738..d9cd89bc4 100644
--- a/lib/v2/bangumi/online.js
+++ b/lib/v2/bangumi/online/online.js
@@ -11,7 +11,7 @@ module.exports = async (ctx) => {
const items = list.map((item) => ({
title: `${item.title_zh} - 第 ${item.volume} 集`,
- description: art(path.join(__dirname, 'templates/image.art'), {
+ description: art(path.join(__dirname, '../templates/online/image.art'), {
src: `https:${item.cover}`,
alt: `${item.title_zh} - 第 ${item.volume} 集`,
}),
diff --git a/lib/v2/bangumi/radar.js b/lib/v2/bangumi/radar.js
index eea70864b..5abd7ba88 100644
--- a/lib/v2/bangumi/radar.js
+++ b/lib/v2/bangumi/radar.js
@@ -1,3 +1,63 @@
+const bangumiTV = {
+ _name: 'Bangumi 番组计划',
+ '.': [
+ {
+ title: '小组话题',
+ docs: 'https://docs.rsshub.app/anime.html#bangumi',
+ source: '/group/:id',
+ target: '/bangumi/tv/group/:id',
+ },
+ {
+ title: '小组话题的新回复',
+ docs: 'https://docs.rsshub.app/anime.html#bangumi',
+ source: '/group/topic/:id',
+ target: '/bangumi/tv/topic/:id',
+ },
+ {
+ title: '现实人物的新作品',
+ docs: 'https://docs.rsshub.app/anime.html#bangumi',
+ source: '/person/:id',
+ target: '/bangumi/tv/person/:id',
+ },
+ {
+ title: '用户日志',
+ docs: 'https://docs.rsshub.app/anime.html#bangumi',
+ source: '/user/:id',
+ target: '/bangumi/tv/user/blog/:id',
+ },
+ {
+ title: '条目的讨论',
+ docs: 'https://docs.rsshub.app/anime.html#bangumi',
+ source: '/subject/:id',
+ target: '/bangumi/tv/subject/:id/topics',
+ },
+ {
+ title: '条目的评论',
+ docs: 'https://docs.rsshub.app/anime.html#bangumi',
+ source: '/subject/:id',
+ target: '/bangumi/tv/subject/:id/blogs',
+ },
+ {
+ title: '条目的章节',
+ docs: 'https://docs.rsshub.app/anime.html#bangumi',
+ source: '/subject/:id',
+ target: '/bangumi/tv/subject/:id',
+ },
+ {
+ title: '条目的吐槽箱',
+ docs: 'https://docs.rsshub.app/anime.html#bangumi',
+ source: '/subject/:id',
+ target: '/bangumi/tv/subject/:id/comments',
+ },
+ {
+ title: '放送列表',
+ docs: 'https://docs.rsshub.app/anime.html#bangumi',
+ source: '/calendar',
+ target: '/bangumi/tv/calendar/today',
+ },
+ ],
+};
+
module.exports = {
'bangumi.moe': {
_name: '萌番組',
@@ -6,13 +66,13 @@ module.exports = {
title: '最新',
docs: 'https://docs.rsshub.app/anime.html#meng-fan-zu-zui-xin',
source: ['/'],
- target: '/bangumi',
+ target: '/bangumi/moe',
},
{
title: '标签',
docs: 'https://docs.rsshub.app/anime.html#meng-fan-zu-biao-qian',
source: ['/search/index'],
- target: '/bangumi/:tags?',
+ target: '/bangumi/moe/:tags?',
},
],
},
@@ -27,4 +87,6 @@ module.exports = {
},
],
},
+ 'bangumi.tv': bangumiTV,
+ 'bgm.tv': bangumiTV,
};
diff --git a/lib/v2/bangumi/router.js b/lib/v2/bangumi/router.js
index 5c90781a2..7707b9c10 100644
--- a/lib/v2/bangumi/router.js
+++ b/lib/v2/bangumi/router.js
@@ -1,4 +1,14 @@
module.exports = function (router) {
- router.get('/online', require('./online'));
- router.get(/([\w-/]+)?/, require('./index'));
+ // bangumi.moe
+ router.get(/moe([\w-/]+)?/, require('./moe/index'));
+ // bangumi.online
+ router.get('/online', require('./online/online'));
+ // bangumi.tv
+ router.get('/tv/calendar/today', require('./tv/calendar/today'));
+ router.get('/tv/group/:id', require('./tv/group/topic'));
+ router.get('/tv/person/:id', require('./tv/person'));
+ router.get('/tv/subject/:id', require('./tv/subject'));
+ router.get('/tv/subject/:id/:type', require('./tv/subject'));
+ router.get('/tv/topic/:id', require('./tv/group/reply'));
+ router.get('/tv/user/blog/:id', require('./tv/user/blog'));
};
diff --git a/lib/v2/bangumi/templates/image.art b/lib/v2/bangumi/templates/online/image.art
similarity index 100%
rename from lib/v2/bangumi/templates/image.art
rename to lib/v2/bangumi/templates/online/image.art
diff --git a/lib/v2/bangumi/templates/tv/ep.art b/lib/v2/bangumi/templates/tv/ep.art
new file mode 100644
index 000000000..dd383d563
--- /dev/null
+++ b/lib/v2/bangumi/templates/tv/ep.art
@@ -0,0 +1,2 @@
+
+{{@ e.desc.replace(/\r\n/g, '
') }}
diff --git a/lib/v2/bangumi/templates/tv/today.art b/lib/v2/bangumi/templates/tv/today.art
new file mode 100644
index 000000000..a0c4e0258
--- /dev/null
+++ b/lib/v2/bangumi/templates/tv/today.art
@@ -0,0 +1,12 @@
+
+
+{{ each bgm.sites site }}
+{{ set url }}
+{{ if site.url }}
+ {{ url = site.url }}
+{{ else }}
+ <% url = siteMeta[site.site].urlTemplate.replace('{{id}}', site.id) %>
+{{ /if }}
+- {{ siteMeta[site.site].title }}
+{{ /each }}
+
diff --git a/lib/v2/bangumi/tv/calendar/_base.js b/lib/v2/bangumi/tv/calendar/_base.js
new file mode 100644
index 000000000..1e99cf616
--- /dev/null
+++ b/lib/v2/bangumi/tv/calendar/_base.js
@@ -0,0 +1,37 @@
+const got = require('@/utils/got');
+const config = require('@/config').value;
+
+module.exports = (tryGet) => {
+ const bgmCalendarUrl = 'https://api.bgm.tv/calendar';
+ const bgmDataUrl = 'https://cdn.jsdelivr.net/npm/bangumi-data/dist/data.json';
+
+ const urls = [bgmCalendarUrl, bgmDataUrl];
+
+ return Promise.all(
+ urls.map((item, i) =>
+ tryGet(
+ item,
+ async () => {
+ const { data } = await got(item);
+
+ if (i === 1) {
+ // 只保留有 bangumi id 的番剧
+ const items = [];
+ for (const item of data.items) {
+ const bgmSite = item.sites.find((s) => s.site === 'bangumi');
+ if (bgmSite) {
+ item.bgmId = bgmSite.id;
+ items.push(item);
+ }
+ }
+ data.items = items;
+ }
+
+ return data;
+ },
+ config.cache.contentExpire,
+ false
+ )
+ )
+ );
+};
diff --git a/lib/routes/bangumi/calendar/today.js b/lib/v2/bangumi/tv/calendar/today.js
similarity index 62%
rename from lib/routes/bangumi/calendar/today.js
rename to lib/v2/bangumi/tv/calendar/today.js
index 5234a19e0..d157069f4 100644
--- a/lib/routes/bangumi/calendar/today.js
+++ b/lib/v2/bangumi/tv/calendar/today.js
@@ -1,27 +1,25 @@
const getData = require('./_base');
+const { art } = require('@/utils/render');
+const path = require('path');
module.exports = async (ctx) => {
- const [list, data] = await getData(ctx);
+ const [list, data] = await getData(ctx.cache.tryGet);
const siteMeta = data.siteMeta;
const today = new Date(Date.now());
-
// 将 UTC 时间向前移动9小时,即可在数值上表示东京时间
today.setUTCHours(today.getUTCHours() + 9);
-
const day = today.getUTCDay();
- const todayList = list.filter((l) => l.weekday.id % 7 === day)[0];
-
- const todayBgmId = todayList.items.map((t) => t.id);
+ const todayList = list.find((l) => l.weekday.id % 7 === day);
+ const todayBgmId = todayList.items.map((t) => t.id.toString());
const images = todayList.items.reduce((p, c) => {
p[c.id] = (c.images || {}).large;
return p;
}, {});
-
- const todayBgm = data.items.filter((d) => todayBgmId.includes(d.bgm_id));
+ const todayBgm = data.items.filter((d) => todayBgmId.includes(d.bgmId));
todayBgm.forEach((bgm) => {
- bgm.image = images[bgm.bgm_id];
+ bgm.image = images[bgm.bgmId];
});
ctx.state.data = {
@@ -35,25 +33,13 @@ module.exports = async (ctx) => {
updated.setMinutes(begin.getMinutes());
updated.setSeconds(begin.getSeconds());
- const link = `http://bangumi.tv/subject/${bgm.bgm_id}`;
+ const link = `https://bangumi.tv/subject/${bgm.bgmId}`;
const id = `${link}#${new Intl.DateTimeFormat('zh-CN').format(updated)}`;
- const image = `
`;
- const html =
- image +
- '' +
- bgm.sites
- .map((s) => {
- let url;
- if (s.url) {
- url = s.url;
- } else {
- url = siteMeta[s.site].urlTemplate.replace('{{id}}', s.id);
- }
- return `- ${siteMeta[s.site].title}
`;
- })
- .join('') +
- '
';
+ const html = art(path.resolve(__dirname, '../../templates/tv/today.art'), {
+ bgm,
+ siteMeta,
+ });
return {
id,
@@ -63,7 +49,9 @@ module.exports = async (ctx) => {
Object.values(bgm.titleTranslate)
.map((t) => t.join('|'))
.join('|'),
- ].join('|'),
+ ]
+ .filter((t) => t) // don't join if empty
+ .join('|'),
updated: updated.toISOString(),
pubDate: updated.toUTCString(),
link,
diff --git a/lib/routes/bangumi/group/reply.js b/lib/v2/bangumi/tv/group/reply.js
similarity index 50%
rename from lib/routes/bangumi/group/reply.js
rename to lib/v2/bangumi/tv/group/reply.js
index 25d3f630f..d498fe90e 100644
--- a/lib/routes/bangumi/group/reply.js
+++ b/lib/v2/bangumi/tv/group/reply.js
@@ -1,16 +1,18 @@
const got = require('@/utils/got');
const cheerio = require('cheerio');
+const { parseDate } = require('@/utils/parse-date');
+const timezone = require('@/utils/timezone');
module.exports = async (ctx) => {
// bangumi.tv未提供获取小组话题的API,因此仍需要通过抓取网页来获取
const topicID = ctx.params.id;
const link = `https://bgm.tv/group/topic/${topicID}`;
- const html = (await got.get(link)).data;
+ const { data: html } = await got(link);
const $ = cheerio.load(html);
const title = $('#pageHeader h1').text();
const latestReplies = $('.row_reply')
- .slice(-10)
- .map((i, el) => {
+ .toArray()
+ .map((el) => {
const $el = $(el);
return {
id: $el.attr('id'),
@@ -18,19 +20,28 @@ module.exports = async (ctx) => {
content: $el.find('.reply_content .message').html(),
date: $el.children().first().find('small').children().remove().end().text().slice(3),
};
- })
- .get()
- .reverse();
+ });
+
+ const postTopic = {
+ title,
+ description: $('.postTopic .topic_content').html(),
+ author: $('.postTopic .inner strong a').first().text(),
+ pubDate: timezone(parseDate($('.postTopic .re_info small').text().trim().slice(5)), +8),
+ link,
+ };
ctx.state.data = {
title: `${title}的最新回复`,
link,
- item: latestReplies.map((c) => ({
- title: `${c.author}回复了小组话题《${title}》`,
- description: c.content,
- guid: c.id,
- pubDate: new Date(c.date).toUTCString(),
- link,
- })),
+ item: [
+ ...latestReplies.map((c) => ({
+ title: `${c.author} 回复了小组话题《${title}》`,
+ description: c.content,
+ pubDate: timezone(parseDate(c.date), +8),
+ author: c.author,
+ link: `${link}#${c.id}`,
+ })),
+ postTopic,
+ ],
};
};
diff --git a/lib/v2/bangumi/tv/group/topic.js b/lib/v2/bangumi/tv/group/topic.js
new file mode 100644
index 000000000..9142d967e
--- /dev/null
+++ b/lib/v2/bangumi/tv/group/topic.js
@@ -0,0 +1,26 @@
+const got = require('@/utils/got');
+const cheerio = require('cheerio');
+const { parseDate } = require('@/utils/parse-date');
+const base_url = 'https://bgm.tv';
+
+module.exports = async (ctx) => {
+ const groupID = ctx.params.id;
+ const link = `${base_url}/group/${groupID}/forum`;
+ const { data: html } = await got(link);
+ const $ = cheerio.load(html);
+ const title = 'Bangumi - ' + $('.SecondaryNavTitle').text();
+
+ ctx.state.data = {
+ title,
+ link,
+ item: $('.topic_list .topic')
+ .toArray()
+ .map((elem) => ({
+ link: new URL($('.subject a', elem).attr('href'), base_url).href,
+ title: $('.subject a', elem).attr('title'),
+ pubDate: parseDate($('.lastpost .time', elem).text()),
+ description: 'Reply: ' + $('.posts', elem).text(),
+ author: $('.author a', elem).text(),
+ })),
+ };
+};
diff --git a/lib/routes/bangumi/person/index.js b/lib/v2/bangumi/tv/person/index.js
similarity index 59%
rename from lib/routes/bangumi/person/index.js
rename to lib/v2/bangumi/tv/person/index.js
index 3ddeb0645..35ab6ace1 100644
--- a/lib/routes/bangumi/person/index.js
+++ b/lib/v2/bangumi/tv/person/index.js
@@ -1,15 +1,17 @@
const got = require('@/utils/got');
const cheerio = require('cheerio');
+const { parseDate } = require('@/utils/parse-date');
module.exports = async (ctx) => {
// bangumi.tv未提供获取“人物信息”的API,因此仍需要通过抓取网页来获取
const personID = ctx.params.id;
const link = `https://bgm.tv/person/${personID}/works?sort=date`;
- const html = (await got.get(link)).data;
+ const { data: html } = await got(link);
const $ = cheerio.load(html);
const personName = $('.nameSingle a').text();
const works = $('.item')
- .map((i, el) => {
+ .toArray()
+ .map((el) => {
const $el = $(el);
const $workEl = $el.find('.l');
return {
@@ -18,17 +20,19 @@ module.exports = async (ctx) => {
workInfo: $el.find('p.info').text(),
job: $el.find('.badge_job').text(),
};
- })
- .get();
+ });
ctx.state.data = {
title: `${personName}参与的作品`,
link,
- item: works.map((c) => ({
- title: `${personName}以${c.job}的身份参与了作品《${c.work}》`,
- description: c.workInfo,
- link: c.workURL,
- pubDate: c.workInfo.substring(0, c.workInfo.indexOf(' /')) === '' ? new Date(0).toUTCString() : new Date(c.workInfo.substring(0, c.workInfo.indexOf(' /'))).toUTCString(),
- })),
+ item: works.map((c) => {
+ const match = c.workInfo.match(/(\d{4}(?:-|年)\d{1,2}(?:-|月)\d{1,2})/);
+ return {
+ title: `${personName}以${c.job}的身份参与了作品《${c.work}》`,
+ description: c.workInfo,
+ link: c.workURL,
+ pubDate: match ? parseDate(match[1], ['YYYY-MM-DD', 'YYYY-M-D']) : null,
+ };
+ }),
};
};
diff --git a/lib/routes/bangumi/subject/comments.js b/lib/v2/bangumi/tv/subject/comments.js
similarity index 65%
rename from lib/routes/bangumi/subject/comments.js
rename to lib/v2/bangumi/tv/subject/comments.js
index b150fd1f0..7c0ca8d56 100644
--- a/lib/routes/bangumi/subject/comments.js
+++ b/lib/v2/bangumi/tv/subject/comments.js
@@ -1,34 +1,32 @@
const got = require('@/utils/got');
const cheerio = require('cheerio');
+const { parseDate, parseRelativeDate } = require('@/utils/parse-date');
module.exports = async (subjectID, minLength) => {
// bangumi.tv未提供获取“吐槽(comments)”的API,因此仍需要通过抓取网页来获取
const link = `https://bgm.tv/subject/${subjectID}/comments`;
- const html = (await got.get(link)).data;
+ const { data: html } = await got(link);
const $ = cheerio.load(html);
const title = $('.nameSingle').find('a').text();
const comments = $('.item')
- .map((i, el) => {
+ .toArray()
+ .map((el) => {
const $el = $(el);
- const $rateEl = $el.find('.starsinfo');
+ const $rateEl = $el.find('.starlight');
let rate = null;
if ($rateEl.length > 0) {
- rate = $rateEl.attr('class').match(/sstars(\d)/)[1];
+ rate = $rateEl.attr('class').match(/stars(\d)/)[1];
}
const dateString = $el.find('small.grey').text().slice(2);
+
let date;
if (dateString.includes('ago')) {
// 处理表示相对日期的字符串
- const list = dateString
- .match(/(\dd )?(\d{1,2}h )?(\d{1,2}m )?ago/)
- .slice(1)
- .map((s) => (s ? Number(s.slice(0, -2)) : 0));
-
- date = new Date(new Date().getTime() - 1000 * 60 * 60 * 24 * list[0] - 1000 * 60 * 60 * list[1] - 1000 * 60 * list[2]).toUTCString();
+ date = parseRelativeDate(dateString);
} else {
// 表示绝对日期的字符串
- date = new Date(dateString).toUTCString();
+ date = parseDate(dateString);
}
return {
@@ -38,15 +36,15 @@ module.exports = async (subjectID, minLength) => {
date,
};
})
- .get()
.filter((obj) => obj.content.length >= minLength);
+
return {
- title: `${title}的Bangumi吐槽箱`,
+ title: `${title}的 Bangumi 吐槽箱`,
link,
item: comments.map((c) => ({
title: `${c.user}的吐槽`,
description: `【评分:${c.rate}】 ${c.content}`,
- guid: c.user,
+ guid: `${link}#${c.user}`,
pubDate: c.date,
link,
})),
diff --git a/lib/v2/bangumi/tv/subject/ep.js b/lib/v2/bangumi/tv/subject/ep.js
new file mode 100644
index 000000000..b0e02b8b3
--- /dev/null
+++ b/lib/v2/bangumi/tv/subject/ep.js
@@ -0,0 +1,31 @@
+const got = require('@/utils/got');
+const { parseDate } = require('@/utils/parse-date');
+const { art } = require('@/utils/render');
+const path = require('path');
+
+module.exports = async (subjectID) => {
+ const url = `https://api.bgm.tv/subject/${subjectID}?responseGroup=large`;
+ const { data: epsInfo } = await got(url);
+ const activeEps = [];
+
+ epsInfo.eps.forEach((e) => {
+ if (e.status === 'Air') {
+ activeEps.push(e);
+ }
+ });
+
+ return {
+ title: epsInfo.name_cn || epsInfo.name,
+ link: `https://bgm.tv/subject/${subjectID}`,
+ description: epsInfo.summary,
+ item: activeEps.map((e) => ({
+ title: `ep.${e.sort} ${e.name_cn || e.name}`,
+ description: art(path.resolve(__dirname, '../../templates/tv/ep.art'), {
+ e,
+ epsInfo,
+ }),
+ pubDate: parseDate(e.airdate),
+ link: e.url.replace('http:', 'https:'),
+ })),
+ };
+};
diff --git a/lib/routes/bangumi/subject/index.js b/lib/v2/bangumi/tv/subject/index.js
similarity index 88%
rename from lib/routes/bangumi/subject/index.js
rename to lib/v2/bangumi/tv/subject/index.js
index 8eb61a088..0929aa32d 100644
--- a/lib/routes/bangumi/subject/index.js
+++ b/lib/v2/bangumi/tv/subject/index.js
@@ -1,6 +1,5 @@
const getComments = require('./comments.js');
const getFromAPI = require('./offcial-subject-api.js');
-
const getEps = require('./ep.js');
module.exports = async (ctx) => {
@@ -9,7 +8,7 @@ module.exports = async (ctx) => {
if (ctx.params.type) {
switch (ctx.params.type) {
case 'comments':
- response = await getComments(id, Number(ctx.request.query.minLength) || 0);
+ response = await getComments(id, Number(ctx.query.minLength) || 0);
break;
case 'blogs':
response = await getFromAPI('blog')(id);
diff --git a/lib/routes/bangumi/subject/offcial-subject-api.js b/lib/v2/bangumi/tv/subject/offcial-subject-api.js
similarity index 62%
rename from lib/routes/bangumi/subject/offcial-subject-api.js
rename to lib/v2/bangumi/tv/subject/offcial-subject-api.js
index ac4792b00..98e6b1f6a 100644
--- a/lib/routes/bangumi/subject/offcial-subject-api.js
+++ b/lib/v2/bangumi/tv/subject/offcial-subject-api.js
@@ -1,4 +1,5 @@
const got = require('@/utils/got');
+const { parseDate } = require('@/utils/parse-date');
module.exports = (type) => {
const mapping = {
@@ -13,17 +14,18 @@ module.exports = (type) => {
};
return async (subjectID) => {
- // 官方提供的条目API文档见https://github.com/bangumi/api/blob/master/docs-raw/Subject-API.md
+ // 官方提供的条目API文档见 https://github.com/bangumi/api/blob/3f3fa6390c468816f9883d24be488e41f8946159/docs-raw/Subject-API.md
const url = `https://api.bgm.tv/subject/${subjectID}?responseGroup=large`;
- const subjectInfo = (await got.get(url)).data;
+ const { data: subjectInfo } = await got(url);
return {
- title: `${subjectInfo.name_cn || subjectInfo.name}的Bangumi${mapping[type].cn}`,
+ title: `${subjectInfo.name_cn || subjectInfo.name}的 Bangumi ${mapping[type].cn}`,
link: `https://bgm.tv/subject/${subjectInfo.id}/${mapping[type].en}`,
item: subjectInfo[type].map((article) => ({
title: `${article.user.nickname}:${article.title}`,
description: article.summary || '',
- link: article.url,
- pubDate: new Date(article.timestamp * 1000).toUTCString(),
+ link: article.url.replace('http:', 'https:'),
+ pubDate: parseDate(article.timestamp, 'X'),
+ author: article.user.nickname,
})),
};
};
diff --git a/lib/routes/bangumi/user/blog.js b/lib/v2/bangumi/tv/user/blog.js
similarity index 76%
rename from lib/routes/bangumi/user/blog.js
rename to lib/v2/bangumi/tv/user/blog.js
index f4307cd01..466eec5ce 100644
--- a/lib/routes/bangumi/user/blog.js
+++ b/lib/v2/bangumi/tv/user/blog.js
@@ -1,6 +1,7 @@
-const url = require('url');
const got = require('@/utils/got');
const cheerio = require('cheerio');
+const { parseDate } = require('@/utils/parse-date');
+const timezone = require('@/utils/timezone');
module.exports = async (ctx) => {
const currentUrl = `https://bgm.tv/user/${ctx.params.id}/blog`;
@@ -11,16 +12,16 @@ module.exports = async (ctx) => {
const $ = cheerio.load(response.data);
const list = $('#entry_list div.item')
.find('h2.title')
- .map((_, item) => {
+ .toArray()
+ .map((item) => {
item = $(item);
const a = item.find('a');
return {
title: a.text(),
- link: url.resolve(`https://bgm.tv/`, a.attr('href')),
- pubDate: new Date(item.parent().find('small.time').text() + ' GMT+8').toUTCString(),
+ link: new URL(a.attr('href'), 'https://bgm.tv').href,
+ pubDate: timezone(parseDate(item.parent().find('small.time').text()), 0),
};
- })
- .get();
+ });
const items = await Promise.all(
list.map((item) =>