Skip to content

Commit

Permalink
feat(route): add asianfanfics route
Browse files Browse the repository at this point in the history
  • Loading branch information
KazooTTT committed Feb 21, 2025
1 parent a4aa62a commit 322e0d5
Show file tree
Hide file tree
Showing 3 changed files with 208 additions and 0 deletions.
7 changes: 7 additions & 0 deletions lib/routes/asianfanfics/namespace.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
import type { Namespace } from '@/types';

export const namespace: Namespace = {
name: 'Asianfanfics 亚洲同人网',
url: 'asianfanfics.com',
lang: 'zh-CN',
};
112 changes: 112 additions & 0 deletions lib/routes/asianfanfics/tag.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,112 @@
import { DataItem, Route } from '@/types';
import logger from '@/utils/logger';
import { parseDate } from '@/utils/parse-date';
import puppeteer from '@/utils/puppeteer';
import { load } from 'cheerio';

// test url http://localhost:1200/asianfanfics/tag/milklove/N

export const route: Route = {
path: '/tag/:tag/:type',
categories: ['reading'],
example: '/tag/milklove/N',
parameters: {
tag: '标签',
type: '排序类型',
},
name: '亚洲同人网标签',
maintainers: ['KazooTTT'],
radar: [
{
source: ['www.asianfanfics.com/browse/tag/:tag/:type'],
target: '/tag/:tag/:type',
},
],
description: `匹配亚洲同人网标签,支持类型:
- L: Latest 最近更新
- N: Newest 最近发布
- O: Oldest 最早发布
- C: Completed 已完成
- OS: One Shots 短篇
`,
handler,
features: {
requirePuppeteer: true,
},
};

type Type = 'L' | 'N' | 'O' | 'C' | 'OS';

const typeToText = {
L: '最近更新',
N: '最近发布',
O: '最早发布',
C: '已完成',
OS: '短篇',
};

async function handler(ctx) {
const tag = ctx.req.param('tag');
let type = ctx.req.param('type') as Type;
if (!type || !['L', 'N', 'O', 'C', 'OS'].includes(type)) {
type = 'L';
}
const link = `https://www.asianfanfics.com/browse/tag/${tag}/${type}`;

// require puppeteer utility class and initialise a browser instance
const browser = await puppeteer();
// open a new tab
const page = await browser.newPage();
// intercept all requests
await page.setRequestInterception(true);
// only allow certain types of requests to proceed
page.on('request', (request) => {
// in this case, we only allow document requests to proceed
request.resourceType() === 'document' ? request.continue() : request.abort();
});
// ofetch requests will be logged automatically
// but puppeteer requests are not
// so we need to log them manually
logger.http(`Requesting ${link}`);

await page.goto(link, {
// specify how long to wait for the page to load
waitUntil: 'domcontentloaded',
});
// retrieve the HTML content of the page
const response = await page.content();
// close the tab
page.close();

const $ = load(response);

const items: DataItem[] = $('.primary-container .excerpt')
.toArray()
.filter((element) => {
const $element = $(element);
return $element.find('.excerpt__title a').length > 0;
})
.map((element) => {
const $element = $(element);
const title = $element.find('.excerpt__title a').text();
const link = 'https://www.asianfanfics.com' + $element.find('.excerpt__title a').attr('href');
const author = $element.find('.excerpt__meta__name a').text().trim();
const pubDate = parseDate($element.find('time').attr('datetime') || '');

return {
title,
link,
author,
pubDate,
};
});

// don't forget to close the browser instance at the end of the function
browser.close();

return {
title: `Asianfanfics 亚洲同人网 - 标签:${tag} - ${typeToText[type]}`,
link,
item: items,
};
}
89 changes: 89 additions & 0 deletions lib/routes/asianfanfics/text-search.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,89 @@
import { DataItem, Route } from '@/types';
import logger from '@/utils/logger';
import { parseDate } from '@/utils/parse-date';
import puppeteer from '@/utils/puppeteer';
import { load } from 'cheerio';

// test url http://localhost:1200/asianfanfics/text-search/milklove

export const route: Route = {
path: '/text-search/:keyword',
categories: ['reading'],
example: '/text-search/milklove',
parameters: {
keyword: '关键词',
},
name: '亚洲同人网关键词',
maintainers: ['KazooTTT'],
radar: [
{
source: ['www.asianfanfics.com/browse/text_search?q=:keyword'],
target: '/text-search/:keyword',
},
],
description: `匹配亚洲同人网搜索关键词`,
handler,
};

async function handler(ctx) {
const keyword = ctx.req.param('keyword');

const link = `https://www.asianfanfics.com/browse/text_search?q=${keyword}+`;

// require puppeteer utility class and initialise a browser instance
const browser = await puppeteer();
// open a new tab
const page = await browser.newPage();
// intercept all requests
await page.setRequestInterception(true);
// only allow certain types of requests to proceed
page.on('request', (request) => {
// in this case, we only allow document requests to proceed
request.resourceType() === 'document' ? request.continue() : request.abort();
});
// ofetch requests will be logged automatically
// but puppeteer requests are not
// so we need to log them manually
logger.http(`Requesting ${link}`);

await page.goto(link, {
// specify how long to wait for the page to load
waitUntil: 'domcontentloaded',
});
// retrieve the HTML content of the page
const response = await page.content();
// close the tab
page.close();

const $ = load(response);

const items: DataItem[] = $('.primary-container .excerpt')
.toArray()
.filter((element) => {
const $element = $(element);
return $element.find('.excerpt__title a').length > 0;
})
.map((element) => {
const $element = $(element);
const title = $element.find('.excerpt__title a').text();
const link = 'https://www.asianfanfics.com' + $element.find('.excerpt__title a').attr('href');
const author = $element.find('.excerpt__meta__name a').text().trim();
const pubDate = parseDate($element.find('time').attr('datetime') || '');

return {
title,
link,
author,
pubDate,
};
});

// don't forget to close the browser instance at the end of the function
browser.close();

return {
title: `Asianfanfics 亚洲同人网 - 关键词:${keyword}`,
link,
item: items,
};
}

0 comments on commit 322e0d5

Please sign in to comment.