Skip to content

Commit

Permalink
feat(route): kakuyomu (DIYgod#16679)
Browse files Browse the repository at this point in the history
* feat(route): kakuyomu

* remove any types
  • Loading branch information
KarasuShin committed Sep 10, 2024
1 parent 69b58e8 commit 69745ad
Show file tree
Hide file tree
Showing 3 changed files with 85 additions and 0 deletions.
6 changes: 6 additions & 0 deletions lib/routes/kakuyomu/namespace.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,6 @@
import type { Namespace } from '@/types';

export const namespace: Namespace = {
name: 'カクヨム',
url: 'kakuyomu.jp',
};
6 changes: 6 additions & 0 deletions lib/routes/kakuyomu/types.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,6 @@
export interface NextDataEpisode {
__typename: 'Episode';
id: string;
title: string;
publishedAt: string;
}
73 changes: 73 additions & 0 deletions lib/routes/kakuyomu/works.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,73 @@
import type { Data, DataItem, Route } from '@/types';
import { load } from 'cheerio';
import type { Context } from 'hono';
import ofetch from '@/utils/ofetch';
import cache from '@/utils/cache';
import type { NextDataEpisode } from './types';
import { parseDate } from '@/utils/parse-date';

export const route: Route = {
name: '投稿',
categories: ['reading'],
path: '/works/:id',
example: '/kakuyomu/works/1177354054894027232',
parameters: {
id: '投稿 ID',
},
maintainers: ['KarasuShin'],
handler,
features: {
supportRadar: true,
},
radar: [
{
source: ['kakuyomu.jp/works/:id'],
target: '/works/:id',
},
],
};

async function handler(ctx: Context): Promise<Data> {
const id = ctx.req.param('id');
const url = `https://kakuyomu.jp/works/${id}`;
const limit = Number.parseInt(ctx.req.query('limit') || '10');
const $ = load(await ofetch(url));

const nextData = JSON.parse($('#__NEXT_DATA__').text());

const {
props: {
pageProps: { __APOLLO_STATE__ },
},
} = nextData;

const {
[`Work:${id}`]: { title, catchphrase },
} = __APOLLO_STATE__;

const values = Object.values(__APOLLO_STATE__);
const episodes = values.filter((value) => value.__typename === 'Episode') as NextDataEpisode[];
const items = (await Promise.all(
episodes
.sort((a, b) => b.publishedAt.localeCompare(a.publishedAt))
.slice(0, limit)
.map((item) => {
const episodeUrl = `https://kakuyomu.jp/works/${id}/episodes/${item.id}`;
return cache.tryGet(episodeUrl, async () => {
const $ = load(await ofetch(episodeUrl));
const description = $('.widget-episodeBody').html();
return {
title: item.title,
description,
pubDate: parseDate(item.publishedAt),
};
});
})
)) as DataItem[];

return {
title,
description: catchphrase,
item: items,
};
}

0 comments on commit 69745ad

Please sign in to comment.