feat(route): add route for skebetter (#17181)

* feat(route): add route for skebetter

* feat: add radar

* Update lib/routes/skebetter/index.ts

Co-authored-by: Tony <TonyRL@users.noreply.github.com>

* Update lib/routes/skebetter/manga.ts

Co-authored-by: Tony <TonyRL@users.noreply.github.com>

* Update lib/routes/skebetter/illust.ts

Co-authored-by: Tony <TonyRL@users.noreply.github.com>

* fix: import config

---------
This commit is contained in:
Tsuyumi 2024-10-18 13:59:37 +08:00 committed by GitHub
parent 69a35d2f56
commit ff76aa7267
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
5 changed files with 309 additions and 0 deletions

View File

@ -0,0 +1,83 @@
import { Data, DataItem, Route } from '@/types';
import cache from '@/utils/cache';
import { processItems, fetchData } from './utils';
import { config } from '@/config';
export const route: Route = {
path: '/illust/:type',
categories: ['anime'],
example: '/skebetter/illust/hot',
parameters: { type: 'Type, see below' },
features: {
requireConfig: false,
requirePuppeteer: false,
antiCrawler: false,
supportBT: false,
supportPodcast: false,
supportScihub: false,
},
name: 'Illust',
maintainers: ['SnowAgar25'],
handler,
radar: [
{
title: 'Illust - Hot',
source: ['skebetter.com/illust'],
target: '/illust/hot',
},
{
title: 'Illust - Week',
source: ['skebetter.com/illust'],
target: '/illust/week',
},
{
title: 'Illust - Month',
source: ['skebetter.com/illust'],
target: '/illust/month',
},
{
title: 'Illust - Latest',
source: ['skebetter.com/illust'],
target: '/illust/latest',
},
],
description: `
| | | | |
| ----- | ---- | ---- | ---- |
| hot | week | month| latest |`,
};
async function handler(ctx): Promise<Data> {
const type = ctx.req.param('type');
const baseUrl = 'https://api.twieromanga.com/api/illust/hot';
const typeMap = {
hot: '急上昇',
week: '週間',
month: '月間',
latest: '新着',
};
const linkMap = {
hot: '',
week: '?term=week',
month: '?term=month',
latest: '?term=latest',
};
const url = `${baseUrl}?type=${type}`;
const items = await cache.tryGet(
url,
async () => {
const data = await fetchData(url);
return processItems(data, 'illust');
},
config.cache.routeExpire,
false
);
return {
title: `Skebetter Illust - ${typeMap[type]}`,
link: `https://skebetter.com/illust${linkMap[type]}`,
item: items as DataItem[],
};
}

View File

@ -0,0 +1,83 @@
import { Data, DataItem, Route } from '@/types';
import cache from '@/utils/cache';
import { processItems, fetchData } from './utils';
import { config } from '@/config';
export const route: Route = {
path: '/:type',
categories: ['anime'],
example: '/skebetter/hot',
parameters: { type: 'Type, see below' },
features: {
requireConfig: false,
requirePuppeteer: false,
antiCrawler: false,
supportBT: false,
supportPodcast: false,
supportScihub: false,
},
name: 'Hot',
maintainers: ['SnowAgar25'],
handler,
radar: [
{
title: 'Skebetter - Hot',
source: ['skebetter.com'],
target: '/hot',
},
{
title: 'Skebetter - Week',
source: ['skebetter.com'],
target: '/week',
},
{
title: 'Skebetter - Month',
source: ['skebetter.com'],
target: '/month',
},
{
title: 'Skebetter - Latest',
source: ['skebetter.com'],
target: '/latest',
},
],
description: `
| | | | |
| ----- | ---- | ---- | ---- |
| hot | week | month| latest |`,
};
async function handler(ctx): Promise<Data> {
const type = ctx.req.param('type');
const baseUrl = 'https://api.twieromanga.com/api/hotv2';
const typeMap = {
hot: '急上昇',
week: '週間',
month: '月間',
latest: '新着',
};
const linkMap = {
hot: '',
week: '?term=week',
month: '?term=month',
latest: '?term=latest',
};
const url = `${baseUrl}?type=${type}`;
const items = await cache.tryGet(
url,
async () => {
const data = await fetchData(url);
return processItems(data, 'index');
},
config.cache.routeExpire,
false
);
return {
title: `Skebetter - ${typeMap[type]}`,
link: `https://skebetter.com/${linkMap[type]}`,
item: items as DataItem[],
};
}

View File

@ -0,0 +1,65 @@
import { Data, DataItem, Route } from '@/types';
import cache from '@/utils/cache';
import { processItems, fetchData } from './utils';
import { config } from '@/config';
export const route: Route = {
path: '/manga/:order',
categories: ['anime'],
example: '/skebetter/manga/1',
parameters: { order: 'Order, see below.' },
features: {
requireConfig: false,
requirePuppeteer: false,
antiCrawler: false,
supportBT: false,
supportPodcast: false,
supportScihub: false,
},
name: 'Manga',
maintainers: ['SnowAgar25'],
handler,
radar: [
{
title: 'Manga - Latest',
source: ['skebetter.com/series'],
target: '/manga/1',
},
{
title: 'Manga - Hot',
source: ['skebetter.com/series'],
target: '/manga/2',
},
],
description: `
| (Latest) | (Hot) |
| ---- | ---- |
| 1 | 2 |`,
};
async function handler(ctx): Promise<Data> {
const order = ctx.req.param('order') ?? '1';
const baseUrl = 'https://api.twieromanga.com/api/mangaseries';
const orderMap = {
'1': '新着',
'2': '人気',
};
const url = `${baseUrl}?order=${order}`;
const items = await cache.tryGet(
url,
async () => {
const data = await fetchData(url, true);
return processItems(data, 'manga');
},
config.cache.routeExpire,
false
);
return {
title: `Skebetter Manga - ${orderMap[order]}`,
link: `https://skebetter.com/series?order=${order}`,
item: items as DataItem[],
};
}

View File

@ -0,0 +1,6 @@
import type { Namespace } from '@/types';
export const namespace: Namespace = {
name: 'Skebetter',
url: 'skebetter.com',
};

View File

@ -0,0 +1,72 @@
import { DataItem } from '@/types';
import { ofetch } from 'ofetch';
export interface MediaUrl {
h: number;
w: number;
sh: number;
sw: number;
type: string;
media_id: string | null;
media_uri: string;
media_index: number;
}
export interface Tweet {
id: string;
screen_name: string;
series_id?: number;
text: string;
date: string;
img: string;
user_name: string;
fav: string;
retweet: string;
user_id: string;
media_url: string;
media_count: number;
hashtags?: Record<string, unknown>;
media_urls: MediaUrl[];
score: string;
rank: number;
}
export const processItems = (data: Tweet[], type: 'index' | 'illust' | 'manga'): DataItem[] =>
data.map((item) => {
const baseAuthorUrl = `https://skebetter.com/author/${item.user_id}`;
const description = `
<p>${item.fav} 🔁${item.retweet}</p>
${item.media_urls.map((media) => `<img src="${media.media_uri}" />`).join('')}
`;
if (type === 'manga') {
return {
title: item.text,
description,
author: item.user_name,
link: `https://skebetter.com/series/${item.series_id}`,
};
}
if (type === 'illust') {
return {
title: item.text,
description,
author: item.user_name,
link: `${baseAuthorUrl}/illust/${item.id}`,
};
}
// type === 'index'
return {
title: item.text,
description,
author: item.user_name,
link: item.series_id ? `https://skebetter.com/series/${item.series_id}` : `${baseAuthorUrl}/manga/${item.id}`,
};
});
export const fetchData = async (url: string, isManga: boolean = false) => {
const response = await ofetch(url);
return isManga ? (response as Tweet[]) : (response.tweet as Tweet[]);
};