mirror of
https://github.com/DIYgod/RSSHub.git
synced 2025-12-19 06:38:55 +08:00
fix(route): luogu (#11064)
This commit is contained in:
@@ -958,15 +958,15 @@ GitHub 官方也提供了一些 RSS:
|
||||
|
||||
### 日报
|
||||
|
||||
<Route author="LogicJake prnake nczitzk" example="/luogu/daily" path="/luogu/daily/:id?" :paramsDesc="['年度日报所在帖子 id,可在 URL 中找到,不填默认为 2020 年日报']"/>
|
||||
<Route author="LogicJake prnake nczitzk" example="/luogu/daily" path="/luogu/daily/:id?" :paramsDesc="['年度日报所在帖子 id,可在 URL 中找到,不填默认为 `47327`']" radar="1" rssbud="1"/>
|
||||
|
||||
### 近期比赛
|
||||
### 比赛列表
|
||||
|
||||
<Route author="prnake" example="/luogu/contest" path="/luogu/contest"/>
|
||||
<Route author="prnake" example="/luogu/contest" path="/luogu/contest" radar="1" rssbud="1"/>
|
||||
|
||||
### 用户动态
|
||||
|
||||
<Route author="solstice23" example="/luogu/user/feed/1" path="/luogu/user/feed/:uid" :paramsDesc="['用户 UID']"/>
|
||||
<Route author="solstice23" example="/luogu/user/feed/1" path="/luogu/user/feed/:uid" :paramsDesc="['用户 UID']" radar="1" rssbud="1"/>
|
||||
|
||||
## 码农俱乐部
|
||||
|
||||
|
||||
@@ -1356,9 +1356,9 @@ router.get('/ui-cn/user/:id', lazyloadRouteHandler('./routes/ui-cn/user'));
|
||||
router.get('/bjp/apod', lazyloadRouteHandler('./routes/bjp/apod'));
|
||||
|
||||
// 洛谷
|
||||
router.get('/luogu/daily/:id?', lazyloadRouteHandler('./routes/luogu/daily'));
|
||||
router.get('/luogu/contest', lazyloadRouteHandler('./routes/luogu/contest'));
|
||||
router.get('/luogu/user/feed/:uid', lazyloadRouteHandler('./routes/luogu/userFeed'));
|
||||
// router.get('/luogu/daily/:id?', lazyloadRouteHandler('./routes/luogu/daily'));
|
||||
// router.get('/luogu/contest', lazyloadRouteHandler('./routes/luogu/contest'));
|
||||
// router.get('/luogu/user/feed/:uid', lazyloadRouteHandler('./routes/luogu/userFeed'));
|
||||
|
||||
// 决胜网
|
||||
router.get('/juesheng', lazyloadRouteHandler('./routes/juesheng'));
|
||||
|
||||
@@ -1,28 +0,0 @@
|
||||
const got = require('@/utils/got');
|
||||
const cheerio = require('cheerio');
|
||||
const resolve_url = require('url').resolve;
|
||||
|
||||
module.exports = async (ctx) => {
|
||||
const link = 'https://www.luogu.com.cn/';
|
||||
const response = await got.get(link);
|
||||
const $ = cheerio.load(response.data);
|
||||
const title = '洛谷近期比赛';
|
||||
|
||||
const out = $('.am-panel-hd ')
|
||||
.slice(0, 10)
|
||||
.map(function () {
|
||||
const info = {
|
||||
title: $(this).find('a').text() || $(this).text(),
|
||||
description: $(this).html() + $(this).parent().find('.am-panel-bd').html(),
|
||||
link: resolve_url('https://www.luogu.com.cn', $(this).find('a').attr('href')),
|
||||
};
|
||||
return info;
|
||||
})
|
||||
.get();
|
||||
|
||||
ctx.state.data = {
|
||||
title,
|
||||
link,
|
||||
item: out,
|
||||
};
|
||||
};
|
||||
@@ -1,53 +0,0 @@
|
||||
const got = require('@/utils/got');
|
||||
const cheerio = require('cheerio');
|
||||
|
||||
module.exports = async (ctx) => {
|
||||
const id = ctx.params.id || 179788;
|
||||
const link = `https://www.luogu.org/discuss/show/${id}`;
|
||||
const response = await got.get(link);
|
||||
const $ = cheerio.load(response.data);
|
||||
const title = $('title').text();
|
||||
|
||||
const out = $('div.am-comment-main > div > p')
|
||||
.slice(0, 10)
|
||||
.map(function () {
|
||||
const info = {
|
||||
title: $(this).find('strong').text() || $(this).text(),
|
||||
link: $(this).find('a').attr('href'),
|
||||
};
|
||||
return info;
|
||||
})
|
||||
.get();
|
||||
|
||||
const items = await Promise.all(
|
||||
out.map((item) =>
|
||||
ctx.cache.tryGet(item.link, async () => {
|
||||
const detailResponse = await got({
|
||||
method: 'get',
|
||||
url: item.link,
|
||||
});
|
||||
const content = cheerio.load(detailResponse.data);
|
||||
const timeRegExp = new RegExp(/(?<=([1-9]\d{3}-(0[1-9]|1[0-2])-(0[1-9]|[1-2][0-9]|3[0-1])\s+(20|21|22|23|[0-1]\d):[0-5]\d:[0-5]\d))/);
|
||||
|
||||
item.description = content('#article-content').html();
|
||||
|
||||
content('#article-content').remove();
|
||||
|
||||
const line = content
|
||||
.html()
|
||||
.split('\n')
|
||||
.find((line) => timeRegExp.test(line));
|
||||
|
||||
item.pubDate = new Date(line.match(timeRegExp)[1] + ' GMT+8').toUTCString();
|
||||
|
||||
return item;
|
||||
})
|
||||
)
|
||||
);
|
||||
|
||||
ctx.state.data = {
|
||||
title,
|
||||
link,
|
||||
item: items,
|
||||
};
|
||||
};
|
||||
@@ -1,38 +0,0 @@
|
||||
const got = require('@/utils/got');
|
||||
|
||||
module.exports = async (ctx) => {
|
||||
const getUsernameFromUID = async (uid) => {
|
||||
const key = 'luogu-username-from-uid-' + uid;
|
||||
let name = await ctx.cache.get(key);
|
||||
if (!name) {
|
||||
const nameResponse = await got({
|
||||
method: 'get',
|
||||
url: `https://www.luogu.com.cn/user/${uid}?_contentOnly=1`,
|
||||
});
|
||||
name = nameResponse.data.currentData.user.name;
|
||||
ctx.cache.set(key, name);
|
||||
}
|
||||
return name;
|
||||
};
|
||||
|
||||
const uid = ctx.params.uid;
|
||||
const name = await getUsernameFromUID(uid);
|
||||
const response = await got({
|
||||
method: 'get',
|
||||
url: `https://www.luogu.com.cn/api/feed/list?user=${uid}`,
|
||||
});
|
||||
const data = response.data.feeds.result;
|
||||
|
||||
ctx.state.data = {
|
||||
title: `${name} 的洛谷动态`,
|
||||
link: `https://www.luogu.com.cn/user/${uid}#activity`,
|
||||
allowEmpty: true,
|
||||
item: data.map((item) => ({
|
||||
title: item.content,
|
||||
description: item.content,
|
||||
pubDate: new Date(item.time * 1000).toUTCString(),
|
||||
link: `https://www.luogu.com.cn/user/${uid}#activity`,
|
||||
guid: item.id,
|
||||
})),
|
||||
};
|
||||
};
|
||||
72
lib/v2/luogu/contest.js
Normal file
72
lib/v2/luogu/contest.js
Normal file
@@ -0,0 +1,72 @@
|
||||
const got = require('@/utils/got');
|
||||
const cheerio = require('cheerio');
|
||||
const md = require('markdown-it')();
|
||||
const { parseDate } = require('@/utils/parse-date');
|
||||
const asyncPool = require('tiny-async-pool');
|
||||
|
||||
const baseUrl = 'https://www.luogu.com.cn';
|
||||
|
||||
const typeMap = {
|
||||
ruleType: {
|
||||
1: 'OI',
|
||||
2: 'ACM',
|
||||
3: '乐多',
|
||||
4: 'IOI',
|
||||
},
|
||||
visibilityType: {
|
||||
1: '官方比赛',
|
||||
2: '团队公开赛',
|
||||
4: '个人公开赛',
|
||||
},
|
||||
// invitationCodeType: {
|
||||
// 1: '',
|
||||
// 2: '',
|
||||
// },
|
||||
};
|
||||
|
||||
module.exports = async (ctx) => {
|
||||
const link = `${baseUrl}/contest/list`;
|
||||
const { data: response } = await got(link);
|
||||
const $ = cheerio.load(response);
|
||||
|
||||
const data = JSON.parse(
|
||||
decodeURIComponent(
|
||||
$('script')
|
||||
.text()
|
||||
.match(/decodeURIComponent\("(.*)"\)/)[1]
|
||||
)
|
||||
);
|
||||
|
||||
const result = [];
|
||||
for await (const item of asyncPool(4, data.currentData.contests.result, (item) =>
|
||||
ctx.cache.tryGet(`${baseUrl}/contest/${item.id}`, async () => {
|
||||
const { data: response } = await got(`${baseUrl}/contest/${item.id}`);
|
||||
const $ = cheerio.load(response);
|
||||
const data = JSON.parse(
|
||||
decodeURIComponent(
|
||||
$('script')
|
||||
.text()
|
||||
.match(/decodeURIComponent\("(.*)"\)/)[1]
|
||||
)
|
||||
);
|
||||
|
||||
return {
|
||||
title: item.name,
|
||||
description: md.render(data.currentData.contest.description),
|
||||
link: `${baseUrl}/contest/${item.id}`,
|
||||
author: item.host.name,
|
||||
pubDate: parseDate(item.startTime, 'X'),
|
||||
category: [item.rated ? 'Rated' : null, typeMap.ruleType[item.ruleType], typeMap.visibilityType[item.visibilityType]].filter((i) => i),
|
||||
};
|
||||
})
|
||||
)) {
|
||||
result.push(item);
|
||||
}
|
||||
|
||||
ctx.state.data = {
|
||||
title: $('head title').text(),
|
||||
link,
|
||||
image: 'https://www.luogu.com.cn/favicon.ico',
|
||||
item: result,
|
||||
};
|
||||
};
|
||||
33
lib/v2/luogu/daily.js
Normal file
33
lib/v2/luogu/daily.js
Normal file
@@ -0,0 +1,33 @@
|
||||
const got = require('@/utils/got');
|
||||
const cheerio = require('cheerio');
|
||||
const { parseDate } = require('@/utils/parse-date');
|
||||
|
||||
module.exports = async (ctx) => {
|
||||
const id = ctx.params.id ?? 47327;
|
||||
const link = `https://www.luogu.com.cn/discuss/${id}`;
|
||||
const response = await got(link);
|
||||
const $ = cheerio.load(response.data);
|
||||
const title = $('head title').text();
|
||||
|
||||
const firstPost = $('.am-comment-main .am-comment-bd').first();
|
||||
const dailyLink = firstPost.find('a').first().attr('href');
|
||||
const issueHeading = firstPost.find('h1').text().trim();
|
||||
const { data: dailyResponse } = await got(dailyLink);
|
||||
const $daily = cheerio.load(dailyResponse);
|
||||
const item = [
|
||||
{
|
||||
title,
|
||||
description: $daily('#article-content').html(),
|
||||
link,
|
||||
author: firstPost.find('p').eq(1).text(),
|
||||
guid: `${link}#${issueHeading}`,
|
||||
pubDate: parseDate(issueHeading.match(/(\d{4} 年 \d{2} 月 \d{2} 日)/)[1], 'YYYY 年 MM 月 DD 日'),
|
||||
},
|
||||
];
|
||||
|
||||
ctx.state.data = {
|
||||
title: '洛谷日报',
|
||||
link,
|
||||
item,
|
||||
};
|
||||
};
|
||||
5
lib/v2/luogu/maintainer.js
Normal file
5
lib/v2/luogu/maintainer.js
Normal file
@@ -0,0 +1,5 @@
|
||||
module.exports = {
|
||||
'/contest': ['prnake'],
|
||||
'/daily/:id?': ['LogicJake ', 'prnake ', 'nczitzk'],
|
||||
'/user/feed/:uid': ['solstice23'],
|
||||
};
|
||||
25
lib/v2/luogu/radar.js
Normal file
25
lib/v2/luogu/radar.js
Normal file
@@ -0,0 +1,25 @@
|
||||
module.exports = {
|
||||
'luogu.com.cn': {
|
||||
_name: '洛谷',
|
||||
'.': [
|
||||
{
|
||||
title: '日报',
|
||||
docs: 'https://docs.rsshub.app/programming.html#luo-gu',
|
||||
source: ['/discuss/47327', '/'],
|
||||
target: '/luogu/daily',
|
||||
},
|
||||
{
|
||||
title: '比赛列表',
|
||||
docs: 'https://docs.rsshub.app/programming.html#luo-gu',
|
||||
source: ['/contest/list', '/'],
|
||||
target: '/luogu/contest',
|
||||
},
|
||||
{
|
||||
title: '用户动态',
|
||||
docs: 'https://docs.rsshub.app/programming.html#luo-gu',
|
||||
source: ['/user/:uid'],
|
||||
target: '/luogu/user/feed/:uid',
|
||||
},
|
||||
],
|
||||
},
|
||||
};
|
||||
5
lib/v2/luogu/router.js
Normal file
5
lib/v2/luogu/router.js
Normal file
@@ -0,0 +1,5 @@
|
||||
module.exports = (router) => {
|
||||
router.get('/contest', require('./contest'));
|
||||
router.get('/daily/:id?', require('./daily'));
|
||||
router.get('/user/feed/:uid', require('./userFeed'));
|
||||
};
|
||||
30
lib/v2/luogu/userFeed.js
Normal file
30
lib/v2/luogu/userFeed.js
Normal file
@@ -0,0 +1,30 @@
|
||||
const got = require('@/utils/got');
|
||||
const { parseDate } = require('@/utils/parse-date');
|
||||
const md = require('markdown-it')();
|
||||
|
||||
module.exports = async (ctx) => {
|
||||
const getUsernameFromUID = (uid) =>
|
||||
ctx.cache.tryGet('luogu:username:' + uid, async () => {
|
||||
const { data } = await got(`https://www.luogu.com.cn/user/${uid}?_contentOnly=1`);
|
||||
return data.currentData.user.name;
|
||||
});
|
||||
|
||||
const uid = ctx.params.uid;
|
||||
const name = await getUsernameFromUID(uid);
|
||||
const { data: response } = await got(`https://www.luogu.com.cn/api/feed/list?user=${uid}`);
|
||||
|
||||
const data = response.feeds.result;
|
||||
|
||||
ctx.state.data = {
|
||||
title: `${name} 的洛谷动态`,
|
||||
link: `https://www.luogu.com.cn/user/${uid}#activity`,
|
||||
allowEmpty: true,
|
||||
item: data.map((item) => ({
|
||||
title: item.content,
|
||||
description: md.render(item.content),
|
||||
pubDate: parseDate(item.time, 'X'),
|
||||
author: name,
|
||||
link: `https://www.luogu.com.cn/user/${uid}#activity`,
|
||||
})),
|
||||
};
|
||||
};
|
||||
Reference in New Issue
Block a user