UNPKG

rsshub

Version:
154 lines (139 loc) 5.33 kB
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 .toArray() .filter((elem) => { const timeStr = $('.date', elem).eq(0).text(); const pubDate = timeStr.endsWith('前') ? parseRelativeDate(timeStr) : parseDate(timeStr.slice(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.slice(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, }; }); }) : [] ); return { title, link: baseUrl + path, item: resultItem, allowEmpty: true, }; }