fix(route): duplicate-object-key (#15494)
* fix(route): duplicate-object-key * fix: split routes * fix: split routes * fix: typo
This commit is contained in:
parent
7892a54431
commit
936e7032d2
|
|
@ -0,0 +1,23 @@
|
|||
import { Route } from '@/types';
|
||||
import { handler } from './common';
|
||||
|
||||
export const route: Route = {
|
||||
name: '分类',
|
||||
path: ['/category/:id'],
|
||||
example: '/cnbeta/category/movie',
|
||||
maintainers: ['nczitzk'],
|
||||
parameters: {
|
||||
id: '分类 id,可在对应分类页的 URL 中找到',
|
||||
},
|
||||
radar: [
|
||||
{
|
||||
source: ['cnbeta.com.tw/category/:id'],
|
||||
target: (params) => `/cnbeta/category/${params.id.replace('.htm', '')}`,
|
||||
},
|
||||
],
|
||||
handler,
|
||||
url: 'cnbeta.com.tw',
|
||||
description: `| 影视 | 音乐 | 游戏 | 动漫 | 趣闻 | 科学 | 软件 |
|
||||
| ----- | ----- | ---- | ----- | ----- | ------- | ---- |
|
||||
| movie | music | game | comic | funny | science | soft |`,
|
||||
};
|
||||
|
|
@ -1,4 +1,3 @@
|
|||
import { Route } from '@/types';
|
||||
import cache from '@/utils/cache';
|
||||
import got from '@/utils/got';
|
||||
import { load } from 'cheerio';
|
||||
|
|
@ -7,22 +6,7 @@ import { parseDate } from '@/utils/parse-date';
|
|||
|
||||
import { rootUrl, ProcessItems } from './utils';
|
||||
|
||||
export const route: Route = {
|
||||
path: ['/:type/:id', '/'],
|
||||
radar: [
|
||||
{
|
||||
source: ['cnbeta.com.tw/'],
|
||||
target: '',
|
||||
},
|
||||
],
|
||||
name: 'Unknown',
|
||||
maintainers: [],
|
||||
handler,
|
||||
url: 'cnbeta.com.tw/',
|
||||
url: 'cnbeta.com.tw/',
|
||||
};
|
||||
|
||||
async function handler(ctx) {
|
||||
export async function handler(ctx) {
|
||||
const { type, id } = ctx.req.param();
|
||||
|
||||
const currentUrl = type ? `${rootUrl}/${type}/${id}.htm` : rootUrl;
|
||||
|
|
@ -0,0 +1,16 @@
|
|||
import { Route } from '@/types';
|
||||
import { handler } from './common';
|
||||
|
||||
export const route: Route = {
|
||||
name: '头条资讯',
|
||||
path: ['/'],
|
||||
example: '/cnbeta',
|
||||
radar: [
|
||||
{
|
||||
source: ['cnbeta.com.tw/'],
|
||||
},
|
||||
],
|
||||
maintainers: ['kt286', 'HaitianLiu', 'nczitzk'],
|
||||
handler,
|
||||
url: 'cnbeta.com.tw',
|
||||
};
|
||||
|
|
@ -3,4 +3,5 @@ import type { Namespace } from '@/types';
|
|||
export const namespace: Namespace = {
|
||||
name: 'cnBeta.COM',
|
||||
url: 'cnbeta.com.tw',
|
||||
categories: ['new-media'],
|
||||
};
|
||||
|
|
|
|||
|
|
@ -0,0 +1,23 @@
|
|||
import { Route } from '@/types';
|
||||
import { handler } from './common';
|
||||
|
||||
export const route: Route = {
|
||||
name: '主题',
|
||||
path: ['/topics/:id'],
|
||||
example: '/cnbeta/topics/453',
|
||||
maintainers: ['cczhong11', 'nczitzk'],
|
||||
parameters: {
|
||||
id: '主题 id,可在对应主题页的 URL 中找到',
|
||||
},
|
||||
radar: [
|
||||
{
|
||||
source: ['cnbeta.com.tw/topics/:id'],
|
||||
target: (params) => `/cnbeta/topics/${params.id.replace('.htm', '')}`,
|
||||
},
|
||||
],
|
||||
handler,
|
||||
url: 'cnbeta.com.tw',
|
||||
description: `::: tip
|
||||
完整的主题列表参见 [主题列表](https://www.cnbeta.com.tw/topics.htm)
|
||||
:::`,
|
||||
};
|
||||
|
|
@ -29,8 +29,6 @@ export const route: Route = {
|
|||
url: 'www.cnblogs.com/pick',
|
||||
description: `在博客园主页的分类出可查看所有类型。例如,go 的分类地址为: \`https://www.cnblogs.com/cate/go/\`, 则: [\`/cnblogs/cate/go\`](https://rsshub.app/cnblogs/cate/go)`,
|
||||
url: 'www.cnblogs.com/aggsite/headline',
|
||||
url: 'www.cnblogs.com/aggsite/topviews',
|
||||
url: 'www.cnblogs.com/aggsite/topdiggs',
|
||||
};
|
||||
|
||||
async function handler(ctx) {
|
||||
|
|
|
|||
|
|
@ -2,7 +2,7 @@ import { Route } from '@/types';
|
|||
import cache from '@/utils/cache';
|
||||
import got from '@/utils/got';
|
||||
import { load } from 'cheerio';
|
||||
import utils from './utils';
|
||||
import { ProcessItem } from './utils';
|
||||
|
||||
const rootUrl = 'https://kns.cnki.net';
|
||||
|
||||
|
|
@ -70,7 +70,7 @@ async function handler(ctx) {
|
|||
};
|
||||
});
|
||||
|
||||
const items = await Promise.all(list.map((item) => cache.tryGet(item.link, () => utils.ProcessItem(item))));
|
||||
const items = await Promise.all(list.map((item) => cache.tryGet(item.link, () => ProcessItem(item))));
|
||||
|
||||
return {
|
||||
title: `知网 ${authorName} ${companyName}`,
|
||||
|
|
|
|||
|
|
@ -24,4 +24,4 @@ const ProcessItem = async (item) => {
|
|||
return item;
|
||||
};
|
||||
|
||||
export default { ProcessItem };
|
||||
export { ProcessItem };
|
||||
|
|
|
|||
|
|
@ -6,7 +6,7 @@ import cache from '@/utils/cache';
|
|||
import { parseDate } from '@/utils/parse-date';
|
||||
import { art } from '@/utils/render';
|
||||
import path from 'node:path';
|
||||
import { getUuid, getBook, getChapter, getChapters, getImgEncrypted, getImgKey, decrypt, getRealKey, siteHost } from './utils';
|
||||
import { getUuid, getBook, getChapter, getChapters, getImgEncrypted, getImgKey, decrypt, getRealKey, apiHost } from './utils';
|
||||
|
||||
export const route: Route = {
|
||||
path: '/book/:id/:coverOnly?/:quality?',
|
||||
|
|
@ -62,7 +62,7 @@ async function handler(ctx) {
|
|||
const realKey = getRealKey(imgKey);
|
||||
const encrypted = await getImgEncrypted(p.id, quality);
|
||||
|
||||
return cache.tryGet(`${siteHost}/fs/chapter_content/encrypt/${p.id}/${quality}`, () => decrypt(encrypted, realKey));
|
||||
return cache.tryGet(`${apiHost}/fs/chapter_content/encrypt/${p.id}/${quality}`, () => decrypt(encrypted, realKey));
|
||||
})
|
||||
);
|
||||
}
|
||||
|
|
|
|||
|
|
@ -82,4 +82,4 @@ const getRealKey = (imgKey, token = DEFAULT_TOKEN) => {
|
|||
};
|
||||
};
|
||||
|
||||
export { getBook, getChapter, getChapters, getImgEncrypted, getImgKey, getUuid, decrypt, token2Key, getRealKey };
|
||||
export { apiHost, getBook, getChapter, getChapters, getImgEncrypted, getImgKey, getUuid, decrypt, token2Key, getRealKey };
|
||||
|
|
|
|||
|
|
@ -4,18 +4,17 @@ import got from '@/utils/got';
|
|||
import { load } from 'cheerio';
|
||||
|
||||
export const route: Route = {
|
||||
path: ['/all', '/'],
|
||||
name: 'Award Winners',
|
||||
example: '/darwinawards',
|
||||
path: '/',
|
||||
radar: [
|
||||
{
|
||||
source: ['darwinawards.com/darwin', 'darwinawards.com/'],
|
||||
target: '',
|
||||
},
|
||||
],
|
||||
name: 'Unknown',
|
||||
maintainers: ['zoenglinghou', 'nczitzk'],
|
||||
handler,
|
||||
url: 'darwinawards.com/darwin',
|
||||
url: 'darwinawards.com/darwin',
|
||||
};
|
||||
|
||||
async function handler() {
|
||||
|
|
|
|||
|
|
@ -3,4 +3,5 @@ import type { Namespace } from '@/types';
|
|||
export const namespace: Namespace = {
|
||||
name: 'Darwin Awards',
|
||||
url: 'darwinawards.com',
|
||||
categories: ['other'],
|
||||
};
|
||||
|
|
|
|||
|
|
@ -1,105 +0,0 @@
|
|||
import { Route } from '@/types';
|
||||
import cache from '@/utils/cache';
|
||||
import got from '@/utils/got';
|
||||
import { load } from 'cheerio';
|
||||
import { parseDate } from '@/utils/parse-date';
|
||||
import timezone from '@/utils/timezone';
|
||||
import logger from '@/utils/logger';
|
||||
|
||||
export const route: Route = {
|
||||
path: ['/:category', '/topic/:topic'],
|
||||
categories: ['traditional-media'],
|
||||
example: '/dnaindia/headlines',
|
||||
parameters: { category: 'Find it in the URL, or tables below' },
|
||||
features: {
|
||||
requireConfig: false,
|
||||
requirePuppeteer: false,
|
||||
antiCrawler: false,
|
||||
supportBT: false,
|
||||
supportPodcast: false,
|
||||
supportScihub: false,
|
||||
},
|
||||
radar: [
|
||||
{
|
||||
source: ['dnaindia.com/:category'],
|
||||
},
|
||||
],
|
||||
name: 'News',
|
||||
maintainers: ['Rjnishant530'],
|
||||
handler,
|
||||
description: `Topics:
|
||||
|
||||
| DNA verified |
|
||||
| ------------ |
|
||||
| dna-verified |
|
||||
|
||||
:::tip Topic
|
||||
The URL of the form \`https://www.dnaindia.com/topic/dna-verified\` demonstrates the utilization of the subdomain \`topic\`
|
||||
:::`,
|
||||
description: `Categories:
|
||||
|
||||
| Headlines | Explainer | India | Entertainment | Sports | Viral | Lifestyle | Education | Business | World |
|
||||
| --------- | --------- | ----- | ------------- | ------ | ----- | --------- | --------- | -------- | ----- |
|
||||
| headlines | explainer | india | entertainment | sports | viral | lifestyle | education | business | world |`,
|
||||
};
|
||||
|
||||
async function handler(ctx) {
|
||||
const { category, topic } = ctx.req.param();
|
||||
const baseUrl = 'https://www.dnaindia.com';
|
||||
let route;
|
||||
if (category) {
|
||||
route = `/${category}`;
|
||||
} else if (topic) {
|
||||
route = `/topic/${topic}`;
|
||||
} else {
|
||||
logger.error('Invalid URL');
|
||||
}
|
||||
const { data: response } = await got(`${baseUrl}${route}`);
|
||||
const $ = load(response);
|
||||
|
||||
const listItems = $('div.col-lg-6 div.list-news')
|
||||
.toArray()
|
||||
.map((item) => {
|
||||
item = $(item);
|
||||
const a = item.find('div.explainer-subtext a');
|
||||
return {
|
||||
title: a.text(),
|
||||
link: `${baseUrl}${a.attr('href')}`,
|
||||
};
|
||||
});
|
||||
|
||||
const items = await Promise.all(
|
||||
listItems.map((item) =>
|
||||
cache.tryGet(item.link, async () => {
|
||||
const { data: response } = await got(item.link);
|
||||
const $ = load(response);
|
||||
item.itunes_item_image = $('div.article-img img').attr('src');
|
||||
item.category = $('div.tags ul li')
|
||||
.toArray()
|
||||
.map((item) => $(item).find('a').text());
|
||||
const time = $('p.dna-update').text().split('Updated:')[1];
|
||||
item.pubDate = timezone(parseDate(time, 'MMMDD,YYYY,hh:mmA'), +5.5);
|
||||
item.author = 'DNA Web Team';
|
||||
item.description = $('div.article-description')
|
||||
.clone()
|
||||
.children('div')
|
||||
.remove()
|
||||
.end()
|
||||
.toArray()
|
||||
.map((element) => $(element).html())
|
||||
.join('');
|
||||
return item;
|
||||
})
|
||||
)
|
||||
);
|
||||
|
||||
return {
|
||||
title: 'DNA India',
|
||||
link: baseUrl,
|
||||
item: items,
|
||||
description: 'Latest News on dnaIndia.com',
|
||||
logo: 'https://cdn.dnaindia.com/sites/all/themes/dnaindia/favicon-1016.ico',
|
||||
icon: 'https://cdn.dnaindia.com/sites/all/themes/dnaindia/favicon-1016.ico',
|
||||
language: 'en-us',
|
||||
};
|
||||
}
|
||||
|
|
@ -0,0 +1,68 @@
|
|||
import cache from '@/utils/cache';
|
||||
import got from '@/utils/got';
|
||||
import { load } from 'cheerio';
|
||||
import { parseDate } from '@/utils/parse-date';
|
||||
import timezone from '@/utils/timezone';
|
||||
import logger from '@/utils/logger';
|
||||
|
||||
export async function handler(ctx) {
|
||||
const { category, topic } = ctx.req.param();
|
||||
const baseUrl = 'https://www.dnaindia.com';
|
||||
let route;
|
||||
if (category) {
|
||||
route = `/${category}`;
|
||||
} else if (topic) {
|
||||
route = `/topic/${topic}`;
|
||||
} else {
|
||||
logger.error('Invalid URL');
|
||||
}
|
||||
const link = `${baseUrl}${route}`;
|
||||
const { data: response } = await got(link);
|
||||
const $ = load(response);
|
||||
|
||||
const listItems = $('div.col-lg-6 div.list-news')
|
||||
.toArray()
|
||||
.map((item) => {
|
||||
item = $(item);
|
||||
const a = item.find('div.explainer-subtext a');
|
||||
return {
|
||||
title: a.text(),
|
||||
link: `${baseUrl}${a.attr('href')}`,
|
||||
};
|
||||
});
|
||||
|
||||
const items = await Promise.all(
|
||||
listItems.map((item) =>
|
||||
cache.tryGet(item.link, async () => {
|
||||
const { data: response } = await got(item.link);
|
||||
const $ = load(response);
|
||||
item.itunes_item_image = $('div.article-img img').attr('src');
|
||||
item.category = $('div.tags ul li')
|
||||
.toArray()
|
||||
.map((item) => $(item).find('a').text());
|
||||
const time = $('p.dna-update').text().split('Updated:')[1];
|
||||
item.pubDate = timezone(parseDate(time, 'MMMDD,YYYY,hh:mmA'), +5.5);
|
||||
item.author = 'DNA Web Team';
|
||||
item.description = $('div.article-description')
|
||||
.clone()
|
||||
.children('div')
|
||||
.remove()
|
||||
.end()
|
||||
.toArray()
|
||||
.map((element) => $(element).html())
|
||||
.join('');
|
||||
return item;
|
||||
})
|
||||
)
|
||||
);
|
||||
|
||||
return {
|
||||
title: 'DNA India',
|
||||
link,
|
||||
item: items,
|
||||
description: 'Latest News on dnaIndia.com',
|
||||
logo: 'https://cdn.dnaindia.com/sites/all/themes/dnaindia/favicon-1016.ico',
|
||||
icon: 'https://cdn.dnaindia.com/sites/all/themes/dnaindia/favicon-1016.ico',
|
||||
language: 'en-us',
|
||||
};
|
||||
}
|
||||
|
|
@ -3,4 +3,5 @@ import type { Namespace } from '@/types';
|
|||
export const namespace: Namespace = {
|
||||
name: 'DNA India',
|
||||
url: 'dnaindia.com',
|
||||
categories: ['traditional-media'],
|
||||
};
|
||||
|
|
|
|||
|
|
@ -0,0 +1,24 @@
|
|||
import { Route } from '@/types';
|
||||
import { handler } from './common';
|
||||
|
||||
export const route: Route = {
|
||||
name: 'News',
|
||||
maintainers: ['Rjnishant530'],
|
||||
path: ['/:category'],
|
||||
example: '/dnaindia/headlines',
|
||||
parameters: {
|
||||
category: 'Find it in the URL, or tables below',
|
||||
},
|
||||
radar: [
|
||||
{
|
||||
source: ['www.dnaindia.com/:category'],
|
||||
},
|
||||
],
|
||||
handler,
|
||||
url: 'www.dnaindia.com',
|
||||
description: `Categories:
|
||||
|
||||
| Headlines | Explainer | India | Entertainment | Sports | Viral | Lifestyle | Education | Business | World |
|
||||
| --------- | --------- | ----- | ------------- | ------ | ----- | --------- | --------- | -------- | ----- |
|
||||
| headlines | explainer | india | entertainment | sports | viral | lifestyle | education | business | world |`,
|
||||
};
|
||||
|
|
@ -0,0 +1,28 @@
|
|||
import { Route } from '@/types';
|
||||
import { handler } from './common';
|
||||
|
||||
export const route: Route = {
|
||||
name: 'Topic',
|
||||
maintainers: ['Rjnishant530'],
|
||||
path: ['/topic/:topic'],
|
||||
example: '/dnaindia/topic/dna-verified',
|
||||
parameters: {
|
||||
category: 'Find it in the URL',
|
||||
},
|
||||
radar: [
|
||||
{
|
||||
source: ['www.dnaindia.com/topic/:topic'],
|
||||
},
|
||||
],
|
||||
handler,
|
||||
url: 'www.dnaindia.com',
|
||||
description: `Topics:
|
||||
|
||||
| DNA verified |
|
||||
| ------------ |
|
||||
| dna-verified |
|
||||
|
||||
:::tip
|
||||
The URL of the form \`https://www.dnaindia.com/topic/dna-verified\` demonstrates the utilization of the subdomain \`topic\`.
|
||||
:::`,
|
||||
};
|
||||
|
|
@ -42,7 +42,6 @@ export const route: Route = {
|
|||
maintainers: ['nczitzk'],
|
||||
handler,
|
||||
url: 'farmatters.com/news',
|
||||
url: 'farmatters.com/exclusive',
|
||||
};
|
||||
|
||||
async function handler(ctx) {
|
||||
|
|
|
|||
|
|
@ -3,4 +3,5 @@ import type { Namespace } from '@/types';
|
|||
export const namespace: Namespace = {
|
||||
name: 'Farmatters',
|
||||
url: 'farmatters.com',
|
||||
categories: ['new-media'],
|
||||
};
|
||||
|
|
|
|||
|
|
@ -11,15 +11,6 @@ export const route: Route = {
|
|||
path: '/events',
|
||||
categories: ['new-media'],
|
||||
example: '/houxu/events',
|
||||
parameters: {},
|
||||
features: {
|
||||
requireConfig: false,
|
||||
requirePuppeteer: false,
|
||||
antiCrawler: false,
|
||||
supportBT: false,
|
||||
supportPodcast: false,
|
||||
supportScihub: false,
|
||||
},
|
||||
radar: [
|
||||
{
|
||||
source: ['houxu.app/events', 'houxu.app/'],
|
||||
|
|
|
|||
|
|
@ -8,19 +8,17 @@ import { art } from '@/utils/render';
|
|||
import path from 'node:path';
|
||||
|
||||
export const route: Route = {
|
||||
path: ['/featured', '/index', '/'],
|
||||
name: '热点',
|
||||
maintainers: ['nczitzk'],
|
||||
example: '/houxu',
|
||||
path: '/',
|
||||
radar: [
|
||||
{
|
||||
source: ['houxu.app/'],
|
||||
target: '',
|
||||
},
|
||||
],
|
||||
name: 'Unknown',
|
||||
maintainers: [],
|
||||
handler,
|
||||
url: 'houxu.app/',
|
||||
url: 'houxu.app/',
|
||||
url: 'houxu.app/',
|
||||
};
|
||||
|
||||
async function handler(ctx) {
|
||||
|
|
|
|||
|
|
@ -11,15 +11,6 @@ export const route: Route = {
|
|||
path: '/memory',
|
||||
categories: ['new-media'],
|
||||
example: '/houxu/memory',
|
||||
parameters: {},
|
||||
features: {
|
||||
requireConfig: false,
|
||||
requirePuppeteer: false,
|
||||
antiCrawler: false,
|
||||
supportBT: false,
|
||||
supportPodcast: false,
|
||||
supportScihub: false,
|
||||
},
|
||||
radar: [
|
||||
{
|
||||
source: ['houxu.app/memory', 'houxu.app/'],
|
||||
|
|
|
|||
|
|
@ -30,7 +30,6 @@ export const route: Route = {
|
|||
| 全部 | 可下载 | 含字幕 | 含短評 |
|
||||
| ---- | ------ | ------ | ------ |
|
||||
| 0 | 1 | 2 | 3 |`,
|
||||
url: 'javdb.com/',
|
||||
};
|
||||
|
||||
async function handler(ctx) {
|
||||
|
|
|
|||
|
|
@ -21,9 +21,7 @@ export const route: Route = {
|
|||
maintainers: ['nczitzk'],
|
||||
handler,
|
||||
url: 'logonews.cn/',
|
||||
url: 'logonews.cn/',
|
||||
description: `如 [中国 - 标志情报局](https://www.logonews.cn/tag/china) 的 URL 为 \`https://www.logonews.cn/tag/china\`,可得路由为 [\`/logonews/tag/china\`](https://rsshub.app/logonews/tag/china)。`,
|
||||
url: 'logonews.cn/work',
|
||||
};
|
||||
|
||||
async function handler(ctx) {
|
||||
|
|
|
|||
|
|
@ -0,0 +1,19 @@
|
|||
import { Route } from '@/types';
|
||||
import { handler } from './common';
|
||||
|
||||
export const route: Route = {
|
||||
name: 'All Papers',
|
||||
maintainers: ['5upernova-heng'],
|
||||
path: '/papers',
|
||||
example: '/nber/papers',
|
||||
features: {
|
||||
supportScihub: true,
|
||||
},
|
||||
radar: [
|
||||
{
|
||||
source: ['nber.org/papers'],
|
||||
},
|
||||
],
|
||||
handler,
|
||||
url: 'nber.org/papers',
|
||||
};
|
||||
|
|
@ -1,10 +1,9 @@
|
|||
import { Route } from '@/types';
|
||||
import { getCurrentPath } from '@/utils/helpers';
|
||||
const __dirname = getCurrentPath(import.meta.url);
|
||||
|
||||
import { getSubPath } from '@/utils/common-utils';
|
||||
import cache from '@/utils/cache';
|
||||
import got from '@/utils/got';
|
||||
import ofetch from '@/utils/ofetch';
|
||||
import { load } from 'cheerio';
|
||||
import path from 'node:path';
|
||||
import { art } from '@/utils/render';
|
||||
|
|
@ -12,37 +11,10 @@ import { parseDate } from '@/utils/parse-date';
|
|||
import { config } from '@/config';
|
||||
|
||||
async function getData(url) {
|
||||
const response = await got(url).json();
|
||||
const response = await ofetch(url);
|
||||
return response.results;
|
||||
}
|
||||
|
||||
export const route: Route = {
|
||||
path: ['/papers', '/news'],
|
||||
categories: ['journal'],
|
||||
example: '/nber/papers',
|
||||
parameters: {},
|
||||
features: {
|
||||
requireConfig: false,
|
||||
requirePuppeteer: false,
|
||||
antiCrawler: false,
|
||||
supportBT: false,
|
||||
supportPodcast: false,
|
||||
supportScihub: true,
|
||||
},
|
||||
radar: [
|
||||
{
|
||||
source: ['nber.org/papers'],
|
||||
},
|
||||
],
|
||||
name: 'All Papers',
|
||||
maintainers: [],
|
||||
handler,
|
||||
url: 'nber.org/papers',
|
||||
description: `Papers that are published in this week.`,
|
||||
url: 'nber.org/papers',
|
||||
};
|
||||
|
||||
async function handler(ctx) {
|
||||
export async function handler(ctx) {
|
||||
const url = 'https://www.nber.org/api/v1/working_page_listing/contentType/working_paper/_/_/search';
|
||||
const baseUrl = 'https://www.nber.org';
|
||||
const data = await cache.tryGet(url, () => getData(url), config.cache.routeExpire, false);
|
||||
|
|
@ -52,8 +24,8 @@ async function handler(ctx) {
|
|||
.map((article) => {
|
||||
const link = `${baseUrl}${article.url}`;
|
||||
return cache.tryGet(link, async () => {
|
||||
const response = await got(link);
|
||||
const $ = load(response.data);
|
||||
const response = await ofetch(link);
|
||||
const $ = load(response);
|
||||
const downloadLink = $('meta[name="citation_pdf_url"]').attr('content');
|
||||
const fullAbstract = $('.page-header__intro-inner').html();
|
||||
return {
|
||||
|
|
@ -76,6 +48,5 @@ async function handler(ctx) {
|
|||
link: 'https://www.nber.org/papers',
|
||||
item: items,
|
||||
description: `National Bureau of Economic Research Working Papers articles`,
|
||||
language: $('html').attr('lang'),
|
||||
};
|
||||
}
|
||||
|
|
@ -3,4 +3,5 @@ import type { Namespace } from '@/types';
|
|||
export const namespace: Namespace = {
|
||||
name: 'National Bureau of Economic Research',
|
||||
url: 'nber.org',
|
||||
categories: ['journal'],
|
||||
};
|
||||
|
|
|
|||
|
|
@ -0,0 +1,20 @@
|
|||
import { Route } from '@/types';
|
||||
import { handler } from './common';
|
||||
|
||||
export const route: Route = {
|
||||
name: 'New Papers',
|
||||
maintainers: ['5upernova-heng'],
|
||||
path: '/new',
|
||||
example: '/nber/new',
|
||||
features: {
|
||||
supportScihub: true,
|
||||
},
|
||||
radar: [
|
||||
{
|
||||
source: ['nber.org/papers'],
|
||||
},
|
||||
],
|
||||
handler,
|
||||
url: 'nber.org/papers',
|
||||
description: 'Papers that are published in this week.',
|
||||
};
|
||||
|
|
@ -3,18 +3,9 @@ import got from '@/utils/got';
|
|||
import { parseDate } from '@/utils/parse-date';
|
||||
|
||||
export const route: Route = {
|
||||
path: ['/news', '/newsflash'],
|
||||
path: '/news',
|
||||
categories: ['new-media'],
|
||||
example: '/panewslab/news',
|
||||
parameters: {},
|
||||
features: {
|
||||
requireConfig: false,
|
||||
requirePuppeteer: false,
|
||||
antiCrawler: false,
|
||||
supportBT: false,
|
||||
supportPodcast: false,
|
||||
supportScihub: false,
|
||||
},
|
||||
radar: [
|
||||
{
|
||||
source: ['panewslab.com/'],
|
||||
|
|
@ -24,7 +15,6 @@ export const route: Route = {
|
|||
maintainers: ['nczitzk'],
|
||||
handler,
|
||||
url: 'panewslab.com/',
|
||||
url: 'panewslab.com/',
|
||||
};
|
||||
|
||||
async function handler(ctx) {
|
||||
|
|
|
|||
|
|
@ -20,21 +20,13 @@ const categories = {
|
|||
};
|
||||
|
||||
export const route: Route = {
|
||||
path: '/:category?',
|
||||
path: '/profundity/:category?',
|
||||
categories: ['new-media'],
|
||||
example: '/panewslab',
|
||||
example: '/panewslab/profundity',
|
||||
parameters: { category: '分类,见下表,默认为精选' },
|
||||
features: {
|
||||
requireConfig: false,
|
||||
requirePuppeteer: false,
|
||||
antiCrawler: false,
|
||||
supportBT: false,
|
||||
supportPodcast: false,
|
||||
supportScihub: false,
|
||||
},
|
||||
radar: [
|
||||
{
|
||||
source: ['panewslab.com/'],
|
||||
source: ['panewslab.com/', 'www.panewslab.com/zh/profundity/index.html'],
|
||||
},
|
||||
],
|
||||
name: '深度',
|
||||
|
|
@ -104,6 +104,29 @@ const fetchIntlItems = async (params) => {
|
|||
});
|
||||
};
|
||||
|
||||
async function handler(ctx) {
|
||||
const is_intl = ctx.req.url.indexOf('/intl/') === 0;
|
||||
const id = ctx.req.param('id');
|
||||
const order = ctx.req.param('order') ?? 'default';
|
||||
const lang = ctx.req.param('lang') ?? (is_intl ? 'en_US' : 'zh_CN');
|
||||
|
||||
const app_detail = await appDetail(id, lang, is_intl);
|
||||
const app_img = app_detail.app.icon.original_url;
|
||||
const app_name = app_detail.app.title;
|
||||
|
||||
const items = is_intl ? await fetchIntlItems(ctx.params) : await fetchMainlandItems(ctx.params);
|
||||
|
||||
const ret = {
|
||||
title: `TapTap 评价 ${app_name} - ${(is_intl ? intlSortMap : sortMap)[order][lang]}排序`,
|
||||
link: `${getRootUrl(is_intl)}/app/${id}/review?${makeSortParam(is_intl, order)}`,
|
||||
image: app_img,
|
||||
item: items,
|
||||
};
|
||||
|
||||
ctx.set('json', ret);
|
||||
return ret;
|
||||
}
|
||||
|
||||
export const route: Route = {
|
||||
path: ['/review/:id/:order?/:lang?', '/intl/review/:id/:order?/:lang?'],
|
||||
categories: ['game'],
|
||||
|
|
@ -141,26 +164,3 @@ export const route: Route = {
|
|||
| ------ | ---- | -------- | -------- |
|
||||
| update | hot | spent | default |`,
|
||||
};
|
||||
|
||||
async function handler(ctx) {
|
||||
const is_intl = ctx.req.url.indexOf('/intl/') === 0;
|
||||
const id = ctx.req.param('id');
|
||||
const order = ctx.req.param('order') ?? 'default';
|
||||
const lang = ctx.req.param('lang') ?? (is_intl ? 'en_US' : 'zh_CN');
|
||||
|
||||
const app_detail = await appDetail(id, lang, is_intl);
|
||||
const app_img = app_detail.app.icon.original_url;
|
||||
const app_name = app_detail.app.title;
|
||||
|
||||
const items = is_intl ? await fetchIntlItems(ctx.params) : await fetchMainlandItems(ctx.params);
|
||||
|
||||
const ret = {
|
||||
title: `TapTap 评价 ${app_name} - ${(is_intl ? intlSortMap : sortMap)[order][lang]}排序`,
|
||||
link: `${getRootUrl(is_intl)}/app/${id}/review?${makeSortParam(is_intl, order)}`,
|
||||
image: app_img,
|
||||
item: items,
|
||||
};
|
||||
|
||||
ctx.set('json', ret);
|
||||
return ret;
|
||||
}
|
||||
|
|
|
|||
|
|
@ -5,18 +5,9 @@ import { parseDate } from '@/utils/parse-date';
|
|||
import dayjs from 'dayjs';
|
||||
|
||||
export const route: Route = {
|
||||
path: ['/express', '/newsflash'],
|
||||
path: '/express',
|
||||
categories: ['finance'],
|
||||
example: '/techflowpost/express',
|
||||
parameters: {},
|
||||
features: {
|
||||
requireConfig: false,
|
||||
requirePuppeteer: false,
|
||||
antiCrawler: false,
|
||||
supportBT: false,
|
||||
supportPodcast: false,
|
||||
supportScihub: false,
|
||||
},
|
||||
radar: [
|
||||
{
|
||||
source: ['techflowpost.com/newsletter/index.html'],
|
||||
|
|
@ -26,7 +17,6 @@ export const route: Route = {
|
|||
maintainers: ['nczitzk'],
|
||||
handler,
|
||||
url: 'techflowpost.com/',
|
||||
url: 'techflowpost.com/newsletter/index.html',
|
||||
};
|
||||
|
||||
async function handler(ctx) {
|
||||
|
|
|
|||
|
|
@ -5,13 +5,13 @@ import { parseDate } from '@/utils/parse-date';
|
|||
|
||||
export const route: Route = {
|
||||
path: '/',
|
||||
example: '/techflowpost',
|
||||
radar: [
|
||||
{
|
||||
source: ['techflowpost.com/'],
|
||||
target: '',
|
||||
},
|
||||
],
|
||||
name: 'Unknown',
|
||||
name: '首页',
|
||||
maintainers: ['nczitzk'],
|
||||
handler,
|
||||
url: 'techflowpost.com/',
|
||||
|
|
|
|||
|
|
@ -0,0 +1,38 @@
|
|||
import cache from '@/utils/cache';
|
||||
import got from '@/utils/got';
|
||||
import { load } from 'cheerio';
|
||||
import { baseUrl, parseList, parseItems } from './utils';
|
||||
import { getSubPath } from '@/utils/common-utils';
|
||||
|
||||
export async function handler(ctx) {
|
||||
const requestPath = getSubPath(ctx);
|
||||
const isTopic = requestPath.startsWith('/topic/');
|
||||
let link = baseUrl;
|
||||
|
||||
if (isTopic) {
|
||||
link += `/topic/${ctx.req.param('id')}`;
|
||||
} else if (requestPath === '/') {
|
||||
link += `/articles/report`;
|
||||
} else {
|
||||
link += `/articles${requestPath}`;
|
||||
}
|
||||
|
||||
const { data: response } = await got(link);
|
||||
const $ = load(response);
|
||||
|
||||
const list = $(`${isTopic ? '.view-grouping' : '.pane-clone-of-article'} .views-row-inner`)
|
||||
.toArray()
|
||||
.map((item) => parseList($(item)));
|
||||
|
||||
const items = await parseItems(list, cache.tryGet);
|
||||
|
||||
return {
|
||||
title: $('head title').text(),
|
||||
description: $('head meta[name="description"]').attr('content'),
|
||||
image: $('head meta[property="og:image"]').attr('content'),
|
||||
logo: $('head link[rel="shortcut icon"]').attr('href'),
|
||||
icon: $('head link[rel="shortcut icon"]').attr('href'),
|
||||
link,
|
||||
item: items,
|
||||
};
|
||||
}
|
||||
|
|
@ -1,47 +1,17 @@
|
|||
import { Route } from '@/types';
|
||||
import cache from '@/utils/cache';
|
||||
import got from '@/utils/got';
|
||||
import { load } from 'cheerio';
|
||||
import { baseUrl, parseList, parseItems } from './utils';
|
||||
import { handler } from './common';
|
||||
|
||||
export const route: Route = {
|
||||
path: ['/', '/category/:id{.+}', '/info', '/report', '/topic/:id'],
|
||||
name: 'Unknown',
|
||||
name: '最新相關資訊 / 最新查核報告',
|
||||
maintainers: ['TonyRL'],
|
||||
example: '/tfc-taiwan',
|
||||
path: '/:type?',
|
||||
parameters: {
|
||||
type: '分類,見下表,預設為 `report`',
|
||||
},
|
||||
handler,
|
||||
url: 'tfc-taiwan.org.tw/articles/report',
|
||||
url: 'tfc-taiwan.org.tw/articles/info',
|
||||
description: `| 最新相關資訊 | 最新查核報告 |
|
||||
| ------------ | ------------ |
|
||||
| info | report |`,
|
||||
};
|
||||
|
||||
async function handler(ctx) {
|
||||
const requestPath = ctx.req.path;
|
||||
const isTopic = requestPath.startsWith('/topic/');
|
||||
let link = baseUrl;
|
||||
|
||||
if (isTopic) {
|
||||
link += `/topic/${ctx.req.param('id')}`;
|
||||
} else if (requestPath === '/') {
|
||||
link += `/articles/report`;
|
||||
} else {
|
||||
link += `/articles${requestPath}`;
|
||||
}
|
||||
|
||||
const { data: response } = await got(link);
|
||||
const $ = load(response);
|
||||
|
||||
const list = $(`${isTopic ? '.view-grouping' : '.pane-clone-of-article'} .views-row-inner`)
|
||||
.toArray()
|
||||
.map((item) => parseList($(item)));
|
||||
|
||||
const items = await parseItems(list, cache.tryGet);
|
||||
|
||||
return {
|
||||
title: $('head title').text(),
|
||||
description: $('head meta[name="description"]').attr('content'),
|
||||
image: $('head meta[property="og:image"]').attr('content'),
|
||||
logo: $('head link[rel="shortcut icon"]').attr('href'),
|
||||
icon: $('head link[rel="shortcut icon"]').attr('href'),
|
||||
link,
|
||||
item: items,
|
||||
};
|
||||
}
|
||||
|
|
|
|||
|
|
@ -0,0 +1,17 @@
|
|||
import { Route } from '@/types';
|
||||
import { handler } from './common';
|
||||
|
||||
export const route: Route = {
|
||||
name: '專題 / 重點專區',
|
||||
maintainers: ['TonyRL'],
|
||||
example: '/tfc-taiwan/category/242',
|
||||
path: '/:type/:id{.+}',
|
||||
parameters: {
|
||||
type: '分類,見下表,預設為 `report`',
|
||||
},
|
||||
handler,
|
||||
url: 'tfc-taiwan.org.tw/articles/report',
|
||||
description: `| 專題 | 重點專區 |
|
||||
| -------- | -------- |
|
||||
| category | topic |`,
|
||||
};
|
||||
|
|
@ -1,5 +1,5 @@
|
|||
import { Route } from '@/types';
|
||||
import got from '@/utils/got';
|
||||
import ofetch from '@/utils/ofetch';
|
||||
import { parseDate } from '@/utils/parse-date';
|
||||
|
||||
export const route: Route = {
|
||||
|
|
@ -30,14 +30,9 @@ async function handler(ctx) {
|
|||
const rootUrl = 'https://trendingpapers.com';
|
||||
const currentUrl = `${rootUrl}/api/papers?p=1&o=pagerank_growth&pd=${time}&cc=${cited}&c=${category}`;
|
||||
|
||||
const response = await got({
|
||||
method: 'get',
|
||||
url: currentUrl,
|
||||
});
|
||||
const response = await ofetch(currentUrl);
|
||||
|
||||
const $ = response.data;
|
||||
|
||||
const papers = $.data.map((_) => {
|
||||
const papers = response.data.map((_) => {
|
||||
const title = _.title;
|
||||
const abstract = _.abstract;
|
||||
const url = _.url;
|
||||
|
|
@ -60,6 +55,5 @@ async function handler(ctx) {
|
|||
title: `Trending Papers on arXiv.org | ${category} | ${time} | ${cited} | `,
|
||||
link: currentUrl,
|
||||
item: papers,
|
||||
language: $('html').attr('lang'),
|
||||
};
|
||||
}
|
||||
|
|
|
|||
|
|
@ -0,0 +1,17 @@
|
|||
import { Route } from '@/types';
|
||||
import { handler } from './common';
|
||||
|
||||
export const route: Route = {
|
||||
name: '分类更新',
|
||||
maintainers: ['Gandum2077'],
|
||||
path: '/category/:cid',
|
||||
example: '/wnacg/category/6',
|
||||
radar: [
|
||||
{
|
||||
source: ['wnacg.com/*'],
|
||||
target: (_, url) => `/wnacg/category/${new URL(url).pathname.match(/albums-index-cate-(\d+)\.html$/)[1]}`,
|
||||
},
|
||||
],
|
||||
handler,
|
||||
url: 'wnacg.com/albums.html',
|
||||
};
|
||||
|
|
@ -0,0 +1,111 @@
|
|||
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';
|
||||
import InvalidParameterError from '@/errors/types/invalid-parameter';
|
||||
|
||||
const categories = {
|
||||
1: '同人誌 漢化',
|
||||
2: '同人誌 CG畫集',
|
||||
3: '同人誌 Cosplay',
|
||||
5: '同人誌',
|
||||
6: '單行本',
|
||||
7: '雜誌&短篇',
|
||||
9: '單行本 漢化',
|
||||
10: '雜誌&短篇 漢化',
|
||||
12: '同人誌 日語',
|
||||
13: '單行本 日語',
|
||||
14: '雜誌&短篇 日語',
|
||||
16: '同人誌 English',
|
||||
17: '單行本 English',
|
||||
18: '雜誌&短篇 English',
|
||||
19: '韓漫',
|
||||
20: '韓漫 漢化',
|
||||
21: '韓漫 生肉',
|
||||
22: '同人誌 3D漫畫',
|
||||
};
|
||||
|
||||
const baseUrl = 'https://www.wnacg.com';
|
||||
|
||||
export async function handler(ctx) {
|
||||
const { cid, tag } = ctx.req.param();
|
||||
if (cid && !Object.keys(categories).includes(cid)) {
|
||||
throw new InvalidParameterError('此分类不存在');
|
||||
}
|
||||
|
||||
const url = `${baseUrl}/albums${cid ? `-index-cate-${cid}` : ''}${tag ? `-index-tag-${tag}` : ''}.html`;
|
||||
const { data } = await got(url);
|
||||
const $ = load(data);
|
||||
|
||||
const list = $('.gallary_item')
|
||||
.toArray()
|
||||
.map((item) => {
|
||||
item = $(item);
|
||||
const href = item.find('a').attr('href');
|
||||
const aid = href.match(/^\/photos-index-aid-(\d+)\.html$/)[1];
|
||||
return {
|
||||
title: item.find('a').attr('title'),
|
||||
link: `${baseUrl}${href}`,
|
||||
pubDate: parseDate(
|
||||
item
|
||||
.find('.info_col')
|
||||
.text()
|
||||
.replace(/\d+張照片,\n創建於/, ''),
|
||||
'YYYY-MM-DD'
|
||||
),
|
||||
aid,
|
||||
};
|
||||
});
|
||||
|
||||
const items = await Promise.all(
|
||||
list.map((item) =>
|
||||
cache.tryGet(item.link, async () => {
|
||||
const { data: descRes } = await got(item.link, {
|
||||
headers: {
|
||||
referer: encodeURI(url),
|
||||
},
|
||||
});
|
||||
let $ = load(descRes);
|
||||
const author = $('.uwuinfo p').first().text();
|
||||
const category = $('.tagshow')
|
||||
.toArray()
|
||||
.map((item) => $(item).text());
|
||||
$('.addtags').remove();
|
||||
const description = $('.uwconn').html();
|
||||
|
||||
const { data } = await got(`${baseUrl}/photos-gallery-aid-${item.aid}.html`, {
|
||||
headers: {
|
||||
referer: `${baseUrl}/photos-slide-aid-${item.aid}.html`,
|
||||
},
|
||||
});
|
||||
$ = load(data);
|
||||
|
||||
const imgListMatch = $('script')
|
||||
.text()
|
||||
.match(/var imglist = (\[.*]);"\);/)[1];
|
||||
|
||||
const imgList = JSON.parse(imgListMatch.replaceAll('url:', '"url":').replaceAll('caption:', '"caption":').replaceAll('fast_img_host+\\', '').replaceAll('\\', ''));
|
||||
|
||||
item.author = author;
|
||||
item.category = category;
|
||||
item.description = art(path.join(__dirname, 'templates/manga.art'), {
|
||||
description,
|
||||
imgList,
|
||||
});
|
||||
|
||||
return item;
|
||||
})
|
||||
)
|
||||
);
|
||||
|
||||
return {
|
||||
title: $('head title').text(),
|
||||
link: url,
|
||||
item: items,
|
||||
};
|
||||
}
|
||||
|
|
@ -1,126 +1,16 @@
|
|||
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';
|
||||
import InvalidParameterError from '@/errors/types/invalid-parameter';
|
||||
|
||||
const categories = {
|
||||
1: '同人誌 漢化',
|
||||
2: '同人誌 CG畫集',
|
||||
3: '同人誌 Cosplay',
|
||||
5: '同人誌',
|
||||
6: '單行本',
|
||||
7: '雜誌&短篇',
|
||||
9: '單行本 漢化',
|
||||
10: '雜誌&短篇 漢化',
|
||||
12: '同人誌 日語',
|
||||
13: '單行本 日語',
|
||||
14: '雜誌&短篇 日語',
|
||||
16: '同人誌 English',
|
||||
17: '單行本 English',
|
||||
19: '韓漫',
|
||||
20: '韓漫 漢化',
|
||||
21: '韓漫 生肉',
|
||||
};
|
||||
|
||||
const baseUrl = 'https://www.wnacg.com';
|
||||
import { handler } from './common';
|
||||
|
||||
export const route: Route = {
|
||||
path: ['/', '/category/:cid', '/tag/:tag'],
|
||||
name: '最新',
|
||||
maintainers: ['KenMizz'],
|
||||
path: '/',
|
||||
example: '/wnacg',
|
||||
radar: [
|
||||
{
|
||||
source: ['wnacg.org/albums.html', 'wnacg.org/'],
|
||||
target: '',
|
||||
source: ['wnacg.com/albums.html', 'wnacg.com/'],
|
||||
},
|
||||
],
|
||||
name: 'Unknown',
|
||||
maintainers: ['KenMizz'],
|
||||
handler,
|
||||
url: 'wnacg.org/albums.html',
|
||||
url: 'wnacg.org/albums.html',
|
||||
url: 'wnacg.org/albums.html',
|
||||
url: 'wnacg.com/albums.html',
|
||||
};
|
||||
|
||||
async function handler(ctx) {
|
||||
const { cid, tag } = ctx.req.param();
|
||||
if (cid && !Object.keys(categories).includes(cid)) {
|
||||
throw new InvalidParameterError('此分类不存在');
|
||||
}
|
||||
|
||||
const url = `${baseUrl}/albums${cid ? `-index-cate-${cid}` : ''}${tag ? `-index-tag-${tag}` : ''}.html`;
|
||||
const { data } = await got(url);
|
||||
const $ = load(data);
|
||||
|
||||
const list = $('.gallary_item')
|
||||
.toArray()
|
||||
.map((item) => {
|
||||
item = $(item);
|
||||
const href = item.find('a').attr('href');
|
||||
const aid = href.match(/^\/photos-index-aid-(\d+)\.html$/)[1];
|
||||
return {
|
||||
title: item.find('a').attr('title'),
|
||||
link: `${baseUrl}${href}`,
|
||||
pubDate: parseDate(
|
||||
item
|
||||
.find('.info_col')
|
||||
.text()
|
||||
.replace(/\d+張照片,\n創建於/, ''),
|
||||
'YYYY-MM-DD'
|
||||
),
|
||||
aid,
|
||||
};
|
||||
});
|
||||
|
||||
const items = await Promise.all(
|
||||
list.map((item) =>
|
||||
cache.tryGet(item.link, async () => {
|
||||
const { data: descRes } = await got(item.link, {
|
||||
headers: {
|
||||
referer: encodeURI(url),
|
||||
},
|
||||
});
|
||||
let $ = load(descRes);
|
||||
const author = $('.uwuinfo p').first().text();
|
||||
const category = $('.tagshow')
|
||||
.toArray()
|
||||
.map((item) => $(item).text());
|
||||
$('.addtags').remove();
|
||||
const description = $('.uwconn').html();
|
||||
|
||||
const { data } = await got(`${baseUrl}/photos-gallery-aid-${item.aid}.html`, {
|
||||
headers: {
|
||||
referer: `${baseUrl}/photos-slide-aid-${item.aid}.html`,
|
||||
},
|
||||
});
|
||||
$ = load(data);
|
||||
|
||||
const imgListMatch = $('script')
|
||||
.text()
|
||||
.match(/var imglist = (\[.*]);"\);/)[1];
|
||||
|
||||
const imgList = JSON.parse(imgListMatch.replaceAll('url:', '"url":').replaceAll('caption:', '"caption":').replaceAll('fast_img_host+\\', '').replaceAll('\\', ''));
|
||||
|
||||
item.author = author;
|
||||
item.category = category;
|
||||
item.description = art(path.join(__dirname, 'templates/manga.art'), {
|
||||
description,
|
||||
imgList,
|
||||
});
|
||||
|
||||
return item;
|
||||
})
|
||||
)
|
||||
);
|
||||
|
||||
return {
|
||||
title: $('head title').text(),
|
||||
link: url,
|
||||
item: items,
|
||||
};
|
||||
}
|
||||
|
|
|
|||
|
|
@ -0,0 +1,17 @@
|
|||
import { Route } from '@/types';
|
||||
import { handler } from './common';
|
||||
|
||||
export const route: Route = {
|
||||
name: '標籤更新',
|
||||
maintainers: ['Gandum2077'],
|
||||
path: '/tag/:tag',
|
||||
example: '/wnacg/tag/漢化',
|
||||
radar: [
|
||||
{
|
||||
source: ['wnacg.com/*'],
|
||||
target: (_, url) => `/wnacg/tag/${new URL(url).pathname.match(/albums-index-tag-(.+?)\.html$/)[1]}`,
|
||||
},
|
||||
],
|
||||
handler,
|
||||
url: 'wnacg.com/albums.html',
|
||||
};
|
||||
Loading…
Reference in New Issue