fix(route): 修复bangumi吐槽箱无法获取评分的问题 (#10780)
* 修复bangumi吐槽箱无法获取评分的问题 * refactor: migrate to v2 * fix: subject date parsing * fix: old routes * fix: sort maintainer
This commit is contained in:
parent
6251a2dc02
commit
2600c1ab16
|
|
@ -827,20 +827,6 @@
|
|||
{ title: '日记评论区', docs: 'https://docs.rsshub.app/social-media.html#fur-affinity', source: '/journal/:id/', target: '/furaffinity/journal_comments/:id' },
|
||||
],
|
||||
},
|
||||
'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',
|
||||
'.': [
|
||||
|
|
|
|||
|
|
@ -204,43 +204,43 @@ pageClass: routes
|
|||
|
||||
<Route author="ranpox" path="/anitama/:channel?" example="/anitama" :paramsDesc="['频道id,从频道的地址栏中查看']"/>
|
||||
|
||||
## Bangumi
|
||||
## Bangumi 番组计划
|
||||
|
||||
### 放送列表
|
||||
|
||||
<Route author="magic-akari" example="/bangumi/calendar/today" path="/bangumi/calendar/today" radar="1"/>
|
||||
<Route author="magic-akari" example="/bangumi/tv/calendar/today" path="/bangumi/tv/calendar/today" radar="1"/>
|
||||
|
||||
### 条目的章节
|
||||
|
||||
<Route author="SettingDust" example="/bangumi/subject/240038" path="/bangumi/subject/:id" :paramsDesc="['条目 id, 在条目页面的地址栏查看']" radar="1"/>
|
||||
<Route author="SettingDust" example="/bangumi/tv/subject/240038" path="/bangumi/tv/subject/:id" :paramsDesc="['条目 id, 在条目页面的地址栏查看']" radar="1"/>
|
||||
|
||||
### 条目的吐槽箱
|
||||
|
||||
<Route author="ylc395" example="/bangumi/subject/214265/comments?minLength=100" path="/bangumi/subject/:id/comments" :paramsDesc="['条目 id, 在条目页面的地址栏查看. minLength: 以查询字符串(query string)的形式指定. 用于过滤掉内容长度小于指定值的吐槽']" radar="1"/>
|
||||
<Route author="ylc395" example="/bangumi/tv/subject/214265/comments?minLength=100" path="/bangumi/tv/subject/:id/comments" :paramsDesc="['条目 id, 在条目页面的地址栏查看. minLength: 以查询字符串(query string)的形式指定. 用于过滤掉内容长度小于指定值的吐槽']" radar="1"/>
|
||||
|
||||
### 条目的评论
|
||||
|
||||
<Route author="ylc395" example="/bangumi/subject/214265/blogs" path="/bangumi/subject/:id/blogs" :paramsDesc="['条目 id, 在条目页面的地址栏查看']" radar="1"/>
|
||||
<Route author="ylc395" example="/bangumi/tv/subject/214265/blogs" path="/bangumi/tv/subject/:id/blogs" :paramsDesc="['条目 id, 在条目页面的地址栏查看']" radar="1"/>
|
||||
|
||||
### 条目的讨论
|
||||
|
||||
<Route author="ylc395" example="/bangumi/subject/214265/topics" path="/bangumi/subject/:id/topics" :paramsDesc="['条目 id, 在条目页面的地址栏查看']" radar="1"/>
|
||||
<Route author="ylc395" example="/bangumi/tv/subject/214265/topics" path="/bangumi/tv/subject/:id/topics" :paramsDesc="['条目 id, 在条目页面的地址栏查看']" radar="1"/>
|
||||
|
||||
### 现实人物的新作品
|
||||
|
||||
<Route author="ylc395" example="/bangumi/person/32943" path="/bangumi/person/:id" :paramsDesc="['人物 id, 在人物页面的地址栏查看']" radar="1"/>
|
||||
<Route author="ylc395" example="/bangumi/tv/person/32943" path="/bangumi/tv/person/:id" :paramsDesc="['人物 id, 在人物页面的地址栏查看']" radar="1"/>
|
||||
|
||||
### 小组话题的新回复
|
||||
|
||||
<Route author="ylc395" example="/bangumi/topic/24657" path="/bangumi/topic/:id" :paramsDesc="['话题 id, 在话题页面地址栏查看']" radar="1"/>
|
||||
<Route author="ylc395" example="/bangumi/tv/topic/367032" path="/bangumi/tv/topic/:id" :paramsDesc="['话题 id, 在话题页面地址栏查看']" radar="1"/>
|
||||
|
||||
### 小组话题
|
||||
|
||||
<Route author="SettingDust" example="/bangumi/group/boring" path="/bangumi/group/:id" :paramsDesc="['小组 id, 在小组页面地址栏查看']" radar="1"/>
|
||||
<Route author="SettingDust" example="/bangumi/tv/group/boring" path="/bangumi/tv/group/:id" :paramsDesc="['小组 id, 在小组页面地址栏查看']" radar="1"/>
|
||||
|
||||
### 用户日志
|
||||
|
||||
<Route author="nczitzk" example="/bangumi/user/blog/sai" path="/bangumi/user/blog/:id" :paramsDesc="['用户 id, 在用户页面地址栏查看']" radar="1"/>
|
||||
<Route author="nczitzk" example="/bangumi/tv/user/blog/sai" path="/bangumi/tv/user/blog/:id" :paramsDesc="['用户 id, 在用户页面地址栏查看']" radar="1"/>
|
||||
|
||||
## bilibili
|
||||
|
||||
|
|
@ -616,11 +616,11 @@ Sources
|
|||
|
||||
### 最新
|
||||
|
||||
<Route author="nczitzk" example="/bangumi" path="/bangumi"/>
|
||||
<Route author="nczitzk" example="/bangumi/moe" path="/bangumi/moe"/>
|
||||
|
||||
### 标签
|
||||
|
||||
<Route author="nczitzk" example="/bangumi/简体中文/1080p" path="/bangumi/:tags?" :paramsDesc="['标签,默认为空,多个标签用 `/` 分隔']">
|
||||
<Route author="nczitzk" example="/bangumi/moe/简体中文/1080p" path="/bangumi/moe/:tags?" :paramsDesc="['标签,默认为空,多个标签用 `/` 分隔']">
|
||||
|
||||
更多标签请前往 [搜索种子](https://bangumi.moe/search/index)
|
||||
|
||||
|
|
|
|||
|
|
@ -8,11 +8,11 @@ pageClass: routes
|
|||
|
||||
### Latest
|
||||
|
||||
<RouteEn author="nczitzk" example="/bangumi" path="/bangumi"/>
|
||||
<RouteEn author="nczitzk" example="/bangumi/moe" path="/bangumi/moe"/>
|
||||
|
||||
### Tags
|
||||
|
||||
<RouteEn author="nczitzk" example="/bangumi/chs/1080p" path="/bangumi/:tags?" :paramsDesc="['Tags, empty by default, multiple tags separated by `/`']">
|
||||
<RouteEn author="nczitzk" example="/bangumi/moe/chs/1080p" path="/bangumi/moe/:tags?" :paramsDesc="['Tags, empty by default, multiple tags separated by `/`']">
|
||||
|
||||
For more tags, please go to [Search torrent](https://bangumi.moe/search/index)
|
||||
|
||||
|
|
|
|||
|
|
@ -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',
|
||||
'.': [
|
||||
|
|
|
|||
|
|
@ -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'));
|
||||
|
|
|
|||
|
|
@ -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;
|
||||
};
|
||||
|
|
@ -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() + '<br>' + 'Reply: ' + $('.posts', elem).text(),
|
||||
}))
|
||||
.get(),
|
||||
};
|
||||
};
|
||||
|
|
@ -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: `<img src="${epsInfo.images.common}" alt="ep.${e.sort} ${e.name_cn}"><p>${e.desc.replace(/\n+/g, '<br>')}</p>`,
|
||||
pubDate: new Date(e.airdate).toUTCString(),
|
||||
guid: e.id,
|
||||
link: e.url,
|
||||
})),
|
||||
};
|
||||
};
|
||||
|
|
@ -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'],
|
||||
};
|
||||
|
|
|
|||
|
|
@ -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) =>
|
||||
|
|
@ -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} 集`,
|
||||
}),
|
||||
|
|
@ -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,
|
||||
};
|
||||
|
|
|
|||
|
|
@ -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'));
|
||||
};
|
||||
|
|
|
|||
|
|
@ -0,0 +1,2 @@
|
|||
<img src="{{ epsInfo.images.large || epsInfo.images.common }}" alt="ep.{{ e.sort }} {{ e.name_cn || e.name }}">
|
||||
<p>{{@ e.desc.replace(/\r\n/g, '<br>') }}</p>
|
||||
|
|
@ -0,0 +1,12 @@
|
|||
<img src={{ bgm.image }}>
|
||||
<ul>
|
||||
{{ each bgm.sites site }}
|
||||
{{ set url }}
|
||||
{{ if site.url }}
|
||||
{{ url = site.url }}
|
||||
{{ else }}
|
||||
<% url = siteMeta[site.site].urlTemplate.replace('{{id}}', site.id) %>
|
||||
{{ /if }}
|
||||
<li><a href="{{ url }}">{{ siteMeta[site.site].title }}</a></li>
|
||||
{{ /each }}
|
||||
</ul>
|
||||
|
|
@ -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
|
||||
)
|
||||
)
|
||||
);
|
||||
};
|
||||
|
|
@ -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 = `<img src=${bgm.image} />`;
|
||||
const html =
|
||||
image +
|
||||
'<ul>' +
|
||||
bgm.sites
|
||||
.map((s) => {
|
||||
let url;
|
||||
if (s.url) {
|
||||
url = s.url;
|
||||
} else {
|
||||
url = siteMeta[s.site].urlTemplate.replace('{{id}}', s.id);
|
||||
}
|
||||
return `<li><a href="${url}">${siteMeta[s.site].title}</a></li>`;
|
||||
})
|
||||
.join('') +
|
||||
'</ul>';
|
||||
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,
|
||||
|
|
@ -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,
|
||||
],
|
||||
};
|
||||
};
|
||||
|
|
@ -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(),
|
||||
})),
|
||||
};
|
||||
};
|
||||
|
|
@ -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,
|
||||
};
|
||||
}),
|
||||
};
|
||||
};
|
||||
|
|
@ -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,
|
||||
})),
|
||||
|
|
@ -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:'),
|
||||
})),
|
||||
};
|
||||
};
|
||||
|
|
@ -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);
|
||||
|
|
@ -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,
|
||||
})),
|
||||
};
|
||||
};
|
||||
|
|
@ -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) =>
|
||||
Loading…
Reference in New Issue