Merge remote-tracking branch 'origin/master' into feature/hono

This commit is contained in:
DIYgod 2024-02-26 22:51:20 +08:00
commit 765c6777f8
No known key found for this signature in database
26 changed files with 463 additions and 12 deletions

View File

@ -26,7 +26,7 @@ module.exports = async (ctx) => {
const message = response.data.code === -6 ? '对应 uid 的 Bilibili 用户的 Cookie 已过期' : response.data.message;
throw new Error(`Error code ${response.data.code}: ${message}`);
}
const list = response.data.data.list;
const list = response.data.data.list || [];
const out = list.map((item) => ({
title: item.title,

View File

@ -0,0 +1,3 @@
module.exports = {
'/': ['cnkmmk'],
};

13
lib/v2/lala/radar.js Normal file
View File

@ -0,0 +1,13 @@
module.exports = {
'lala.im': {
_name: '荒岛',
'.': [
{
title: '博客',
docs: 'https://docs.rsshub.app/routes/blog#huang-dao',
source: ['/'],
target: '/lala',
},
],
},
};

3
lib/v2/lala/router.js Normal file
View File

@ -0,0 +1,3 @@
module.exports = function (router) {
router.get('/', require('./rss'));
};

32
lib/v2/lala/rss.js Normal file
View File

@ -0,0 +1,32 @@
const got = require('@/utils/got');
const cheerio = require('cheerio');
module.exports = async (ctx) => {
const currentUrl = 'https://lala.im';
const response = await got(`${currentUrl}/feed`);
const $ = cheerio.load(response.data, { xmlMode: true });
const titleMain = $('channel > title').text();
const descriptionMain = $('channel > description').text();
const items = $('channel > item')
.map((_, item) => {
const $item = $(item);
const link = $item.find('link').text();
const title = $item.find('title').text();
const description = $item.find('description').text();
const pubDate = $item.find('pubDate').text();
return {
link,
pubDate, // no need to normalize because it's from a valid RSS feed
title,
description,
};
})
.get();
ctx.state.data = {
title: titleMain,
description: descriptionMain,
link: currentUrl,
item: items,
};
};

82
lib/v2/m4/index.js Normal file
View File

@ -0,0 +1,82 @@
const got = require('@/utils/got');
const cheerio = require('cheerio');
const timezone = require('@/utils/timezone');
const { parseDate } = require('@/utils/parse-date');
const { art } = require('@/utils/render');
const path = require('path');
module.exports = async (ctx) => {
const { id = 'news', category = 'china' } = ctx.params;
const limit = ctx.query.limit ? Number.parseInt(ctx.query.limit, 10) : 30;
const rootUrl = `http://${id}.m4.cn`;
const currentUrl = new URL(category ? `/${category.replace(/\/$/, '')}/` : '/', rootUrl).href;
const { data: response } = await got(currentUrl);
const $ = cheerio.load(response);
let items = $('div.articleitem0 div.aheader0')
.slice(0, limit)
.toArray()
.map((item) => {
item = $(item);
const a = item.find('a').first();
return {
title: a.text(),
link: a.prop('href'),
description: art(path.join(__dirname, 'templates/description.art'), {
images: [
{
src: item.parent().find('div.aimg0 a img').prop('src'),
alt: a.text(),
},
],
}),
category: item
.find('a.aclass')
.toArray()
.map((c) => $(c).text().replaceAll('[]', '').trim()),
pubDate: timezone(parseDate(item.find('span.atime').text()), +8),
};
});
items = await Promise.all(
items.map((item) =>
ctx.cache.tryGet(item.link, async () => {
const { data: detailResponse } = await got(item.link);
const content = cheerio.load(detailResponse);
item.title = content('h1').first().text();
item.description = art(path.join(__dirname, 'templates/description.art'), {
intro: content('div.aintro1, p.cont-summary').text(),
description: content('div.content0, div.cont-detail').html(),
});
item.category = content('span.dd0 a, a[rel="category"]')
.toArray()
.map((c) => content(c).text())
.slice(1);
item.pubDate = timezone(parseDate(content('span.atime1, span.post-time').text()), +8);
return item;
})
)
);
const image = $('a.logo0_b img').prop('src');
ctx.state.data = {
item: items,
title: $('title').text(),
link: currentUrl,
description: $('meta[name="description"]').prop('content'),
language: 'zh',
image,
subtitle: $('meta[name="keywords"]').prop('content'),
author: $('meta[name="author"]').prop('content'),
allowEmpty: true,
};
};

4
lib/v2/m4/maintainer.js Normal file
View File

@ -0,0 +1,4 @@
module.exports = {
'/mil/:category?': ['nczitzk'],
'/news/:category?': ['nczitzk'],
};

87
lib/v2/m4/radar.js Normal file
View File

@ -0,0 +1,87 @@
module.exports = {
'm4.cn': {
_name: '四月网',
news: [
{
title: '要闻 - 国内新闻',
docs: 'https://docs.rsshub.app/routes/new-media#si-yue-wang-yao-wen',
source: ['/china/'],
target: '/m4/news/china',
},
{
title: '要闻 - 国际新闻',
docs: 'https://docs.rsshub.app/routes/new-media#si-yue-wang-yao-wen',
source: ['/world/'],
target: '/m4/news/world',
},
{
title: '要闻 - 民生',
docs: 'https://docs.rsshub.app/routes/new-media#si-yue-wang-yao-wen',
source: ['/livelihood/'],
target: '/m4/news/livelihood',
},
{
title: '要闻 - 社会',
docs: 'https://docs.rsshub.app/routes/new-media#si-yue-wang-yao-wen',
source: ['/society/'],
target: '/m4/news/society',
},
{
title: '要闻 - 财经',
docs: 'https://docs.rsshub.app/routes/new-media#si-yue-wang-yao-wen',
source: ['/finance/'],
target: '/m4/news/finance',
},
{
title: '要闻 - 科技',
docs: 'https://docs.rsshub.app/routes/new-media#si-yue-wang-yao-wen',
source: ['/tech/'],
target: '/m4/news/tech',
},
],
mil: [
{
title: '军事 - 中国军情',
docs: 'https://docs.rsshub.app/routes/new-media#si-yue-wang-jun-shi',
source: ['/china/'],
target: '/m4/mil/china',
},
{
title: '军事 - 国际军情',
docs: 'https://docs.rsshub.app/routes/new-media#si-yue-wang-jun-shi',
source: ['/world/'],
target: '/m4/mil/world',
},
{
title: '军事 - 军事评论',
docs: 'https://docs.rsshub.app/routes/new-media#si-yue-wang-jun-shi',
source: ['/views/'],
target: '/m4/mil/views',
},
{
title: '军事 - 军事历史',
docs: 'https://docs.rsshub.app/routes/new-media#si-yue-wang-jun-shi',
source: ['/history/'],
target: '/m4/mil/history',
},
{
title: '军事 - 军迷说',
docs: 'https://docs.rsshub.app/routes/new-media#si-yue-wang-jun-shi',
source: ['/talk/'],
target: '/m4/mil/talk',
},
{
title: '军事 - 图说军事',
docs: 'https://docs.rsshub.app/routes/new-media#si-yue-wang-jun-shi',
source: ['/photo/'],
target: '/m4/mil/photo',
},
{
title: '军事 - 武器库',
docs: 'https://docs.rsshub.app/routes/new-media#si-yue-wang-jun-shi',
source: ['/arms/'],
target: '/m4/mil/arms',
},
],
},
};

3
lib/v2/m4/router.js Normal file
View File

@ -0,0 +1,3 @@
module.exports = (router) => {
router.get('/:id?/:category*', require('./'));
};

View File

@ -0,0 +1,21 @@
{{ if images }}
{{ each images image }}
{{ if image?.src }}
<figure>
<img
{{ if image.alt }}
alt="{{ image.alt }}"
{{ /if }}
src="{{ image.src }}">
</figure>
{{ /if }}
{{ /each }}
{{ /if }}
{{ if intro }}
<blockquote>{{ intro }}</blockquote>
{{ /if }}
{{ if description }}
{{@ description }}
{{ /if }}

View File

@ -0,0 +1,3 @@
module.exports = {
'/news/:category': ['Duuckjing'],
};

64
lib/v2/shisu/news.js Normal file
View File

@ -0,0 +1,64 @@
const got = require('@/utils/got');
const cheerio = require('cheerio');
const { parseDate } = require('@/utils/parse-date');
const timezone = require('@/utils/timezone');
const url = 'https://news.shisu.edu.cn';
const banner = 'https://news.shisu.edu.cn/news/index/39adf3d9ae414bc39c6d3b9316ae531f.png';
module.exports = async (ctx) => {
const { section = 'news' } = ctx.params;
const { data: r } = await got(`${url}/${section}/index.html`);
const $ = cheerio.load(r);
let itemsoup;
switch (section) {
case 'news':
itemsoup = $('#gallery-wrapper > article')
.toArray()
.map((i0) => {
const i = $(i0);
const img = i.find('img').attr('src');
return {
title: i.find('a').text().trim(),
link: `${url}${i.find('a').attr('href')}`,
category: i.find('.in-con02 > span:nth-child(1)').text(),
itunes_item_image: `${url}${img}`,
};
});
break;
default:
itemsoup = $('li.clear')
.toArray()
.map((i0) => {
const i = $(i0);
return {
title: i.find('h3>a').attr('title').trim(),
link: `${url}${i.find('h3>a').attr('href')}`,
category: i.find('p>span:nth-child(1)').text(),
};
});
}
const items = await Promise.all(
itemsoup.map((j) =>
ctx.cache.tryGet(j.link, async () => {
const { data: r } = await got(j.link);
const $ = cheerio.load(r);
const img = $('.tempWrap > ul > li:nth-child(1)> img').attr('src');
j.description = $('.ot_main_r .content').html();
j.author = $('.math_time_l > span:nth-child(3)').text().trim();
j.pubDate = timezone(parseDate($('.math_time_l > span:nth-child(2)').text(), 'YYYY-MM-DD'), +8);
if (!j.itunes_item_image) {
j.itunes_item_image = img ? `${url}${img}` : banner;
}
return j;
})
)
);
ctx.state.data = {
title: `上外新闻|SISU TODAY -${section.charAt(0).toUpperCase() + section.slice(1)}`,
image: 'https://bkimg.cdn.bcebos.com/pic/8d5494eef01f3a296b70affa9825bc315c607c4d?x-bce-process=image/resize,m_lfit,w_536,limit_1/quality,Q_70',
link: `${url}/${section}/index.html`,
item: items,
};
};

13
lib/v2/shisu/radar.js Normal file
View File

@ -0,0 +1,13 @@
module.exports = {
'shisu.edu.cn': {
_name: '上海外国语大学',
news: [
{
title: '上外新闻',
docs: 'https://docs.rsshub.app/routes/university#shang-hai-wai-guo-yu-da-xue',
source: ['/:category/index.html'],
target: '/shisu/news/:category',
},
],
},
};

3
lib/v2/shisu/router.js Normal file
View File

@ -0,0 +1,3 @@
module.exports = (router) => {
router.get('/news/:category', require('./news'));
};

View File

@ -2,7 +2,7 @@ const got = require('@/utils/got');
const cheerio = require('cheerio');
module.exports = async (ctx) => {
const type = ctx.params.type;
const { type, keywoard, preview } = ctx.params;
// should be:
// undefined
// U3C3
@ -15,13 +15,12 @@ module.exports = async (ctx) => {
const rootURL = 'https://www.u3c3.com';
let currentURL;
let title;
if (type === undefined) {
if (keywoard) {
currentURL = `${rootURL}/?search=${keywoard}`;
title = `search ${keywoard} - u3c3`;
} else if (type === undefined) {
currentURL = rootURL;
title = 'home - u3c3';
} else if (type === 'search') {
const keyword = ctx.params.keyword === undefined ? '' : ctx.params.keyword;
currentURL = `${rootURL}/?search=${keyword}`;
title = `search ${keyword} - u3c3`;
} else {
currentURL = `${rootURL}/?type=${type}&p=1`;
title = `${type} - u3c3`;
@ -30,7 +29,7 @@ module.exports = async (ctx) => {
const response = await got(currentURL);
const $ = cheerio.load(response.data);
const items = $('body > div.container > div.table-responsive > table > tbody > tr')
const list = $('body > div.container > div.table-responsive > table > tbody > tr')
.toArray()
.map((item) => {
item = $(item);
@ -50,6 +49,21 @@ module.exports = async (ctx) => {
};
});
const items = preview
? await Promise.all(
list.map((item) =>
ctx.cache.tryGet(item.link, async () => {
const { data: response } = await got(item.link);
const $ = cheerio.load(response);
item.description = $('div.panel-footer > img:first-child').parent().html();
return item;
})
)
)
: list;
ctx.state.data = {
title,
description: title,

View File

@ -1,3 +1,4 @@
module.exports = {
'/:type?/:keyword?': ['noname1897'],
'/search/:keyword/:preview?': ['storytellerF'],
'/:type?/:preview?': ['noname1897', 'storytellerF'],
};

View File

@ -1,3 +1,4 @@
module.exports = function (router) {
router.get('/:type?/:keyword?', require('./index'));
router.get('/search/:keyword/:preview?', require('./index'));
router.get('/:type?/:preview?', require('./index'));
};

View File

@ -0,0 +1,35 @@
const got = require('@/utils/got');
const { parseDate } = require('@/utils/parse-date');
const appFeedUrl = 'https://raw.githubusercontent.com/Squidly271/AppFeed/master/applicationFeed.json';
const defaultLimit = 20;
module.exports = async (ctx) => {
const { data } = await got(appFeedUrl);
const limit = ctx.query.limit ? Number.parseInt(ctx.query.limit) : defaultLimit;
let appList = data.applist;
appList = appList.map((app) => {
const _pubDate = app.LastUpdate ?? app.FirstSeen ?? 0;
return {
...app,
_pubDate,
};
});
appList.sort((a, b) => b._pubDate - a._pubDate);
const returnedAppList = appList.slice(0, limit);
ctx.state.data = {
title: 'Unraid Community Apps',
link: 'https://unraid.net/community/apps',
image: 'https://craftassets.unraid.net/static/favicon/favicon.ico?v=1.0',
item: returnedAppList.map((app) => ({
title: `${app.Name} (${app.Repository ?? 'Unknown repository'})`,
link: app.Registry ?? `https://unraid.net/community/apps?q=${app.Name}`,
description: app.Overview.replaceAll('\r\n', '<br>').replaceAll('\n', '<br>').replaceAll('[br]', '<br>'),
pubDate: parseDate(app._pubDate * 1000),
category: app.CategoryList,
upvotes: app.stars,
})),
};
};

View File

@ -0,0 +1,3 @@
module.exports = {
'/community-apps': ['KTachibanaM'],
};

13
lib/v2/unraid/radar.js Normal file
View File

@ -0,0 +1,13 @@
module.exports = {
'unraid.net': {
_name: 'Unraid',
'.': [
{
title: 'Community Apps',
docs: 'https://docs.rsshub.app/routes/program-update#unraid',
source: ['/community/apps'],
target: '/unraid/community-apps',
},
],
},
};

3
lib/v2/unraid/router.js Normal file
View File

@ -0,0 +1,3 @@
module.exports = (router) => {
router.get('/community-apps', require('./community-apps'));
};

View File

@ -340,6 +340,12 @@
<Route author="wxluckly" example="/xunhupay/blog" path="/xunhupay/blog" radar="1" />
## 荒岛 {#huang-dao}
### 博客 {#huang-dao-bo-ke}
<Route author="cnkmmk" example="/lala" path="/lala" />
## 劍心.回憶 {#jian-xin-hui-yi}
### 分类 {#jian-xin-hui-yi-fen-lei}

View File

@ -1198,11 +1198,11 @@ Refer to [https://developers.themoviedb.org/3/getting-started/languages](https:/
### Keyword Search {#u3c3-keyword-search}
<Route author="noname1897" example="/u3c3/search/les" path="/u3c3/search/:keyword?" paramsDesc={['search keyword']} supportBT="1" radar="1" />
<Route author="noname1897" example="/u3c3/search/les" path="/u3c3/search/:keyword/:preview?" paramsDesc={['search keyword', 'Show image preview, off by default, non empty value means on']} supportBT="1" radar="1" />
### Type {#u3c3-type}
<Route author="noname1897" example="/u3c3/U3C3" path="/u3c3/:type?" paramsDesc={['type, pay attention to case, it should be exactly same as the choices: `U3C3`/`Video`/`Photo`/`Book`/`Game`/`Software`/`Other`, if no type is provided, show the home index']} supportBT="1" radar="1" />
<Route author="noname1897" example="/u3c3/U3C3" path="/u3c3/:type?/:preview?" paramsDesc={['type, pay attention to case, it should be exactly same as the choices: `U3C3`/`Video`/`Photo`/`Book`/`Game`/`Software`/`Other`, if no type is provided, show the home index','Show image preview, off by default, non empty value means on']} supportBT="1" radar="1" />
## U9A9 {#u9a9}

View File

@ -4328,6 +4328,34 @@
<Route author="nczitzk" example="/shuiguopai" path="/shuiguopai" radar="1" />
## 四月网 {#si-yue-wang}
### 要闻 {#si-yue-wang-yao-wen}
<Route author="nczitzk" example="/m4/news/china" path="/m4/news/:category?" paramsDesc={['分类,见下表,默认为国内新闻']} radar="1">
| 分类 | ID |
| ------------------------------------- | ---------- |
| [国内新闻](http://news.m4.cn/china/) | china |
| [国际新闻](http://news.m4.cn/world/) | world |
| [民生](http://news.m4.cn/livelihood/) | livelihood |
| [社会](http://news.m4.cn/society/) | society |
| [财经](http://news.m4.cn/finance/) | finance |
| [科技](http://news.m4.cn/tech/) | tech |
</Route>
### 军事 {#si-yue-wang-jun-shi}
<Route author="nczitzk" example="/m4/mil/china" path="/m4/mil/:category?" paramsDesc={['分类,见下表,默认为中国军情']} radar="1">
| 分类 | ID |
| ------------------------------------- | ------- |
| [中国军情](http://mil.m4.cn/china/) | china |
| [国际军情](http://mil.m4.cn/world/) | world |
| [军事评论](http://mil.m4.cn/views/) | views |
| [军事历史](http://mil.m4.cn/history/) | history |
| [军迷说](http://mil.m4.cn/talk/) | talk |
| [武器库](http://mil.m4.cn/arms/) | arms |
</Route>
## 搜狐号 {#sou-hu-hao}
### 更新 {#sou-hu-hao-geng-xin}

View File

@ -643,6 +643,12 @@ Logseq 开发团队已经放弃了 [旧网站](https://logseq.com/blog)。
<Route author="nczitzk" example="/typora/changelog/dev" path="/typora/changelog/dev" radar="1" />
## Unraid {#unraid}
### Community Apps {#unraid-community-apps}
<Route author="KTachibanaM" example="/unraid/community-apps" path="/unraid/community-apps" radar="1" />
## Western Digital {#western-digital}
### Download {#western-digital-download}

View File

@ -2625,6 +2625,16 @@ jsjxy.hbut.edu.cn 证书链不全,自建 RSSHub 可设置环境变量 NODE\_TL
| 1793 | sstmzs |
</Route>
## 上海外国语大学 {#shang-hai-wai-guo-yu-da-xue}
### 上外新闻 {#shang-hai-wai-guo-yu-da-xue-shang-wai-xin-wen}
<Route author="Duuckjing" example="/shisu/news/notice" path="/shisu/news/:category" paramsDesc={['新闻的分类可根据自己的需要选择,首页为全部新闻']} radar="1">
| 首页 | 特稿 | 学术 | 教学 | 国际 | 校园 | 人物 | 视讯 | 公告 |
| ---- | ------- | --------- | ---------- | ------------- | ------ | ------ | ---------- | ------ |
| news | gazette | research- | academics- | international | campus | people | multimedia | notice |
</Route>
## 深圳大学 {#shen-zhen-da-xue}
### 研究生招生网 {#shen-zhen-da-xue-yan-jiu-sheng-zhao-sheng-wang}