From b621d38e51137472b0dab3ead4d9b232517963ba Mon Sep 17 00:00:00 2001 From: DIYgod Date: Wed, 28 Feb 2024 23:49:11 +0800 Subject: [PATCH] feat: v3 migration - 8/n --- lib/routes.ts | 4 +- lib/{v3 => v2}/index.ts | 0 lib/{v3 => v2}/robots.txt.ts | 0 lib/{v3 => v2}/test/index.js | 0 lib/{v3 => v2}/test/maintainer.js | 0 lib/v2/test/router.js | 3 + lib/v3/jike/maintainer.js | 5 - lib/v3/jike/radar.js | 54 -------- lib/v3/jike/router.js | 5 - lib/v3/jike/topic-text.js | 21 --- lib/v3/jike/topic.js | 48 ------- lib/v3/jike/user.js | 158 ----------------------- lib/v3/jike/utils.js | 198 ----------------------------- lib/v3/rsshub/maintainer.js | 6 - lib/v3/rsshub/radar.js | 13 -- lib/v3/rsshub/router.js | 6 - lib/v3/rsshub/routes.js | 65 ---------- lib/v3/rsshub/transform/html.js | 65 ---------- lib/v3/rsshub/transform/json.js | 58 --------- lib/v3/rsshub/transform/sitemap.js | 50 -------- lib/v3/test/router.js | 3 - 21 files changed, 5 insertions(+), 757 deletions(-) rename lib/{v3 => v2}/index.ts (100%) rename lib/{v3 => v2}/robots.txt.ts (100%) rename lib/{v3 => v2}/test/index.js (100%) rename lib/{v3 => v2}/test/maintainer.js (100%) create mode 100644 lib/v2/test/router.js delete mode 100644 lib/v3/jike/maintainer.js delete mode 100644 lib/v3/jike/radar.js delete mode 100644 lib/v3/jike/router.js delete mode 100644 lib/v3/jike/topic-text.js delete mode 100644 lib/v3/jike/topic.js delete mode 100644 lib/v3/jike/user.js delete mode 100644 lib/v3/jike/utils.js delete mode 100644 lib/v3/rsshub/maintainer.js delete mode 100644 lib/v3/rsshub/radar.js delete mode 100644 lib/v3/rsshub/router.js delete mode 100644 lib/v3/rsshub/routes.js delete mode 100644 lib/v3/rsshub/transform/html.js delete mode 100644 lib/v3/rsshub/transform/json.js delete mode 100644 lib/v3/rsshub/transform/sitemap.js delete mode 100644 lib/v3/test/router.js diff --git a/lib/routes.ts b/lib/routes.ts index 7458881206..6470201d7c 100644 --- a/lib/routes.ts +++ b/lib/routes.ts @@ -3,8 +3,8 @@ import type { Hono, Handler } from 'hono'; import { serveStatic } from '@hono/node-server/serve-static'; import * as path from 'node:path'; -import index from '@/v3/index'; -import robotstxt from '@/v3/robots.txt'; +import index from '@/v2/index'; +import robotstxt from '@/v2/robots.txt'; type Root = { get: (routePath: string, filePath: string) => void; diff --git a/lib/v3/index.ts b/lib/v2/index.ts similarity index 100% rename from lib/v3/index.ts rename to lib/v2/index.ts diff --git a/lib/v3/robots.txt.ts b/lib/v2/robots.txt.ts similarity index 100% rename from lib/v3/robots.txt.ts rename to lib/v2/robots.txt.ts diff --git a/lib/v3/test/index.js b/lib/v2/test/index.js similarity index 100% rename from lib/v3/test/index.js rename to lib/v2/test/index.js diff --git a/lib/v3/test/maintainer.js b/lib/v2/test/maintainer.js similarity index 100% rename from lib/v3/test/maintainer.js rename to lib/v2/test/maintainer.js diff --git a/lib/v2/test/router.js b/lib/v2/test/router.js new file mode 100644 index 0000000000..de87b52670 --- /dev/null +++ b/lib/v2/test/router.js @@ -0,0 +1,3 @@ +module.exports = function (router) { + router.get('/:id', './index'); +}; diff --git a/lib/v3/jike/maintainer.js b/lib/v3/jike/maintainer.js deleted file mode 100644 index 28c9801b4e..0000000000 --- a/lib/v3/jike/maintainer.js +++ /dev/null @@ -1,5 +0,0 @@ -module.exports = { - '/topic/text/:id': ['HenryQW'], - '/topic/:id/:showUid?': ['DIYgod', 'prnake'], - '/user/:id': ['DIYgod', 'prnake'], -}; diff --git a/lib/v3/jike/radar.js b/lib/v3/jike/radar.js deleted file mode 100644 index b226de810c..0000000000 --- a/lib/v3/jike/radar.js +++ /dev/null @@ -1,54 +0,0 @@ -module.exports = { - 'okjike.com': { - _name: '即刻', - m: [ - { - title: '用户动态', - docs: 'https://docs.rsshub.app/routes/social-media#ji-ke', - source: '/users/:uid', - target: '/jike/user/:uid', - }, - { - title: '用户动态', - docs: 'https://docs.rsshub.app/routes/social-media#ji-ke', - source: '/reposts/:repostId', - target: (params, url, document) => { - const uid = document.querySelector('.avatar').getAttribute('href').replace('/users/', ''); - return uid ? `/jike/user/${uid}` : ''; - }, - }, - { - title: '圈子', - docs: 'https://docs.rsshub.app/routes/social-media#ji-ke', - source: '/topics/:id', - target: '/jike/topic/:id', - }, - { - title: '圈子 - 纯文字', - docs: 'https://docs.rsshub.app/routes/social-media#ji-ke', - source: '/topics/:id', - target: '/jike/topic/text/:id', - }, - ], - web: [ - { - title: '用户动态', - docs: 'https://docs.rsshub.app/routes/social-media#ji-ke', - source: '/u/:uid', - target: '/jike/user/:uid', - }, - { - title: '圈子', - docs: 'https://docs.rsshub.app/routes/social-media#ji-ke', - source: '/topic/:id', - target: '/jike/topic/:id', - }, - { - title: '圈子 - 纯文字', - docs: 'https://docs.rsshub.app/routes/social-media#ji-ke', - source: '/topic/:id', - target: '/jike/topic/text/:id', - }, - ], - }, -}; diff --git a/lib/v3/jike/router.js b/lib/v3/jike/router.js deleted file mode 100644 index fc0901c4b0..0000000000 --- a/lib/v3/jike/router.js +++ /dev/null @@ -1,5 +0,0 @@ -module.exports = (router) => { - router.get('/topic/text/:id', require('./topic-text')); - router.get('/topic/:id/:showUid?', require('./topic')); - router.get('/user/:id', require('./user')); -}; diff --git a/lib/v3/jike/topic-text.js b/lib/v3/jike/topic-text.js deleted file mode 100644 index f243428f3c..0000000000 --- a/lib/v3/jike/topic-text.js +++ /dev/null @@ -1,21 +0,0 @@ -const dayjs = require('dayjs'); -const { constructTopicEntry } = require('./utils'); - -module.exports = async (ctx) => { - const id = ctx.req.param('id'); - const topicUrl = `https://m.okjike.com/topics/${id}`; - - const data = await constructTopicEntry(ctx, topicUrl); - - if (data) { - ctx.state.data.item = data.posts.map((item) => { - const date = dayjs(item.createdAt); - return { - title: `${data.topic.content} ${date.format('MM月DD日')}`, - description: item.content.replaceAll('\n', '
'), - pubDate: date.toDate(), - link: `https://m.okjike.com/originalPosts/${item.id}`, - }; - }); - } -}; diff --git a/lib/v3/jike/topic.js b/lib/v3/jike/topic.js deleted file mode 100644 index 336a1c30d4..0000000000 --- a/lib/v3/jike/topic.js +++ /dev/null @@ -1,48 +0,0 @@ -const got = require('@/utils/got'); -const { topicDataHanding } = require('./utils'); -const cheerio = require('cheerio'); -const dayjs = require('dayjs'); -const { constructTopicEntry } = require('@/v3/jike/utils'); - -module.exports = async (ctx) => { - const id = ctx.req.param('id'); - const topicUrl = `https://m.okjike.com/topics/${id}`; - - const data = await constructTopicEntry(ctx, topicUrl); - - if (data) { - let item = topicDataHanding(data, ctx); - if (id === '553870e8e4b0cafb0a1bef68' || id === '55963702e4b0d84d2c30ce6f') { - item = await Promise.all( - item.map(async (one) => { - const item = { ...one }; - const regResult = /https:\/\/www\.okjike\.com\/medium\/[\dA-Za-z]*/.exec(item.description); - if (regResult) { - const newsUrl = regResult[0]; - item.description = await ctx.cache.tryGet(newsUrl, async () => { - const { data } = await got(newsUrl); - const $ = cheerio.load(data); - const upper = $('ul.main > li.item'); - const links = upper.find('a').map((_, ele) => $(ele).attr('href')); - const texts = upper.find('span.text').map((_, ele) => $(ele).text()); - let description = ''; - for (const [i, link] of links.entries()) { - description += `${i + 1}、${texts[i]}
`; - } - description = description.replace(/
$/, ''); - return description; - }); - } - item.title = `${data.topic.content} ${dayjs(one.pubDate).format('MM月DD日')}`; - return item; - }) - ); - } - - - ctx.set('data', { - ...ctx.get('data'), - item, - }); - } -}; diff --git a/lib/v3/jike/user.js b/lib/v3/jike/user.js deleted file mode 100644 index bef1798231..0000000000 --- a/lib/v3/jike/user.js +++ /dev/null @@ -1,158 +0,0 @@ -const got = require('@/utils/got'); -const cheerio = require('cheerio'); -const { parseDate } = require('@/utils/parse-date'); - -module.exports = async (ctx) => { - const id = ctx.req.param('id'); - - const response = await got({ - method: 'get', - url: `https://m.okjike.com/users/${id}`, - headers: { - Referer: `https://m.okjike.com/users/${id}`, - }, - }); - - const html = response.data; - const $ = cheerio.load(html); - const raw = $('[type = "application/json"]').html(); - const data = JSON.parse(raw).props.pageProps; - - const getLink = (id, type) => { - switch (type) { - case 'REPOST': - return `https://m.okjike.com/reposts/${id}`; - case 'MEDIUM': - return `https://www.okjike.com/medium/${id}`; - default: - return `https://m.okjike.com/originalPosts/${id}`; - } - }; - - const items = await Promise.all( - data.posts.map(async (item) => { - const typeMap = { - ORIGINAL_POST: '发布', - REPOST: '转发', - ANSWER: '回答', - QUESTION: '提问', - PERSONAL_UPDATE: '创建新主题', - }; - - let linkTemplate = ''; - if (item.linkInfo && item.linkInfo.linkUrl) { - linkTemplate = `${item.linkInfo.title}
`; - } - - let imgTemplate = ''; - if (item.pictures) { - for (const picture of item.pictures) { - imgTemplate += `
`; - } - } - - let content = item.content || (item.linkInfo && item.linkInfo.title) || (item.question && item.question.title) || item.title || ''; - content = content.replaceAll(/\r\n|\n|\r/g, '
'); - - let shortenTitle = '一条动态'; - if (content) { - shortenTitle = content.replaceAll(/(
)+/g, ' '); - content = `${content}

`; - } - - let repostContent; - if (item.type === 'REPOST') { - const screenNameTemplate = item.target.user ? `@${item.target.user.screenName}` : ''; - - let repostImgTemplate = ''; - if (item.target.pictures) { - for (const picture of item.target.pictures) { - repostImgTemplate += `
`; - } - } - - repostContent = `
转发 ${screenNameTemplate}: ${item.target.content}${repostImgTemplate}
`.replaceAll(/\r\n|\n|\r/g, '
'); - content = `${content}${repostContent}`; - } - // 部分功能未知 - /* else if (item.type === 'ANSWER') { - let answerTextTemplate = ''; - let answerImgTemplate = ''; - let answerImgKeys = []; - item.richtextContent.blocks && - item.richtextContent.blocks.forEach((item) => { - if (item.entityRanges.length && item.text === '[图片]') { - answerImgKeys = [...answerImgKeys, ...Object.keys(item.entityRanges)]; - } else { - answerTextTemplate += item.text; - } - }); - - if (answerImgKeys.length) { - answerImgKeys.forEach((key) => { - const entity = item.richtextContent.entityMap[key]; - if (entity.type.toUpperCase() === 'IMAGE') { - answerImgTemplate += `
`; - } - }); - } - const answerContent = `回答: ${answerTextTemplate}${answerImgTemplate}`; - content = `${content}${answerContent}`.replace(/\n|\r/g, '
'); - } else if (item.type === 'QUESTION') { - content = `在主题 ${item.topic.content} 提出了一个问题:

${content}`; - } else if (item.type === 'PERSONAL_UPDATE') { - shortenTitle = item.topic.content; - content = ` 主题简介:
${item.topic.briefIntro.replace(/(?:\r\n|\r|\n)/g, '
')}`; - }*/ - - const single = { - title: `${typeMap[item.type]}了: ${shortenTitle}`, - description: `${content}${linkTemplate}${imgTemplate}`.replace(/(
|\s)+$/, ''), - pubDate: parseDate(item.createdAt), - link: getLink(item.id, item.type), - _extra: repostContent && { - links: [ - { - url: getLink(item.target.id, item.target.type), - type: 'quote', - }, - ], - }, - }; - - if (id === 'wenhao1996' && item.topic.id === '553870e8e4b0cafb0a1bef68') { - single.link = item.urlsInText[0].url; - - const { data } = await got({ - method: 'get', - url: single.link, - headers: { - Referer: `https://m.okjike.com/users/${id}`, - }, - }); - const $$ = cheerio.load(data); - $$('span.num,span.arrow').remove(); - - single.title = `一觉醒来世界发生了什么 ${$$('title').text()}`; - - single.description = ''; - $$('div.container') - .find('li.item') - // eslint-disable-next-line array-callback-return - .map((i, j) => { - single.description += `${$$(j).find('a').text()}
`; - }); - } - - return single; - }) - ); - - ctx.set('data', { - title: `${data.user.screenName}的即刻动态`, - description: data.user.bio, - link: `https://m.okjike.com/users/${id}`, - image: data.user.avatarImage.picUrl, - item: items, - }); -}; diff --git a/lib/v3/jike/utils.js b/lib/v3/jike/utils.js deleted file mode 100644 index ad3fece218..0000000000 --- a/lib/v3/jike/utils.js +++ /dev/null @@ -1,198 +0,0 @@ -const cheerio = require('cheerio'); -import parseDate from '@/utils/parse-date'; -import got from '@/utils/got'; -import { config } from '@/config'; -import cache from '@/utils/cache'; - -const videoAPI = 'https://api.ruguoapp.com/1.0/mediaMeta/play?type=ORIGINAL_POST'; - -module.exports = { - topicDataHanding: (data, ctx) => - data.posts.map((item) => { - let audioName, videoName, linkName; - - // 获取纯文字内容 和 即刻原文链接 - let content, link; - switch (item.type) { - case 'ORIGINAL_POST': - content = item.content; - link = `https://m.okjike.com/originalPosts/${item.id}`; - break; - - /* case 'QUESTION': - content = item.title; - link = `https://m.okjike.com/questions/${item.id}`; - break; - case 'OFFICIAL_MESSAGE': - content = item.content; - link = `https://web.okjike.com/message-detail/${item.id}/officialMessage`; - break;*/ - default: - content = '未知类型,请前往GitHub提交issue'; - link = 'https://github.com/DIYgod/RSSHub/issues'; - } - - // rss内容 - let description = ''; - // 作者昵称 - let author = ''; - - // 添加内容作者信息 - if (item.user) { - author = item.user.screenName; - if (ctx.req.param('showUid')) { - description += `用户昵称:${author}
Username:${item.user.username}

`; - } - } - - if (item.linkInfo) { - const linkUrl = item.linkInfo.originalLinkUrl || item.linkInfo.linkUrl; - - // 对于即刻抓取的微信公众号文章 特殊处理 - // 此时 Rss原文链接 变为 微信公众号链接 - if (new URL(linkUrl).host === 'mp.weixin.qq.com') { - link = linkUrl; - } - - // 1. 音频 - const audioObject = item.linkInfo.audio || item.audio; - if (audioObject) { - const audioImage = audioObject.image.picUrl || audioObject.image.thumbnailUrl; - const audioLink = linkUrl; - const audioTitle = audioObject.title; - const audioAuthor = audioObject.author; - audioName = `${audioTitle} - ${audioAuthor}`; - description += ` - - ${audioName} - `; - } - - // 2. 视频 - const videoObject = item.linkInfo.video || item.video; - if (videoObject) { - const videoImage = videoObject.image.picUrl || videoObject.image.thumbnailUrl; - const videoLink = linkUrl; - const videoDuration = Math.floor(videoObject.duration / 60000); - videoName = item.linkInfo.title; - description += ` - - ${videoName || '观看视频'} - 约${videoDuration}分钟 - `; - } - - // 3. 链接 - if (!audioObject && !videoObject && linkUrl) { - // 部分链接有标题 - linkName = item.linkInfo.title; - const linkTitle = linkName || '访问原文'; - // 部分链接有缩略图 - const linkImage = item.linkInfo.pictureUrl; - const imageTag = ``; - description += ` - ${linkImage ? imageTag : ''} - ${linkTitle} - `; - } - } - - // 4. 文字内容 - description += description ? `
${content}` : content; - - // 5. 图片 - if (item.pictures) { - for (const pic of item.pictures) { - if (pic.format === 'gif') { - description += ``; - } else { - // jpeg, bmp, png, gif, webp - // https://developer.mozilla.org/en-US/docs/Web/HTTP/Basics_of_HTTP/MIME_types - // let type = 'jpeg'; - // switch (pic.format) { - // case 'bmp': - // type = 'bmp'; - // break; - // case 'png': - // type = 'png'; - // break; - // default: - // break; - // } - const imgUrl = /\.[\da-z]+?\?imageMogr2/.test(pic.picUrl) ? pic.picUrl.split('?imageMogr2/')[0] : pic.picUrl.replace(/thumbnail\/.+/, ''); - description += `
`; - // description += `
`; - } - } - } - - // 6. 视频 - if (item.video) { - description += `
`; - } - - // rss标题 - // 优先将音频和视频名作为标题 - // 其次将正文内容作为标题 - // 若都没有 则是推送型消息,将连接标题作为主题 - // “无题” fallback - const title = audioName || videoName || content || linkName || '无题'; - - return { - title, - description: description.trim().replaceAll('\n', '
'), - pubDate: parseDate.parse(item.createdAt), - author, - link, - }; - }), - constructTopicEntry: async (ctx, url) => { - const data = await cache.tryGet( - url, - async () => { - const resp = await got(url); - const html = resp.data; - const $ = cheerio.load(html); - const raw = $('[type = "application/json"]').html(); - const data = JSON.parse(raw).props.pageProps; - data.posts = await Promise.all( - data.posts.map(async (item) => { - if (!item.video) { - return item; - } - - const videoUrl = `${videoAPI}&id=${item.id}`; - const videoRes = await got(videoUrl); - item.video = videoRes.data; - - return item; - }) - ); - - return data; - }, - false, - config.cache.routeExpire - ); - - if (data.length === 0) { - ctx.set('data', { - title: '主题 ID 不存在,或该主题暂无内容', - }); - return null; - } - - const topic = data.topic; - - ctx.set('data', { - title: `${topic.content} - 即刻圈子`, - link: url, - description: topic.briefIntro, - image: topic.squarePicture.picUrl || topic.squarePicture.middlePicUrl || topic.squarePicture.thumbnailUrl, - // item: topicDataHanding(data), - }); - - return data; - }, -}; diff --git a/lib/v3/rsshub/maintainer.js b/lib/v3/rsshub/maintainer.js deleted file mode 100644 index 158998b451..0000000000 --- a/lib/v3/rsshub/maintainer.js +++ /dev/null @@ -1,6 +0,0 @@ -module.exports = { - '/routes/:lang?': ['DIYgod'], - '/transform/html/:url/:routeParams': ['ttttmr'], - '/transform/json/:url/:routeParams': ['ttttmr'], - '/transform/sitemap/:url/:routeParams?': ['flrngel'], -}; diff --git a/lib/v3/rsshub/radar.js b/lib/v3/rsshub/radar.js deleted file mode 100644 index 8327f7fec3..0000000000 --- a/lib/v3/rsshub/radar.js +++ /dev/null @@ -1,13 +0,0 @@ -module.exports = { - 'rsshub.app': { - _name: 'RSSHub', - docs: [ - { - title: '有新路由啦', - docs: 'https://docs.rsshub.app/routes/program-update#rsshub', - source: ['/*'], - target: '/rsshub/routes', - }, - ], - }, -}; diff --git a/lib/v3/rsshub/router.js b/lib/v3/rsshub/router.js deleted file mode 100644 index 7e580dcc58..0000000000 --- a/lib/v3/rsshub/router.js +++ /dev/null @@ -1,6 +0,0 @@ -module.exports = (router) => { - router.get('/routes/:lang?', require('./routes')); - router.get('/transform/html/:url/:routeParams', require('./transform/html')); - router.get('/transform/json/:url/:routeParams', require('./transform/json')); - router.get('/transform/sitemap/:url/:routeParams?', require('./transform/sitemap')); -}; diff --git a/lib/v3/rsshub/routes.js b/lib/v3/rsshub/routes.js deleted file mode 100644 index 9e9c2bc281..0000000000 --- a/lib/v3/rsshub/routes.js +++ /dev/null @@ -1,65 +0,0 @@ -import got from '@/utils/got'; -const cheerio = require('cheerio'); - -module.exports = async (ctx) => { - const isEnglish = ctx.req.param('lang') !== 'zh'; - - const lang = isEnglish ? '' : 'zh/'; - const types = [ - 'social-media', - 'new-media', - 'traditional-media', - 'bbs', - 'blog', - 'programming', - 'design', - 'live', - 'multimedia', - 'picture', - 'anime', - 'program-update', - 'university', - 'forecast', - 'travel', - 'shopping', - 'game', - 'reading', - 'government', - 'study', - 'journal', - 'finance', - 'other', - ]; - const all = await Promise.all( - types.map(async (type) => { - const response = await got(`https://docs.rsshub.app/${lang}routes/${type}`); - - const data = response.data; - - const $ = cheerio.load(data); - const page = $('.page').toArray(); - const item = $('.routeBlock').toArray(); - return { page, item, type }; - }) - ); - const list = all.flatMap(({ page, item, type }) => item.map((item) => ({ page, item, type }))); - - ctx.set('data', { - title: isEnglish ? 'RSSHub has new routes' : 'RSSHub 有新路由啦', - link: 'https://docs.rsshub.app', - description: isEnglish ? 'Everything is RSSible' : '万物皆可 RSS', - language: isEnglish ? 'en-us' : 'zh-cn', - item: list.map(({ page, item, type }) => { - const $ = cheerio.load(page); - item = $(item); - const h2Title = item.prevAll('h2').eq(0); - const h3Title = item.prevAll('h3').eq(0); - return { - title: `${h2Title.text().trim()} - ${h3Title.text().trim()}`, - description: item.html(), - link: `https://docs.rsshub.app/${lang}routes/${type}#${encodeURIComponent(h2Title.find('.hash-link').attr('href') && h3Title.find('.hash-link').attr('href')?.substring(1))}`, - guid: item.attr('id'), - }; - }), - }); -}; diff --git a/lib/v3/rsshub/transform/html.js b/lib/v3/rsshub/transform/html.js deleted file mode 100644 index 0073580dad..0000000000 --- a/lib/v3/rsshub/transform/html.js +++ /dev/null @@ -1,65 +0,0 @@ -import got from '@/utils/got'; -const cheerio = require('cheerio'); -import { config } from '@/config'; - -module.exports = async (ctx) => { - if (!config.feature.allow_user_supply_unsafe_domain) { - throw new Error(`This RSS is disabled unless 'ALLOW_USER_SUPPLY_UNSAFE_DOMAIN' is set to 'true'.`); - } - const url = ctx.req.param('url'); - const response = await got({ - method: 'get', - url, - }); - - const routeParams = new URLSearchParams(ctx.req.param('routeParams')); - const $ = cheerio.load(response.data); - const rssTitle = routeParams.get('title') || $('title').text(); - const item = routeParams.get('item') || 'html'; - const items = $(item) - .toArray() - .map((item) => { - try { - item = $(item); - - const titleEle = routeParams.get('itemTitle') ? item.find(routeParams.get('itemTitle')) : item; - const title = routeParams.get('itemTitleAttr') ? titleEle.attr(routeParams.get('itemTitleAttr')) : titleEle.text(); - - let link; - const linkEle = routeParams.get('itemLink') ? item.find(routeParams.get('itemLink')) : item; - if (routeParams.get('itemLinkAttr')) { - link = linkEle.attr(routeParams.get('itemLinkAttr')); - } else { - link = linkEle.is('a') ? linkEle.attr('href') : linkEle.find('a').attr('href'); - } - // 补全绝对链接 - link = link.trim(); - if (link && !link.startsWith('http')) { - link = `${new URL(url).origin}${link}`; - } - - const descEle = routeParams.get('itemDesc') ? item.find(routeParams.get('itemDesc')) : item; - const desc = routeParams.get('itemDescAttr') ? descEle.attr(routeParams.get('itemDescAttr')) : descEle.html(); - - const pubDateEle = routeParams.get('itemPubDate') ? item.find(routeParams.get('itemPubDate')) : item; - const pubDate = routeParams.get('itemPubDateAttr') ? pubDateEle.attr(routeParams.get('itemPubDateAttr')) : pubDateEle.html(); - - return { - title, - link, - description: desc, - pubDate, - }; - } catch { - return null; - } - }) - .filter(Boolean); - - ctx.set('data', { - title: rssTitle, - link: url, - description: `Proxy ${url}`, - item: items, - }); -}; diff --git a/lib/v3/rsshub/transform/json.js b/lib/v3/rsshub/transform/json.js deleted file mode 100644 index 5ab74d2a30..0000000000 --- a/lib/v3/rsshub/transform/json.js +++ /dev/null @@ -1,58 +0,0 @@ -import got from '@/utils/got'; -const cheerio = require('cheerio'); -import { config } from '@/config'; - -function jsonGet(obj, attr) { - if (typeof attr !== 'string') { - return obj; - } - // a.b.c - // a.b[0].c => a.b.0.c - for (const key of attr.split('.')) { - obj = obj[key]; - } - return obj; -} - -module.exports = async (ctx) => { - if (!config.feature.allow_user_supply_unsafe_domain) { - throw new Error(`This RSS is disabled unless 'ALLOW_USER_SUPPLY_UNSAFE_DOMAIN' is set to 'true'.`); - } - const url = ctx.req.param('url'); - const response = await got({ - method: 'get', - url, - }); - - const routeParams = new URLSearchParams(ctx.req.param('routeParams')); - let rssTitle = routeParams.get('title'); - if (!rssTitle) { - const resp = await got({ - method: 'get', - url: new URL(url).origin, - }); - const $ = cheerio.load(resp.data); - rssTitle = $('title').text(); - } - - const items = jsonGet(response.data, routeParams.get('item')).map((item) => { - let link = jsonGet(item, routeParams.get('itemLink')).trim(); - // 补全绝对链接 - if (link && !link.startsWith('http')) { - link = `${new URL(url).origin}${link}`; - } - return { - title: jsonGet(item, routeParams.get('itemTitle')), - link, - description: routeParams.get('itemDesc') ? jsonGet(item, routeParams.get('itemDesc')) : '', - pubDate: routeParams.get('itemPubDate') ? jsonGet(item, routeParams.get('itemPubDate')) : '', - }; - }); - - ctx.set('data', { - title: rssTitle, - link: url, - description: `Proxy ${url}`, - item: items, - }); -}; diff --git a/lib/v3/rsshub/transform/sitemap.js b/lib/v3/rsshub/transform/sitemap.js deleted file mode 100644 index 4d7946e42e..0000000000 --- a/lib/v3/rsshub/transform/sitemap.js +++ /dev/null @@ -1,50 +0,0 @@ -import got from '@/utils/got'; -const cheerio = require('cheerio'); -import { config } from '@/config'; - -module.exports = async (ctx) => { - if (!config.feature.allow_user_supply_unsafe_domain) { - throw new Error(`This RSS is disabled unless 'ALLOW_USER_SUPPLY_UNSAFE_DOMAIN' is set to 'true'.`); - } - const url = ctx.req.param('url'); - const response = await got({ - method: 'get', - url, - }); - - const routeParams = new URLSearchParams(ctx.req.param('routeParams')); - const $ = cheerio.load(response.data, { xmlMode: true }); - - const rssTitle = routeParams.get('title') || ($('urlset url').length && $('urlset url').first().find('loc').text() ? $('urlset url').first().find('loc').text() : 'Sitemap'); - - const urls = $('urlset url').toArray(); - const items = - urls && urls.length - ? urls - .map((item) => { - try { - const title = $(item).find('loc').text() || ''; - const link = $(item).find('loc').text() || ''; - const description = $(item).find('loc').text() || ''; - const pubDate = $(item).find('lastmod').text() || undefined; - - return { - title, - link, - description, - pubDate, - }; - } catch { - return null; - } - }) - .filter(Boolean) - : []; - - ctx.set('data', { - title: rssTitle, - link: url, - description: `Proxy ${url}`, - item: items, - }); -}; diff --git a/lib/v3/test/router.js b/lib/v3/test/router.js deleted file mode 100644 index 641c23df3a..0000000000 --- a/lib/v3/test/router.js +++ /dev/null @@ -1,3 +0,0 @@ -module.exports = function (router) { - router.get('/:id', require('./index')); -};