diff --git a/assets/radar-rules.js b/assets/radar-rules.js index 5d5c74ede..2e6057168 100644 --- a/assets/radar-rules.js +++ b/assets/radar-rules.js @@ -1678,4 +1678,26 @@ }, ], }, + 'zhuixinfan.com': { + _name: '追新番日剧站', + '.': [ + { + title: '更新列表', + docs: 'https://docs.rsshub.app/multimedia.html#zhui-xin-fan-ri-ju-zhan', + source: ['/main.php'], + target: '/zhuixinfan/list', + }, + ], + }, + 'etoland.co.kr': { + _name: 'eTOLAND', + '.': [ + { + title: '主题贴', + docs: 'https://docs.rsshub.app/bbs.html#etoland', + source: ['/bbs/board.php', '/plugin/mobile/board.php'], + target: (url) => `/etoland/${new URL(url).searchParams.get('bo_table')}`, + }, + ], + }, }); diff --git a/docs/bbs.md b/docs/bbs.md index 1ed898fbb..cddea5504 100644 --- a/docs/bbs.md +++ b/docs/bbs.md @@ -86,7 +86,7 @@ pageClass: routes ### 主题贴 - + ## LearnKu diff --git a/docs/en/install/README.md b/docs/en/install/README.md index 736764cb3..f61113f08 100644 --- a/docs/en/install/README.md +++ b/docs/en/install/README.md @@ -347,6 +347,8 @@ Access control includes a whitelist and a blacklist, support IP and route, use ` `SENTRY`: [Sentry](https://sentry.io) dsn, used for error tracking +`DISALLOW_ROBOT`: prevent indexing by search engine + ### Route-specific Configurations - pixiv: [Registration](https://accounts.pixiv.net/signup) diff --git a/docs/forecast.md b/docs/forecast.md index 9d87c667c..cea9fb737 100644 --- a/docs/forecast.md +++ b/docs/forecast.md @@ -98,7 +98,7 @@ pageClass: routes ### 全国气象预警 - + 可通过全局过滤参数订阅您感兴趣的地区. diff --git a/docs/game.md b/docs/game.md index 437cee621..ba6bad0af 100644 --- a/docs/game.md +++ b/docs/game.md @@ -174,6 +174,12 @@ pageClass: routes +## ScoreSaber + +### 用户动态 + + + ## Steam ### Steam search diff --git a/docs/install/README.md b/docs/install/README.md index 561ef2904..5393e32fa 100644 --- a/docs/install/README.md +++ b/docs/install/README.md @@ -351,6 +351,8 @@ RSSHub 支持 `memory` 和 `redis` 两种缓存方式 `SENTRY`: [Sentry](https://sentry.io) dsn,用于错误追踪 +`DISALLOW_ROBOT`: 防止被搜索引擎收录 + ### 部分 RSS 模块配置 - pixiv 全部路由: [注册地址](https://accounts.pixiv.net/signup) diff --git a/docs/multimedia.md b/docs/multimedia.md index 17836e760..50dded82c 100644 --- a/docs/multimedia.md +++ b/docs/multimedia.md @@ -474,7 +474,7 @@ pageClass: routes ### 更新列表 - + ## 字幕库 diff --git a/lib/config.js b/lib/config.js index d9691ed51..cf17473e7 100644 --- a/lib/config.js +++ b/lib/config.js @@ -40,6 +40,7 @@ const calculateValue = () => { requestRetry: parseInt(envs.REQUEST_RETRY) || 2, // 请求失败重试次数 // 是否显示 Debug 信息,取值 boolean 'false' 'key' ,取值为 'false' false 时永远不显示,取值为 'key' 时带上 ?debug=key 显示 debugInfo: envs.DEBUG_INFO || true, + disallowRobot: envs.DISALLOW_ROBOT !== '0' && envs.DISALLOW_ROBOT !== 'false', titleLengthLimit: parseInt(envs.TITLE_LENGTH_LIMIT) || 150, redis: { url: envs.REDIS_URL || 'redis://localhost:6379/', diff --git a/lib/router.js b/lib/router.js index 3fb8d5c13..4a980183d 100755 --- a/lib/router.js +++ b/lib/router.js @@ -1,4 +1,5 @@ const Router = require('@koa/router'); +const config = require('@/config').value; const router = new Router(); // 遍历整个 routes 文件夹,导入模块路由 router.js 和 router-custom.js 文件 @@ -24,13 +25,23 @@ router.get('/', require('./routes/index')); // test router.get('/test/:id', require('./routes/test')); +router.get('/robots.txt', async (ctx, next) => { + if (config.disallowRobot) { + ctx.set('Content-Type', 'text/plain'); + ctx.body = 'User-agent: *\nDisallow: /'; + } else { + ctx.throw(404, 'Not Found'); + } + await next(); +}); + // RSSHub router.get('/rsshub/rss', require('./routes/rsshub/routes')); // 弃用 router.get('/rsshub/routes', require('./routes/rsshub/routes')); router.get('/rsshub/sponsors', require('./routes/rsshub/sponsors')); // 1draw -router.get('/1draw/', require('./routes/1draw/index')); +router.get('/1draw', require('./routes/1draw/index')); // 1X Magazine router.get('/1x/magazine', require('./routes/1x/magazine')); @@ -143,7 +154,7 @@ router.get('/mzitu/tag/:tag', require('./routes/mzitu/tag')); // pixiv router.get('/pixiv/user/bookmarks/:id', require('./routes/pixiv/bookmarks')); router.get('/pixiv/user/illustfollows', require('./routes/pixiv/illustfollow')); -router.get('/pixiv/user/:id/', require('./routes/pixiv/user')); +router.get('/pixiv/user/:id', require('./routes/pixiv/user')); router.get('/pixiv/ranking/:mode/:date?', require('./routes/pixiv/ranking')); router.get('/pixiv/search/:keyword/:order?/:r18?', require('./routes/pixiv/search')); @@ -528,7 +539,7 @@ router.get('/novel/ptwxz/:id1/:id2', require('./routes/novel/ptwxz')); router.get('/novel/zhaishuyuan/:id', require('./routes/novel/zhaishuyuan')); // 中国气象网 -router.get('/weatheralarm', require('./routes/weatheralarm')); +router.get('/weatheralarm/:province?', require('./routes/weatheralarm')); // Gitlab router.get('/gitlab/explore/:type', require('./routes/gitlab/explore')); @@ -694,8 +705,8 @@ router.get('/whu/news/:type?', require('./routes/universities/whu/news')); // 华中科技大学 router.get('/hust/auto/notice/:type?', require('./routes/universities/hust/aia/notice')); -router.get('/hust/auto/news/', require('./routes/universities/hust/aia/news')); -router.get('/hust/aia/news/', require('./routes/universities/hust/aia/news')); +router.get('/hust/auto/news', require('./routes/universities/hust/aia/news')); +router.get('/hust/aia/news', require('./routes/universities/hust/aia/news')); router.get('/hust/aia/notice/:type?', require('./routes/universities/hust/aia/notice')); // 井冈山大学 @@ -778,7 +789,7 @@ router.get('/guokr/:channel', require('./routes/guokr/calendar')); // 联合早报 router.get('/zaobao/realtime/:section?', require('./routes/zaobao/realtime')); router.get('/zaobao/znews/:section?', require('./routes/zaobao/znews')); -router.get('/zaobao/:type/:section', require('./routes/zaobao/')); +router.get('/zaobao/:type/:section', require('./routes/zaobao/index')); // Apple router.get('/apple/exchange_repair/:country?', require('./routes/apple/exchange_repair')); @@ -1228,7 +1239,7 @@ router.get('/wenku8/chapter/:id', require('./routes/wenku8/chapter')); // 鲸跃汽车 router.get('/whalegogo/home', require('./routes/whalegogo/home')); -router.get('/whalegogo/portal/:type_id/:tagid?/', require('./routes/whalegogo/portal')); +router.get('/whalegogo/portal/:type_id/:tagid?', require('./routes/whalegogo/portal')); // 爱思想 router.get('/aisixiang/column/:id', require('./routes/aisixiang/column')); @@ -1379,7 +1390,7 @@ router.get('/zju/cst/:type', require('./routes/universities/zju/cst')); // 浙江大学城市学院 router.get('/zucc/news/latest', require('./routes/universities/zucc/news')); -router.get('/zucc/cssearch/latest/:webVpn/:key/', require('./routes/universities/zucc/cssearch')); +router.get('/zucc/cssearch/latest/:webVpn/:key', require('./routes/universities/zucc/cssearch')); // 华中师范大学 router.get('/ccnu/career', require('./routes/universities/ccnu/career')); @@ -1898,11 +1909,11 @@ router.get('/latexstudio/home', require('./routes/latexstudio/home')); // 上证债券信息网 - 可转换公司债券公告 router.get('/sse/convert/:query?', require('./routes/sse/convert')); -router.get('/sse/renewal/', require('./routes/sse/renewal')); -router.get('/sse/inquire/', require('./routes/sse/inquire')); +router.get('/sse/renewal', require('./routes/sse/renewal')); +router.get('/sse/inquire', require('./routes/sse/inquire')); // 深圳证券交易所——上市公告 -router.get('/szse/notice/', require('./routes/szse/notice')); +router.get('/szse/notice', require('./routes/szse/notice')); router.get('/szse/inquire/:type', require('./routes/szse/inquire')); // 前端艺术家每日整理&&飞冰早报 @@ -2555,6 +2566,10 @@ router.get('/51voa/:channel', require('./routes/51voa/channel')); // zhuixinfan router.get('/zhuixinfan/list', require('./routes/zhuixinfan/list')); +// scoresaber +router.get('/scoresaber/user/:id', require('./routes/scoresaber/user')); + // unit-image router.get('/unit-image/films/:type?', require('./routes/unit-image/films')); + module.exports = router; diff --git a/lib/routes/facebook/page.js b/lib/routes/facebook/page.js index c2f0c3a10..7f9ba36d9 100644 --- a/lib/routes/facebook/page.js +++ b/lib/routes/facebook/page.js @@ -80,9 +80,10 @@ module.exports = async (ctx) => { const html = await fetchPageHtml(linkPath, pageId, ctx.cache); const $ = cheerio.load(html); - const itemLinks = $('div[role=article] > div:nth-child(2) > div:nth-child(2)') + const itemLinks = $('footer > div:nth-child(2) > a:nth-child(1)') .toArray() - .map((div) => $(div).find('a').last().attr('href')); + .map((a) => $(a).attr('href')); + const items = await Promise.all( itemLinks.map(async (itemLink) => { if (new RegExp(`^/.+/photos/`).test(itemLink)) { diff --git a/lib/routes/gov/customs/list.js b/lib/routes/gov/customs/list.js index 7c7c04d39..06213f06d 100644 --- a/lib/routes/gov/customs/list.js +++ b/lib/routes/gov/customs/list.js @@ -10,7 +10,7 @@ module.exports = async (ctx) => { switch (gchannel) { case 'paimai': channelName = '拍卖信息'; - link = `http://www.customs.gov.cn/customs/302249/2476857/302309/index.html`; + link = `http://www.customs.gov.cn/customs/302249/302309/index.html`; break; case 'fagui': diff --git a/lib/routes/index.js b/lib/routes/index.js index e55db0c95..cef9fa9fc 100644 --- a/lib/routes/index.js +++ b/lib/routes/index.js @@ -61,11 +61,13 @@ module.exports = async (ctx) => { } else { showDebug = config.debugInfo === true || config.debugInfo === ctx.query.debug; } + const { disallowRobot } = config; const stats = await pidusage(process.pid); ctx.body = art(path.resolve(__dirname, '../views/welcome.art'), { showDebug, + disallowRobot, debug: [ config.nodeName ? { diff --git a/lib/routes/scoresaber/user.js b/lib/routes/scoresaber/user.js new file mode 100644 index 000000000..e2d54a4a3 --- /dev/null +++ b/lib/routes/scoresaber/user.js @@ -0,0 +1,44 @@ +const got = require('@/utils/got'); +const cheerio = require('cheerio'); + +module.exports = async (ctx) => { + const id = ctx.params.id; + const hostname = 'https://scoresaber.com'; + + const response = await got({ + method: 'get', + url: `${hostname}/u/${id}&sort=2`, + }); + + const $ = cheerio.load(response.data); + + const username = $('.is-5 a').text(); + const list = $('tbody tr').reverse(); + + const result1 = list + .map((index, item) => { + item = $(item); + const song = item.find('.songTop.pp').text(); + const mapper = item.find('.songTop.mapper').text(); + const rank = item.find('.rank').text(); + const time = new Date(item.find('.time').attr('title')).toLocaleString(); + const ppValue = item.find('.ppValue').text(); + const ppWeightedValue = item.find('.ppWeightedValue').text(); + const scoreBottom = item.find('.scoreBottom').text(); + + return { + title: `【${song}】${mapper} ${time} ${rank} PP:${ppValue}${ppWeightedValue} - ${scoreBottom}`, + description: $('.box:first-child').html(), + link: hostname + item.find('a').attr('href') + '?search=' + username, + pubDate: time, + author: 'scoresaber', + }; + }) + .get(); + + ctx.state.data = { + title: `${username}的ScoreSaber动态`, + link: `https://scoresaber.com/u/${id}&sort=2`, + item: result1, + }; +}; diff --git a/lib/routes/weatheralarm/index.js b/lib/routes/weatheralarm/index.js index f41b9815f..810601299 100644 --- a/lib/routes/weatheralarm/index.js +++ b/lib/routes/weatheralarm/index.js @@ -1,23 +1,25 @@ const got = require('@/utils/got'); -const cheerio = require('cheerio'); -const date = require('@/utils/date'); module.exports = async (ctx) => { - const alarmInfoURL = 'http://www.nmc.cn/f/alarm.html'; - const html = (await got.get(alarmInfoURL)).data; - const $ = cheerio.load(html); - const alarmElements = $('.alarmlist > div:not(.pagination)').toArray(); + const province = ctx.params.province || '&'; + const alarmInfoURL = `http://www.nmc.cn/rest/findAlarm?pageNo=1&pageSize=20&signaltype=&signallevel=&province=${province}`; + const response = await got({ + method: 'get', + url: alarmInfoURL, + }); + const data = response.data.data; + const list = data.page.list; ctx.state.data = { title: '中央气象台全国气象预警', - link: alarmInfoURL, - item: alarmElements.map((el) => { - const $el = $(el); - const $aEl = $el.find('a'); + link: `http://www.nmc.cn/publish/alarm.html`, + item: list.map((item) => { + const title = item.title; + const url = item.url; return { - title: $aEl.text(), - link: `http://www.nmc.cn${$aEl.attr('href')}`, - pubDate: date($el.find('.date').text(), 8), + title: `${title}`, + link: `http://www.nmc.cn${url}`, + pubDate: `${item.issuetime}`, }; }), }; diff --git a/lib/routes/youtube/utils.js b/lib/routes/youtube/utils.js index 0a9c1d67b..c796ae8c7 100644 --- a/lib/routes/youtube/utils.js +++ b/lib/routes/youtube/utils.js @@ -29,6 +29,7 @@ const youtubeUtils = { const res = await getYoutube().playlistItems.list({ part, playlistId: id, + maxResults: 50, // youtube api param value default is 5 }); return res; }, diff --git a/lib/views/welcome.art b/lib/views/welcome.art index 800409772..d3868592d 100644 --- a/lib/views/welcome.art +++ b/lib/views/welcome.art @@ -3,6 +3,9 @@ Welcome to RSSHub! + {{ if disallowRobot }} + + {{ /if }}