From 264bd1d21f35013b1abafd2f1472472707aa48e5 Mon Sep 17 00:00:00 2001 From: Tsuyumi25 <40047364+Tsuyumi25@users.noreply.github.com> Date: Sat, 1 Mar 2025 02:40:27 +0800 Subject: [PATCH] feat(route): add news route for toranoana.jp (#18479) * feat: add news * fix: add thumbnail * Update news.ts * Update lib/routes/toranoana/news.ts Co-authored-by: Tony * fix: use _embed in query instead of /media api * fix: add null check for _embedded --------- --- lib/routes/toranoana/namespace.ts | 7 ++ lib/routes/toranoana/news.ts | 110 ++++++++++++++++++++++++++++++ 2 files changed, 117 insertions(+) create mode 100644 lib/routes/toranoana/namespace.ts create mode 100644 lib/routes/toranoana/news.ts diff --git a/lib/routes/toranoana/namespace.ts b/lib/routes/toranoana/namespace.ts new file mode 100644 index 0000000000..3d48496571 --- /dev/null +++ b/lib/routes/toranoana/namespace.ts @@ -0,0 +1,7 @@ +import type { Namespace } from '@/types'; + +export const namespace: Namespace = { + name: 'とらのあな', + url: 'toranoana.jp', + lang: 'ja', +}; diff --git a/lib/routes/toranoana/news.ts b/lib/routes/toranoana/news.ts new file mode 100644 index 0000000000..404c1f513f --- /dev/null +++ b/lib/routes/toranoana/news.ts @@ -0,0 +1,110 @@ +import { Route, Data, DataItem } from '@/types'; +import ofetch from '@/utils/ofetch'; +import { parseDate } from '@/utils/parse-date'; +import { load } from 'cheerio'; + +export const route: Route = { + path: '/news/:category?', + categories: ['anime'], + example: '/toranoana/news/toragen', + parameters: { category: 'category' }, + features: { + requireConfig: false, + requirePuppeteer: false, + antiCrawler: false, + supportBT: false, + supportPodcast: false, + supportScihub: false, + }, + name: 'Category', + maintainers: ['Tsuyumi25'], + handler, + radar: [ + { + title: '総合新着記事', + source: ['news.toranoana.jp'], + target: '/news', + }, + { + title: '女性向け', + source: ['news.toranoana.jp/joshi'], + target: '/news/joshi', + }, + { + title: 'イラスト展', + source: ['news.toranoana.jp/exhibitions'], + target: '/news/exhibition', + }, + { + source: ['news.toranoana.jp/category/:category'], + target: '/news/:category', + }, + ], + description: ` +::: warning TIP +[総合新着記事](https://news.toranoana.jp)→\`/toranoana/news\` +[女性向け](https://news.toranoana.jp/joshi)→\`/toranoana/news/joshi\` +[イラスト展](https://news.toranoana.jp/exhibitions)→\`/toranoana/news/exhibition\` +[\`https://news.toranoana.jp/category/media\`](https://news.toranoana.jp/category/media)→\`/toranoana/news/media\` +:::`, +}; + +async function handler(ctx): Promise { + const { category = '' } = ctx.req.param(); + let apiUrl = 'https://news.toranoana.jp/wp-json/wp/v2/posts'; + + if (category) { + const categoryResponse = await ofetch(`https://news.toranoana.jp/wp-json/wp/v2/categories?slug=${category}`); + if (categoryResponse && categoryResponse.length > 0) { + apiUrl += `?categories=${categoryResponse[0].id}`; + } + } else { + // exclude category-joshi to get result of general + apiUrl += `?categories_exclude=1598`; + } + + const posts = await ofetch(apiUrl, { + query: { + per_page: 20, + _embed: 'wp:featuredmedia', + }, + }); + + if (!posts || !posts.length) { + throw new Error('No posts found'); + } + + const items = posts.map((post) => { + const $ = load(post.content.rendered); + + // remove unnecessary title + $('h1').first().remove(); + $('h2').first().remove(); + + let thumbnail = ''; + if (post._embedded && post._embedded['wp:featuredmedia'][0].source_url) { + thumbnail = post._embedded['wp:featuredmedia'][0].source_url; + } + + if (thumbnail) { + $('body').prepend(`${post.title.rendered}`); + } + + return { + title: post.title.rendered, + link: post.link, + description: $.html(), + pubDate: parseDate(post.date_gmt), + guid: post.link, + author: 'とらのあな', + }; + }); + + return { + title: category ? `とらのあな総合インフォメーション - ${category}` : 'とらのあな総合インフォメーション', + link: category ? `https://news.toranoana.jp/category/${category}` : 'https://news.toranoana.jp/', + description: 'とらのあなの最新情報をお届け!同人誌、書籍、コミック、店舗フェア、イラスト展、とらのあな限定版、キャンペーンなど…スペシャルでお得な情報をいち早くチェック!', + item: items.filter(Boolean) as DataItem[], + language: 'ja', + }; +}