From 02f8872d5a8b7918f2d4fc4ab5894a429a365b80 Mon Sep 17 00:00:00 2001 From: Ethan Shen Date: Sun, 23 Jan 2022 00:09:54 +0800 Subject: [PATCH] feat(route): add Kemono (#8640) --- docs/anime.md | 20 ++++++++ docs/en/anime.md | 20 ++++++++ lib/v2/kemono/index.js | 99 +++++++++++++++++++++++++++++++++++++ lib/v2/kemono/maintainer.js | 4 ++ lib/v2/kemono/radar.js | 13 +++++ lib/v2/kemono/router.js | 3 ++ 6 files changed, 159 insertions(+) create mode 100644 lib/v2/kemono/index.js create mode 100644 lib/v2/kemono/maintainer.js create mode 100644 lib/v2/kemono/radar.js create mode 100644 lib/v2/kemono/router.js diff --git a/docs/anime.md b/docs/anime.md index 3a89b5030c..c16af579c0 100644 --- a/docs/anime.md +++ b/docs/anime.md @@ -253,6 +253,26 @@ pageClass: routes +## Kemono + +### Posts + + + +Sources + +| Posts | Patreon | Pixiv Fanbox | Gumroad | SubscribeStar | DLsite | Discord | Fantia | +| ----- | ------- | ------------ | ------- | ------------- | ------ | ------- | ------ | +| posts | patreon | fanbox | gumroad | subscribestar | dlsite | discord | fantia | + +::: tip 提示 + +当选择 `posts` 作为参数 **source** 的值时,参数 **id** 不生效。 + +::: + + + ## Mox.moe ### 首頁 diff --git a/docs/en/anime.md b/docs/en/anime.md index de298e77c6..18ae2c4198 100644 --- a/docs/en/anime.md +++ b/docs/en/anime.md @@ -10,6 +10,26 @@ pageClass: routes +## Kemono + +### Posts + + + +Sources + +| Posts | Patreon | Pixiv Fanbox | Gumroad | SubscribeStar | DLsite | Discord | Fantia | +| ----- | ------- | ------------ | ------- | ------------- | ------ | ------- | ------ | +| posts | patreon | fanbox | gumroad | subscribestar | dlsite | discord | fantia | + +::: tip Tip + +When `posts` is selected as the value of the parameter **source**, the parameter **id** does not take effect. + +::: + + + ## Touhougarakuta ### Articles diff --git a/lib/v2/kemono/index.js b/lib/v2/kemono/index.js new file mode 100644 index 0000000000..6650c221f8 --- /dev/null +++ b/lib/v2/kemono/index.js @@ -0,0 +1,99 @@ +const got = require('@/utils/got'); +const cheerio = require('cheerio'); +const { parseDate } = require('@/utils/parse-date'); + +module.exports = async (ctx) => { + const source = ctx.params.source ?? ''; + const id = ctx.params.id; + + const rootUrl = 'https://kemono.party'; + const apiUrl = `${rootUrl}/api/discord/channels/lookup?q=${id}`; + const currentUrl = `${rootUrl}/${source ? `${source}/${source === 'discord' ? `server/${id}` : `user/${id}`}` : 'posts'}`; + + const headers = { + cookie: '__ddg2=sBQ4uaaGecmfEUk7', + }; + + const response = await got({ + method: 'get', + url: source === 'discord' ? apiUrl : currentUrl, + headers, + }); + + let items = [], + title = ''; + + if (source === 'discord') { + title = `Posts of ${id} from Discord | Kemono`; + + await Promise.all( + response.data.map(async (channel) => { + await ctx.cache.tryGet(channel.id, async () => { + const channelResponse = await got({ + method: 'get', + url: `${rootUrl}/api/discord/channel/${channel.id}?skip=0`, + headers, + }); + + items.push( + ...channelResponse.data + .filter((i) => i.content || i.attachments) + .map((i) => ({ + title: i.content, + description: (i.content ? `

${i.content}

` : '') + (i.attachments ? i.attachments.map((a) => ``).join('') : ''), + author: i.author.username, + pubDate: parseDate(i.published), + category: channel.name, + })) + ); + }); + }) + ); + } else { + const $ = cheerio.load(response.data); + + title = $('title').text(); + + items = await Promise.all( + $('.post-card') + .find('.fancy-link') + .slice(0, ctx.query.limit ? parseInt(ctx.query.limit) : 25) + .toArray() + .map((item) => { + item = $(item); + + return { + link: `${rootUrl}${item.attr('href')}`, + }; + }) + .map((item) => + ctx.cache.tryGet(item.link, async () => { + const detailResponse = await got({ + method: 'get', + url: item.link, + headers, + }); + + const content = cheerio.load(detailResponse.data); + + content('.post__thumbnail').each(function () { + content(this).html(``); + }); + + item.description = content('.post__body').html(); + item.author = content('.post__user-name').text(); + item.title = content('.post__title span').first().text(); + item.pubDate = parseDate(content('.timestamp').attr('datetime')); + + return item; + }) + ) + ); + } + + ctx.state.data = { + title, + link: currentUrl, + item: items, + }; +}; diff --git a/lib/v2/kemono/maintainer.js b/lib/v2/kemono/maintainer.js new file mode 100644 index 0000000000..9f495da076 --- /dev/null +++ b/lib/v2/kemono/maintainer.js @@ -0,0 +1,4 @@ +module.exports = { + '/:source?/:id?': ['nczitzk'], + '/posts': ['nczitzk'], +}; diff --git a/lib/v2/kemono/radar.js b/lib/v2/kemono/radar.js new file mode 100644 index 0000000000..f603d66e51 --- /dev/null +++ b/lib/v2/kemono/radar.js @@ -0,0 +1,13 @@ +module.exports = { + 'kemono.party': { + _name: 'Kemono', + '.': [ + { + title: 'Posts', + docs: 'https://docs.rsshub.app/anime.html#kemono-posts', + source: ['/:source/user/:id', '/'], + target: '/kemono/:source?/:id?', + }, + ], + }, +}; diff --git a/lib/v2/kemono/router.js b/lib/v2/kemono/router.js new file mode 100644 index 0000000000..a9e750fd89 --- /dev/null +++ b/lib/v2/kemono/router.js @@ -0,0 +1,3 @@ +module.exports = function (router) { + router.get('/:source?/:id?', require('./index')); +};