mirror of
https://github.com/DIYgod/RSSHub.git
synced 2026-09-01 14:57:14 +08:00
fix(route): 迁移看雪路由 (#15064)
* 迁移看雪路由 * 迁移看雪路由 * Update lib/routes/kanxue/topic.ts Co-authored-by: Tony <TonyRL@users.noreply.github.com> * 迁移看雪路由 ---------
This commit is contained in:
+1
-1
@@ -330,7 +330,7 @@ router.get('/qutoutiao/category/:cid', lazyloadRouteHandler('./routes/qutoutiao/
|
||||
// router.get('/bbc/:site?/:channel?', lazyloadRouteHandler('./routes/bbc/index'));
|
||||
|
||||
// 看雪
|
||||
router.get('/pediy/topic/:category?/:type?', lazyloadRouteHandler('./routes/pediy/topic'));
|
||||
// router.get('/pediy/topic/:category?/:type?', lazyloadRouteHandler('./routes/pediy/topic'));
|
||||
|
||||
// 老司机
|
||||
router.get('/laosiji/hot', lazyloadRouteHandler('./routes/laosiji/hot'));
|
||||
|
||||
@@ -1,117 +0,0 @@
|
||||
const got = require('@/utils/got');
|
||||
const pediyUtils = require('./utils');
|
||||
const cheerio = require('cheerio');
|
||||
|
||||
const baseUrl = 'https://bbs.pediy.com/';
|
||||
const categoryId = {
|
||||
iot: [128, '智能设备'],
|
||||
blockchain: [172, '区块链安全'],
|
||||
android: [161, 'Android安全'],
|
||||
ios: [166, 'iOS安全'],
|
||||
re: [4, '软件逆向'],
|
||||
coding: [41, '编程技术'],
|
||||
unpack: [88, '加壳脱壳'],
|
||||
crypto: [132, '密码算法'],
|
||||
vuln: [150, '二进制漏洞'],
|
||||
crackme: [37, 'CrackMe'],
|
||||
pwn: [171, 'Pwn'],
|
||||
web: [151, 'WEB安全'],
|
||||
translate: [32, '外文翻译'],
|
||||
};
|
||||
|
||||
module.exports = async (ctx) => {
|
||||
const category = ctx.params.category || 'all';
|
||||
const type = ctx.params.type || 'latest';
|
||||
let path;
|
||||
let title;
|
||||
if (Object.hasOwn(categoryId, category)) {
|
||||
if (type === 'digest') {
|
||||
// type为digest时只获取精华帖
|
||||
path = `forum-${categoryId[category][0]}-1.htm?digest=1`;
|
||||
title = `看雪论坛精华主题 - ${categoryId[category][1]}`;
|
||||
} else {
|
||||
// type为空/非法/latest时则只获取最新帖
|
||||
path = `forum-${categoryId[category][0]}.html`;
|
||||
title = `看雪论坛最新主题 - ${categoryId[category][1]}`;
|
||||
}
|
||||
} else {
|
||||
// category未知时则获取全站最新帖
|
||||
if (category === 'digest') {
|
||||
path = 'new-digest.htm';
|
||||
title = '看雪论坛精华主题';
|
||||
} else {
|
||||
path = 'new-tid.htm';
|
||||
title = '看雪论坛最新主题';
|
||||
}
|
||||
}
|
||||
|
||||
const response = await got({
|
||||
method: 'get',
|
||||
url: baseUrl + path,
|
||||
headers: {
|
||||
Referer: baseUrl,
|
||||
},
|
||||
});
|
||||
|
||||
const $ = cheerio.load(response.data);
|
||||
const list = $('.thread');
|
||||
|
||||
const resultItem = await Promise.all(
|
||||
list
|
||||
? list
|
||||
// fix .thread .top_3
|
||||
.filter((_, elem) => {
|
||||
const pubDate = pediyUtils.dateParser($('.date', elem).eq(0).text(), 8);
|
||||
return !elem.attribs.class.includes('top') || Date.now() - new Date(pubDate) < 1000 * 60 * 60 * 24 * 3;
|
||||
})
|
||||
.map(async (_, elem) => {
|
||||
const subject = $('.subject a', elem).eq(1);
|
||||
const pubDate = pediyUtils.dateParser($('.date', elem).eq(0).text(), 8);
|
||||
|
||||
const link = `${baseUrl}${subject.attr('href')}`;
|
||||
const key = `pediy: ${link}`;
|
||||
const value = await ctx.cache.get(key);
|
||||
let description;
|
||||
|
||||
if (value) {
|
||||
description = value;
|
||||
} else {
|
||||
const postDetail = await got({
|
||||
method: 'get',
|
||||
url: link,
|
||||
});
|
||||
const $ = cheerio.load(postDetail.data);
|
||||
$('.card')
|
||||
.eq(0)
|
||||
.find('.message img')
|
||||
.each((_, item) => {
|
||||
item = $(item);
|
||||
|
||||
const src = item.attr('src');
|
||||
if (src !== undefined && !src.startsWith('https://') && !src.startsWith('http://')) {
|
||||
item.attr('src', `https://bbs.pediy.com/${src}`);
|
||||
}
|
||||
item.attr('referrerpolicy', 'no-referrer');
|
||||
});
|
||||
|
||||
description = $('.card').eq(0).find('.message').html();
|
||||
ctx.cache.set(key, description);
|
||||
}
|
||||
|
||||
return {
|
||||
title: subject.text(),
|
||||
link,
|
||||
pubDate: new Date(pubDate),
|
||||
description,
|
||||
};
|
||||
})
|
||||
.get()
|
||||
: []
|
||||
);
|
||||
|
||||
ctx.state.data = {
|
||||
title,
|
||||
link: baseUrl + path,
|
||||
item: resultItem,
|
||||
};
|
||||
};
|
||||
@@ -1,27 +0,0 @@
|
||||
const pediyUtils = {
|
||||
dateParser: (html, timeZone) => {
|
||||
let math;
|
||||
let date = new Date();
|
||||
if (/(\d+)分钟前/.test(html)) {
|
||||
math = /(\d+)分钟前/.exec(html);
|
||||
date.setMinutes(date.getMinutes() - math[1]);
|
||||
return date.toUTCString();
|
||||
} else if (/(\d+)小时前/.test(html)) {
|
||||
math = /(\d+)小时前/.exec(html);
|
||||
date.setHours(date.getHours() - math[1]);
|
||||
return date.toUTCString();
|
||||
} else if (/(\d+)天前/.test(html)) {
|
||||
math = /(\d+)天前/.exec(html);
|
||||
date.setDate(date.getDate() - math[1]);
|
||||
return date.toUTCString();
|
||||
} else if (/(\d+)-(\d+)-(\d+) (\d+):(\d+)/.test(html)) {
|
||||
math = /(\d+)-(\d+)-(\d+) (\d+):(\d+)/.exec(html);
|
||||
date = new Date(math[1], Number.parseInt(math[2]) - 1, math[3], math[4], math[5]);
|
||||
const serverOffset = new Date().getTimezoneOffset() / 60;
|
||||
return new Date(date.getTime() - 60 * 60 * 1000 * (timeZone + serverOffset)).toUTCString();
|
||||
}
|
||||
return html;
|
||||
},
|
||||
};
|
||||
|
||||
module.exports = pediyUtils;
|
||||
@@ -0,0 +1,6 @@
|
||||
import type { Namespace } from '@/types';
|
||||
|
||||
export const namespace: Namespace = {
|
||||
name: '看雪',
|
||||
url: 'kanxue.com',
|
||||
};
|
||||
@@ -0,0 +1,153 @@
|
||||
import { Route } from '@/types';
|
||||
import cache from '@/utils/cache';
|
||||
import got from '@/utils/got';
|
||||
import { load } from 'cheerio';
|
||||
import { parseRelativeDate, parseDate } from '@/utils/parse-date';
|
||||
|
||||
const baseUrl = 'https://bbs.kanxue.com/';
|
||||
const categoryId = {
|
||||
iot: [128, '智能设备'],
|
||||
android: [161, 'Android安全'],
|
||||
ios: [166, 'iOS安全'],
|
||||
harmonyos: [178, 'HarmonyOS安全'],
|
||||
re: [4, '软件逆向'],
|
||||
coding: [41, '编程技术'],
|
||||
unpack: [88, '加壳脱壳'],
|
||||
crypto: [132, '密码应用'],
|
||||
vuln: [150, '二进制漏洞'],
|
||||
ctf: [37, 'CTF对抗'],
|
||||
pwn: [171, 'Pwn'],
|
||||
web: [151, 'WEB安全'],
|
||||
chat: [45, '茶余饭后'],
|
||||
geekzone: [172, '极客空间'],
|
||||
translate: [32, '外文翻译'],
|
||||
};
|
||||
|
||||
export const route: Route = {
|
||||
path: '/topic/:category?/:type?',
|
||||
categories: ['bbs'],
|
||||
example: '/kanxue/topic/android/digest',
|
||||
parameters: { category: '版块, 缺省为`all`', type: '类型, 缺省为`latest`' },
|
||||
name: '论坛',
|
||||
maintainers: ['renzhexigua'],
|
||||
handler,
|
||||
description: `| 版块 | category |
|
||||
| -------------- | --------- |
|
||||
| 智能设备 | iot |
|
||||
| Android 安全 | android |
|
||||
| iOS 安全 | ios |
|
||||
| HarmonyOS 安全 | harmonyos |
|
||||
| 软件逆向 | re |
|
||||
| 编程技术 | coding |
|
||||
| 加壳脱壳 | unpack |
|
||||
| 密码应用 | crypto |
|
||||
| 二进制漏洞 | vuln |
|
||||
| CTF 对抗 | ctf |
|
||||
| Pwn | pwn |
|
||||
| WEB 安全 | web |
|
||||
| 茶余饭后 | chat |
|
||||
| 极客空间 | geekzone |
|
||||
| 外文翻译 | translate |
|
||||
| 全站 | all |
|
||||
|
||||
| 类型 | type |
|
||||
| -------- | ------ |
|
||||
| 最新主题 | latest |
|
||||
| 精华主题 | digest |`,
|
||||
};
|
||||
|
||||
const timeDiff = 1000 * 60 * 60 * 24 * 3;
|
||||
|
||||
async function handler(ctx) {
|
||||
const category = ctx.req.param('category') || 'all';
|
||||
const type = ctx.req.param('type') || 'latest';
|
||||
let path;
|
||||
let title;
|
||||
if (Object.hasOwn(categoryId, category)) {
|
||||
if (type === 'digest') {
|
||||
// type为digest时只获取精华帖
|
||||
path = `forum-${categoryId[category][0]}-1.htm?digest=1`;
|
||||
title = `看雪论坛精华主题 - ${categoryId[category][1]}`;
|
||||
} else {
|
||||
// type为空/非法/latest时则只获取最新帖
|
||||
path = `forum-${categoryId[category][0]}.html`;
|
||||
title = `看雪论坛最新主题 - ${categoryId[category][1]}`;
|
||||
}
|
||||
} else {
|
||||
// category未知时则获取全站最新帖
|
||||
if (category === 'digest') {
|
||||
path = 'new-digest.htm';
|
||||
title = '看雪论坛精华主题';
|
||||
} else {
|
||||
path = 'new-tid.htm';
|
||||
title = '看雪论坛最新主题';
|
||||
}
|
||||
}
|
||||
|
||||
const response = await got({
|
||||
method: 'get',
|
||||
url: baseUrl + path,
|
||||
headers: {
|
||||
Referer: baseUrl,
|
||||
},
|
||||
});
|
||||
|
||||
const $ = load(response.data);
|
||||
const list = $('.thread');
|
||||
|
||||
const resultItem = await Promise.all(
|
||||
list
|
||||
? list
|
||||
// fix .thread .top_3
|
||||
.filter((_, elem) => {
|
||||
const timeStr = $('.date', elem).eq(0).text();
|
||||
const pubDate = timeStr.endsWith("前") ? parseRelativeDate(timeStr) : parseDate(timeStr.substring(1));
|
||||
return !elem.attribs.class.includes('top') || Date.now() - pubDate.valueOf() < timeDiff;
|
||||
})
|
||||
.map((_, elem) => {
|
||||
const subject = $('.subject a', elem).eq(1);
|
||||
const timeStr = $('.date', elem).eq(0).text();
|
||||
const pubDate = timeStr.endsWith("前") ? parseRelativeDate(timeStr) : parseDate(timeStr.substring(1));
|
||||
|
||||
const link = `${baseUrl}${subject.attr('href')}`;
|
||||
const key = `kanxue: ${link}`;
|
||||
|
||||
return cache.tryGet(key, async () => {
|
||||
const postDetail = await got({
|
||||
method: 'get',
|
||||
url: link,
|
||||
});
|
||||
const $ = load(postDetail.data);
|
||||
$('.card')
|
||||
.eq(0)
|
||||
.find('.message img')
|
||||
.each((_, item) => {
|
||||
item = $(item);
|
||||
|
||||
const src = item.attr('src');
|
||||
if (src !== undefined && !src.startsWith('https://') && !src.startsWith('http://')) {
|
||||
item.attr('src', `https://bbs.kanxue.com/${src}`);
|
||||
}
|
||||
});
|
||||
|
||||
const description = $('.card').eq(0).find('.message').html();
|
||||
|
||||
return {
|
||||
title: subject.text(),
|
||||
link,
|
||||
pubDate,
|
||||
description,
|
||||
};
|
||||
});
|
||||
})
|
||||
.get()
|
||||
: []
|
||||
);
|
||||
|
||||
return {
|
||||
title,
|
||||
link: baseUrl + path,
|
||||
item: resultItem,
|
||||
allowEmpty: true
|
||||
};
|
||||
};
|
||||
Reference in New Issue
Block a user