rsshub
Version:
Make RSS Great Again!
340 lines (313 loc) • 11.1 kB
text/typescript
import { type Data, type DataItem, type Route, ViewType } from '@/types';
import { art } from '@/utils/render';
import cache from '@/utils/cache';
import ofetch from '@/utils/ofetch';
import { type CheerioAPI, type Cheerio, load } from 'cheerio';
import type { Element } from 'domhandler';
import { type Context } from 'hono';
import path from 'node:path';
export const handler = async (ctx: Context): Promise<Data> => {
const { category = '0', sort = 'latest' } = ctx.req.param();
const limit: number = Number.parseInt(ctx.req.query('limit') ?? '30', 10);
const baseUrl: string = 'https://koyso.to';
const targetUrl: string = new URL(`?${category === '0' ? '' : `category=${category}&`}sort=${sort}`, baseUrl).href;
const response = await ofetch(targetUrl);
const $: CheerioAPI = load(response);
const language = $('html').attr('lang') ?? 'en';
let items: DataItem[] = [];
items = $('a.game_item')
.slice(0, limit)
.toArray()
.map((el): Element => {
const $el: Cheerio<Element> = $(el);
const title: string = $el.find('div.game_info').text();
const image: string | undefined = $el.find('div.game_media img').attr('data-src');
const description: string | undefined = art(path.join(__dirname, 'templates/description.art'), {
images: image
? [
{
src: image,
alt: title,
},
]
: undefined,
});
const linkUrl: string | undefined = $el.attr('href');
const processedItem: DataItem = {
title,
description,
link: linkUrl ? new URL(linkUrl, baseUrl).href : undefined,
content: {
html: description,
text: description,
},
image,
banner: image,
language,
};
return processedItem;
});
items = await Promise.all(
items.map((item) => {
if (!item.link) {
return item;
}
return cache.tryGet(item.link, async (): Promise<DataItem> => {
const detailResponse = await ofetch(item.link);
const $$: CheerioAPI = load(detailResponse);
$$('div.ind').remove();
$$('div.download_div').remove();
const title: string = $$('h1.content_title').text();
$$('h1.content_title').remove();
const description: string | undefined = item.description + ($$('div.game_content').html() || '');
const processedItem: DataItem = {
title,
description,
content: {
html: description,
text: description,
},
language,
};
return {
...item,
...processedItem,
};
});
})
);
const categoryName: string = $(`ul.category li#category_${category}`).text();
const sortName: string = $(`div.genres_content ul li.${sort}`).text();
return {
title: `${$('title').text()} - ${categoryName} - ${sortName}`,
description: $('meta[name="description"]').attr('content'),
link: targetUrl,
item: items,
allowEmpty: true,
language,
id: targetUrl,
};
};
export const route: Route = {
path: '/:category?/:sort?',
name: '游戏',
url: 'koyso.to',
maintainers: ['nczitzk'],
handler,
example: '/koyso/0/latest',
parameters: {
category: {
description: '排序,默认为 `0`,即全部,可在对应分类页 URL 中找到',
options: [
{
label: '全部游戏',
value: '0',
},
{
label: '动作游戏',
value: '3',
},
{
label: '冒险游戏',
value: '5',
},
{
label: '绅士游戏',
value: '7',
},
{
label: '射击游戏',
value: '1',
},
{
label: '休闲游戏',
value: '2',
},
{
label: '体育竞速',
value: '4',
},
{
label: '模拟经营',
value: '6',
},
{
label: '角色扮演',
value: '8',
},
{
label: '策略游戏',
value: '9',
},
{
label: '格斗游戏',
value: '10',
},
{
label: '恐怖游戏',
value: '11',
},
{
label: '即时战略',
value: '12',
},
{
label: '卡牌游戏',
value: '13',
},
{
label: '独立游戏',
value: '14',
},
{
label: '局域网联机',
value: '15',
},
],
},
sort: {
description: '排序,默认为 `latest`,即最新,可在对应页 URL 中找到',
options: [
{
label: '热度',
value: 'views',
},
{
label: '最新',
value: 'latest',
},
],
},
},
description: `::: tip
订阅 [最新动作游戏](https://koyso.to/?category=3&sort=latest),其源网址为 \`https://koyso.to/?category=3&sort=latest\`,请参考该 URL 指定部分构成参数,此时路由为 [\`/koyso/3/latest\`](https://koyso.to/?category=3&sort=latest)。
:::
#### 分类
| 分类 | ID |
| ------------------------------------------- | --------------------------------- |
| [全部游戏](https://koyso.to/) | [0](https://rsshub.app/koyso/0) |
| [动作游戏](https://koyso.to/?category=3) | [3](https://rsshub.app/koyso/3) |
| [冒险游戏](https://koyso.to/?category=5) | [5](https://rsshub.app/koyso/5) |
| [绅士游戏](https://koyso.to/?category=7) | [7](https://rsshub.app/koyso/7) |
| [射击游戏](https://koyso.to/?category=1) | [1](https://rsshub.app/koyso/1) |
| [休闲游戏](https://koyso.to/?category=2) | [2](https://rsshub.app/koyso/2) |
| [体育竞速](https://koyso.to/?category=4) | [4](https://rsshub.app/koyso/4) |
| [模拟经营](https://koyso.to/?category=6) | [6](https://rsshub.app/koyso/6) |
| [角色扮演](https://koyso.to/?category=8) | [8](https://rsshub.app/koyso/8) |
| [策略游戏](https://koyso.to/?category=9) | [9](https://rsshub.app/koyso/9) |
| [格斗游戏](https://koyso.to/?category=10) | [10](https://rsshub.app/koyso/10) |
| [恐怖游戏](https://koyso.to/?category=11) | [11](https://rsshub.app/koyso/11) |
| [即时战略](https://koyso.to/?category=12) | [12](https://rsshub.app/koyso/12) |
| [卡牌游戏](https://koyso.to/?category=13) | [13](https://rsshub.app/koyso/13) |
| [独立游戏](https://koyso.to/?category=14) | [14](https://rsshub.app/koyso/14) |
| [局域网联机](https://koyso.to/?category=15) | [15](https://rsshub.app/koyso/15) |
#### 排序
| 排序 | ID |
| ------------------------------------- | ------------------------------------------- |
| [热度](https://koyso.to/?sort=views) | [views](https://rsshub.app/koyso/0/views) |
| [最新](https://koyso.to/?sort=latest) | [latest](https://rsshub.app/koyso/0/latest) |
`,
categories: ['game'],
features: {
requireConfig: false,
requirePuppeteer: false,
antiCrawler: false,
supportRadar: true,
supportBT: false,
supportPodcast: false,
supportScihub: false,
nsfw: true,
},
radar: [
{
source: ['koyso.to'],
target: (_, url) => {
const urlObj: URL = new URL(url);
const category: string | undefined = urlObj.searchParams.get('category') ?? undefined;
const sort: string | undefined = urlObj.searchParams.get('sort') ?? undefined;
return `/koyso${category ? `/${category}` : '0'}${sort ? `/${sort}` : ''}`;
},
},
{
title: '全部游戏',
source: ['koyso.to'],
target: '/0',
},
{
title: '动作游戏',
source: ['koyso.to'],
target: '/3',
},
{
title: '冒险游戏',
source: ['koyso.to'],
target: '/5',
},
{
title: '绅士游戏',
source: ['koyso.to'],
target: '/7',
},
{
title: '射击游戏',
source: ['koyso.to'],
target: '/1',
},
{
title: '休闲游戏',
source: ['koyso.to'],
target: '/2',
},
{
title: '体育竞速',
source: ['koyso.to'],
target: '/4',
},
{
title: '模拟经营',
source: ['koyso.to'],
target: '/6',
},
{
title: '角色扮演',
source: ['koyso.to'],
target: '/8',
},
{
title: '策略游戏',
source: ['koyso.to'],
target: '/9',
},
{
title: '格斗游戏',
source: ['koyso.to'],
target: '/10',
},
{
title: '恐怖游戏',
source: ['koyso.to'],
target: '/11',
},
{
title: '即时战略',
source: ['koyso.to'],
target: '/12',
},
{
title: '卡牌游戏',
source: ['koyso.to'],
target: '/13',
},
{
title: '独立游戏',
source: ['koyso.to'],
target: '/14',
},
{
title: '局域网联机',
source: ['koyso.to'],
target: '/15',
},
],
view: ViewType.Articles,
};