diff --git a/lib/routes/kadokawa/blog.ts b/lib/routes/kadokawa/blog.ts
new file mode 100644
index 000000000..b44109db5
--- /dev/null
+++ b/lib/routes/kadokawa/blog.ts
@@ -0,0 +1,134 @@
+import { Route } from '@/types';
+import { getCurrentPath } from '@/utils/helpers';
+const __dirname = getCurrentPath(import.meta.url);
+
+import cache from '@/utils/cache';
+import got from '@/utils/got';
+import { load } from 'cheerio';
+import { parseDate } from '@/utils/parse-date';
+import { art } from '@/utils/render';
+import path from 'node:path';
+
+export const handler = async (ctx) => {
+ const limit = ctx.req.query('limit') ? Number.parseInt(ctx.req.query('limit'), 10) : 10;
+
+ const rootUrl = 'https://www.kadokawa.com.tw';
+ const currentUrl = new URL('blog/posts', rootUrl).href;
+
+ const { data: response } = await got(currentUrl);
+
+ const $ = load(response);
+
+ const language = $('html').prop('lang');
+
+ let items = $('div.List-item')
+ .slice(0, limit)
+ .toArray()
+ .map((item) => {
+ item = $(item);
+
+ const image = item.find('div.List-item-excerpt img').prop('src')?.split(/\?/)[0] ?? undefined;
+ const title = item.find('h2.List-item-title').text();
+ const description = art(path.join(__dirname, 'templates/description.art'), {
+ images: image
+ ? [
+ {
+ src: image,
+ alt: title,
+ },
+ ]
+ : undefined,
+ intro: item.find('div.List-item-preview').text(),
+ });
+
+ return {
+ title,
+ description,
+ pubDate: parseDate(item.find('span.primary-border-color-after').text()),
+ link: new URL(item.find('a').prop('href'), rootUrl).href,
+ content: {
+ html: description,
+ text: item.find('div.List-item-preview').text(),
+ },
+ image,
+ banner: image,
+ language,
+ enclosure_url: image,
+ enclosure_type: image ? `image/${image.split(/\./).pop()}` : undefined,
+ enclosure_title: title,
+ };
+ });
+
+ items = await Promise.all(
+ items.map((item) =>
+ cache.tryGet(item.link, async () => {
+ const { data: detailResponse } = await got(item.link);
+
+ const $$ = load(detailResponse);
+
+ const title = $$('h1.Post-title').text().trim();
+ const description = art(path.join(__dirname, 'templates/description.art'), {
+ description: $$('div.Post-content').html(),
+ });
+ const image = $$('meta[property="og:image"]').prop('content')?.split(/\?/)[0] ?? undefined;
+
+ item.title = title;
+ item.description = description;
+ item.pubDate = parseDate($$('div.Post-date').text().trim());
+ item.content = {
+ html: description,
+ text: $$('div.Post-content').text(),
+ };
+ item.image = image;
+ item.banner = image;
+ item.language = language;
+ item.enclosure_url = image;
+ item.enclosure_type = image ? `image/${image.split(/\./).pop()}` : undefined;
+ item.enclosure_title = title;
+
+ return item;
+ })
+ )
+ );
+
+ const image = new URL($('meta[property="og:image"]').prop('content'), rootUrl).href;
+
+ return {
+ title: $('title').text(),
+ description: $('meta[property="og:description"]').prop('content'),
+ link: currentUrl,
+ item: items,
+ allowEmpty: true,
+ image,
+ author: $('meta[property="og:site_name"]').prop('content'),
+ language,
+ };
+};
+
+export const route: Route = {
+ path: '/blog',
+ name: '角編新聞台',
+ url: 'kadokawa.com.tw',
+ maintainers: ['nczitzk'],
+ handler,
+ example: '/kadokawa/blog',
+ parameters: undefined,
+ description: '',
+ categories: ['blog'],
+
+ features: {
+ requireConfig: false,
+ requirePuppeteer: false,
+ antiCrawler: false,
+ supportRadar: true,
+ supportBT: false,
+ supportPodcast: false,
+ supportScihub: false,
+ },
+ radar: [
+ {
+ source: ['kadokawa.com.tw/blog/posts'],
+ target: '/blog',
+ },
+ ],
+};
diff --git a/lib/routes/kadokawa/namespace.ts b/lib/routes/kadokawa/namespace.ts
new file mode 100644
index 000000000..228413266
--- /dev/null
+++ b/lib/routes/kadokawa/namespace.ts
@@ -0,0 +1,8 @@
+import type { Namespace } from '@/types';
+
+export const namespace: Namespace = {
+ name: '台灣角川',
+ url: 'kadokawa.com.tw',
+ categories: ['shopping'],
+ description: 'TAIWAN KADOKAWA',
+};
diff --git a/lib/routes/kadokawa/templates/description.art b/lib/routes/kadokawa/templates/description.art
new file mode 100644
index 000000000..249654e7e
--- /dev/null
+++ b/lib/routes/kadokawa/templates/description.art
@@ -0,0 +1,21 @@
+{{ if images }}
+ {{ each images image }}
+ {{ if image?.src }}
+
+
{{ intro }}+{{ /if }} + +{{ if description }} + {{@ description }} +{{ /if }} \ No newline at end of file