feat(route): add OTOBANANA (#14160)
* feat(route): add OTOBANANA * fix: live guid
This commit is contained in:
parent
8998f70f8a
commit
c058d6a00c
|
|
@ -0,0 +1,29 @@
|
|||
const got = require('@/utils/got');
|
||||
const { apiBase, baseUrl, getUserInfo, renderCast } = require('./utils');
|
||||
|
||||
module.exports = async (ctx) => {
|
||||
const { id } = ctx.params;
|
||||
|
||||
const userInfo = await getUserInfo(id, ctx.cache.tryGet);
|
||||
const { data: castData } = await got(`${apiBase}/users/${id}/casts/`);
|
||||
|
||||
const casts = castData.results.map((item) => renderCast(item));
|
||||
|
||||
ctx.state.data = {
|
||||
title: `${userInfo.name} (@${userInfo.username}) - 音声投稿 | OTOBANANA`,
|
||||
description: userInfo.bio.replace(/\n/g, ' '),
|
||||
link: `${baseUrl}/user/${id}`,
|
||||
image: userInfo.avatar_url,
|
||||
icon: userInfo.avatar_url,
|
||||
logo: userInfo.avatar_url,
|
||||
language: 'ja',
|
||||
author: userInfo.name,
|
||||
itunes_author: userInfo.name,
|
||||
item: casts,
|
||||
};
|
||||
|
||||
ctx.state.json = {
|
||||
userInfo,
|
||||
castData,
|
||||
};
|
||||
};
|
||||
|
|
@ -0,0 +1,29 @@
|
|||
const got = require('@/utils/got');
|
||||
const { apiBase, baseUrl, getUserInfo, renderLive } = require('./utils');
|
||||
|
||||
module.exports = async (ctx) => {
|
||||
const { id } = ctx.params;
|
||||
|
||||
const userInfo = await getUserInfo(id, ctx.cache.tryGet);
|
||||
const { data: liveData } = await got(`${apiBase}/users/${id}/livestreams/`);
|
||||
|
||||
const casts = liveData.results.map((item) => renderLive(item));
|
||||
|
||||
ctx.state.data = {
|
||||
title: `${userInfo.name} (@${userInfo.username}) - ライブ配信 | OTOBANANA`,
|
||||
description: userInfo.bio.replace(/\n/g, ' '),
|
||||
link: `${baseUrl}/user/${id}`,
|
||||
image: userInfo.avatar_url,
|
||||
icon: userInfo.avatar_url,
|
||||
logo: userInfo.avatar_url,
|
||||
language: 'ja',
|
||||
author: userInfo.name,
|
||||
itunes_author: userInfo.name,
|
||||
item: casts,
|
||||
};
|
||||
|
||||
ctx.state.json = {
|
||||
userInfo,
|
||||
liveData,
|
||||
};
|
||||
};
|
||||
|
|
@ -0,0 +1,5 @@
|
|||
module.exports = {
|
||||
'/user/:id': ['TonyRL'],
|
||||
'/user/:id/cast': ['TonyRL'],
|
||||
'/user/:id/livestream': ['TonyRL'],
|
||||
};
|
||||
|
|
@ -0,0 +1,25 @@
|
|||
module.exports = {
|
||||
'otobanana.com': {
|
||||
_name: 'OTOBANANA',
|
||||
'.': [
|
||||
{
|
||||
title: 'Timeline タイムライン',
|
||||
docs: 'https://docs.rsshub.app/multimedia#otobanana',
|
||||
source: ['/user/:id'],
|
||||
target: '/otobanana/user/:id',
|
||||
},
|
||||
{
|
||||
title: 'Cast 音声投稿',
|
||||
docs: 'https://docs.rsshub.app/multimedia#otobanana',
|
||||
source: ['/user/:id/cast', '/user/:id'],
|
||||
target: '/otobanana/user/:id/cast',
|
||||
},
|
||||
{
|
||||
title: 'Livestream ライブ配信',
|
||||
docs: 'https://docs.rsshub.app/multimedia#otobanana',
|
||||
source: ['/user/:id/livestream', '/user/:id'],
|
||||
target: '/otobanana/user/:id/livestream',
|
||||
},
|
||||
],
|
||||
},
|
||||
};
|
||||
|
|
@ -0,0 +1,5 @@
|
|||
module.exports = (router) => {
|
||||
router.get('/user/:id', require('./timeline'));
|
||||
router.get('/user/:id/cast', require('./cast'));
|
||||
router.get('/user/:id/livestream', require('./livestream'));
|
||||
};
|
||||
|
|
@ -0,0 +1,11 @@
|
|||
{{ if cast }}
|
||||
<img src="{{ cast.thumbnail_url }}">
|
||||
<br>
|
||||
<audio controls>
|
||||
<source src="{{ cast.audio_url }}" type="audio/x-m4a">
|
||||
</audio>
|
||||
<br>
|
||||
💬 {{ cast.comment_count }} ❤️ {{ cast.like_count }} 🍌 {{ cast.gift_banana }} {{ cast.play_count }} 再生
|
||||
<br>
|
||||
{{@ cast.text.replace(/\n/g, '<br>') }}
|
||||
{{ /if }}
|
||||
|
|
@ -0,0 +1,29 @@
|
|||
const got = require('@/utils/got');
|
||||
const { apiBase, baseUrl, getUserInfo, renderPost } = require('./utils');
|
||||
|
||||
module.exports = async (ctx) => {
|
||||
const { id } = ctx.params;
|
||||
|
||||
const userInfo = await getUserInfo(id, ctx.cache.tryGet);
|
||||
const { data: postData } = await got(`${apiBase}/users/${id}/posts/`);
|
||||
|
||||
const posts = postData.results.map((item) => renderPost(item));
|
||||
|
||||
ctx.state.data = {
|
||||
title: `${userInfo.name} (@${userInfo.username}) - タイムライン | OTOBANANA`,
|
||||
description: userInfo.bio.replace(/\n/g, ' '),
|
||||
link: `${baseUrl}/user/${id}`,
|
||||
image: userInfo.avatar_url,
|
||||
icon: userInfo.avatar_url,
|
||||
logo: userInfo.avatar_url,
|
||||
language: 'ja',
|
||||
author: userInfo.name,
|
||||
itunes_author: userInfo.name,
|
||||
item: posts,
|
||||
};
|
||||
|
||||
ctx.state.json = {
|
||||
userInfo,
|
||||
postData,
|
||||
};
|
||||
};
|
||||
|
|
@ -0,0 +1,67 @@
|
|||
const got = require('@/utils/got');
|
||||
const { parseDate } = require('@/utils/parse-date');
|
||||
const { art } = require('@/utils/render');
|
||||
const { join } = require('path');
|
||||
|
||||
const domain = 'otobanana.com';
|
||||
const apiBase = `https://api.${domain}`;
|
||||
const baseUrl = `https://${domain}`;
|
||||
|
||||
const getUserInfo = (id, tryGet) =>
|
||||
tryGet(`otobanana:user:${id}`, async () => {
|
||||
const { data } = await got(`${apiBase}/users/${id}/`);
|
||||
return data;
|
||||
});
|
||||
|
||||
const renderCast = (cast) => ({
|
||||
title: cast.title,
|
||||
description: art(join(__dirname, 'templates/description.art'), { cast }),
|
||||
pubDate: parseDate(cast.created_at),
|
||||
link: `https://otobanana.com/cast/${cast.id}`,
|
||||
author: `${cast.user.name} (@${cast.user.username})`,
|
||||
itunes_item_image: cast.thumbnail_url,
|
||||
itunes_duration: cast.duration_time,
|
||||
enclosure_url: cast.audio_url,
|
||||
enclosure_type: 'audio/x-m4a',
|
||||
upvotes: cast.like_count,
|
||||
comments: cast.comment_count,
|
||||
});
|
||||
|
||||
const renderLive = (live) => ({
|
||||
title: live.title,
|
||||
description: live.is_open ? '配信中のライブ' : '終了しました',
|
||||
pubDate: parseDate(live.created_at),
|
||||
link: live.room_url,
|
||||
guid: `${live.room_url}#${live.id}`,
|
||||
author: `${live.user.name} (@${live.user.username})`,
|
||||
upvotes: live.like_count,
|
||||
comments: live.comment_count,
|
||||
});
|
||||
|
||||
const renderPost = ({ id, type_label: type, cast, /** livestream */ message /** , event */ }) => {
|
||||
switch (type) {
|
||||
case 'cast':
|
||||
return renderCast(cast);
|
||||
case 'message':
|
||||
return {
|
||||
title: message.text.split('\n')[0],
|
||||
description: message.text.replace(/\n/g, '<br>'),
|
||||
pubDate: parseDate(message.created_at),
|
||||
link: `https://otobanana.com/${type}/${id}`,
|
||||
author: `${message.user.name} (@${message.user.username})`,
|
||||
upvotes: message.like_count,
|
||||
comments: message.comment_count,
|
||||
};
|
||||
default:
|
||||
throw Error(`Unknown post type: ${type}`);
|
||||
}
|
||||
};
|
||||
|
||||
module.exports = {
|
||||
apiBase,
|
||||
baseUrl,
|
||||
getUserInfo,
|
||||
renderCast,
|
||||
renderLive,
|
||||
renderPost,
|
||||
};
|
||||
|
|
@ -957,6 +957,20 @@ JavDB 有多个备用域名,本路由默认使用永久域名 `https://javdb.c
|
|||
`day` 类型的关键词必须填写 **日期** ,按照示例写成形如 `20200730` 的格式
|
||||
</Route>
|
||||
|
||||
## OTOBANANA {#otobanana}
|
||||
|
||||
### Timeline タイムライン {#otobanana-timeline-%E3%82%BF%E3%82%A4%E3%83%A0%E3%83%A9%E3%82%A4%E3%83%B3}
|
||||
|
||||
<Route author="TonyRL" example="/otobanana/user/cee16401-96b1-420f-8188-abd4d33093f1" path="/otobanana/user/:id" paramsDesc={['User ID, can be found in URL']} radar="1" supportPodcast="1" />
|
||||
|
||||
### Cast 音声投稿 {#otobanana-cast-yin-sheng-tou-gao}
|
||||
|
||||
<Route author="TonyRL" example="/otobanana/user/cee16401-96b1-420f-8188-abd4d33093f1/cast" path="/otobanana/user/:id/cast" paramsDesc={['User ID, can be found in URL']} radar="1" supportPodcast="1" />
|
||||
|
||||
### Livestream ライブ配信 {#otobanana-livestream-%E3%83%A9%E3%82%A4%E3%83%96-pei-xin}
|
||||
|
||||
<Route author="TonyRL" example="/otobanana/user/cee16401-96b1-420f-8188-abd4d33093f1/livestream" path="/otobanana/user/:id/livestream" paramsDesc={['User ID, can be found in URL']} radar="1" />
|
||||
|
||||
## PornHub {#pornhub}
|
||||
|
||||
### Category {#pornhub-category}
|
||||
|
|
|
|||
Loading…
Reference in New Issue