diff --git a/docs/bbs.md b/docs/bbs.md
index 87e67c665..8a5f05011 100644
--- a/docs/bbs.md
+++ b/docs/bbs.md
@@ -16,10 +16,20 @@ pageClass: routes
## Discuz
-### 通用子版块
+### 通用子版块-自动检测
+### 通用子版块-指定版本
+
+
+
+| Discuz X 系列 | Discuz 7.x 系列 |
+| ------------- | --------------- |
+| x | 7 |
+
+
+
## MCBBS
### 版块
diff --git a/docs/en/bbs.md b/docs/en/bbs.md
index 0bb45d43e..1b6caa887 100644
--- a/docs/en/bbs.md
+++ b/docs/en/bbs.md
@@ -3,3 +3,19 @@ pageClass: routes
---
# BBS
+
+## Discuz
+
+### General Subforum - Auto detection
+
+
+
+### General Subforum - Manual version
+
+
+
+| Discuz X Series | Discuz 7.x Series |
+| --------------- | ----------------- |
+| x | 7 |
+
+
diff --git a/docs/program-update.md b/docs/program-update.md
index 77db90e03..c8d9339b7 100644
--- a/docs/program-update.md
+++ b/docs/program-update.md
@@ -60,7 +60,7 @@ pageClass: routes
### 扩展程序更新
-
## CurseForge
diff --git a/docs/reading.md b/docs/reading.md
index 436ecb08a..ce40073f3 100644
--- a/docs/reading.md
+++ b/docs/reading.md
@@ -176,6 +176,16 @@ pageClass: routes
+## 虛詞
+
+### 版块
+
+
+
+### 作者
+
+
+
## 纵横
### 章节
diff --git a/docs/shopping.md b/docs/shopping.md
index 1fdcfa716..ef87cfac6 100644
--- a/docs/shopping.md
+++ b/docs/shopping.md
@@ -42,6 +42,16 @@ For instance, in https://www.leboncoin.fr/recherche/?**category=10&locations=Par
+## 好好住
+
+### 整屋案例
+
+
+
+### 发现
+
+
+
## 京东众筹
### 众筹项目
diff --git a/docs/university.md b/docs/university.md
index be0e71234..cf2247704 100644
--- a/docs/university.md
+++ b/docs/university.md
@@ -247,6 +247,18 @@ xskb1 对应 http://www.auto.uestc.edu.cn/index/xskb1.htm
+## 东北大学
+
+### 东北大学新闻网
+
+
+
+| 东大要闻 | 媒体东大 | 通知公告 | 新闻纵横 | 人才培养 | 学术科研 | 英文新闻 | 招生就业 | 考研出国 | 校园文学 | 校友风采 |
+| -------- | -------- | -------- | -------- | -------: | -------- | -------- | -------- | -------- | -------- | -------- |
+| ddyw | mtdd | tzgg | xwzh | rcpy | xsky | 217 | zsjy | kycg | xywx | xyfc |
+
+
+
## 东莞理工学院
### 教务处通知
@@ -1177,6 +1189,18 @@ https://rsshub.app/**nuist**/`bulletin` 或 https://rsshub.app/**nuist**/`bullet
+## 中国海洋大学
+
+### 信息科学与工程学院
+
+
+
+| 学院要闻 | 学院公告 | 学院活动 |
+| -------- | -------- | -------- |
+| 0 | 1 | 2 |
+
+
+
## 中国科学院
### 上海微系统与信息技术研究所学术活动
diff --git a/lib/router.js b/lib/router.js
index 49fd03ac1..b1dcd088b 100644
--- a/lib/router.js
+++ b/lib/router.js
@@ -695,6 +695,9 @@ router.get('/sdu/cmse/:type?', require('./routes/universities/sdu/cmse'));
router.get('/sdu/mech/:type?', require('./routes/universities/sdu/mech'));
router.get('/sdu/epe/:type?', require('./routes/universities/sdu/epe'));
+// 中国海洋大学
+router.get('/ouc/it/:type?', require('./routes/universities/ouc/it'));
+
// 大连大学
router.get('/dlu/jiaowu/news', require('./routes/universities/dlu/jiaowu/news'));
@@ -2152,6 +2155,7 @@ router.get('/gbcc/trust', require('./routes/gbcc/trust'));
router.get('/apnews/topics/:topic', require('./routes/apnews/topics'));
// discuz
+router.get('/discuz/:ver([7|x])/:link(.*)', require('./routes/discuz/discuz'));
router.get('/discuz/:link(.*)', require('./routes/discuz/discuz'));
// China Dialogue 中外对话
@@ -2232,4 +2236,15 @@ router.get('/2048/bbs/:fid', require('./routes/2048/bbs'));
// Google News
router.get('/google/news/:category/:locale', require('./routes/google/news'));
+// 虛詞
+router.get('/p-articles/section/:section', require('./routes/p-articles/section'));
+router.get('/p-articles/contributors/:author', require('./routes/p-articles/contributors'));
+
+// 好好住
+router.get('/haohaozhu/whole-house/:keyword?', require('./routes/haohaozhu/whole-house'));
+router.get('/haohaozhu/discover/:keyword?', require('./routes/haohaozhu/discover'));
+
+// 东北大学
+router.get('/neu/news/:type', require('./routes/universities/neu/news'));
+
module.exports = router;
diff --git a/lib/routes/discuz/discuz.js b/lib/routes/discuz/discuz.js
index 197f96182..a14ec0c9a 100644
--- a/lib/routes/discuz/discuz.js
+++ b/lib/routes/discuz/discuz.js
@@ -44,6 +44,7 @@ async function load(baseUrl, itemLink, ctx, charset) {
module.exports = async (ctx) => {
let link = ctx.params.link;
+ const ver = ctx.params.ver ? ctx.params.ver.toUpperCase() : undefined;
link = link.replace(/:\/\//, ':/').replace(/:\//, '://');
const response = await got.get(link);
@@ -52,18 +53,18 @@ module.exports = async (ctx) => {
let charset = 'utf-8';
for (const attr of contentType.split(';')) {
if (attr.indexOf('charset=') >= 0) {
- charset = attr.split('=').pop();
+ charset = attr
+ .split('=')
+ .pop()
+ .toLowerCase();
}
}
const responseData = charset === 'utf-8' ? response.data : iconv.decode((await got.get({ url: link, responseType: 'buffer' })).data, charset);
const $ = cheerio.load(responseData);
const title = $('head > title').text();
+ const version = ver ? 'DISCUZ! ' + ver : $('head > meta[name=generator]').attr('content');
let process;
- if (
- $('div#footer p em')
- .text()
- .startsWith('7')
- ) {
+ if (version.toUpperCase().startsWith('DISCUZ! 7')) {
// discuz 7.x 系列
// 支持全文抓取,限制抓取页面5个
const list = $('tbody[id^="normalthread"] tr')
@@ -82,12 +83,7 @@ module.exports = async (ctx) => {
return Promise.resolve(Object.assign({}, single, detail));
})
);
- } else if (
- $('div#frt p em')
- .text()
- .toUpperCase()
- .startsWith('X')
- ) {
+ } else if (version.toUpperCase().startsWith('DISCUZ! X')) {
// discuz X 系列
// 支持全文抓取,限制抓取页面5个
const list = $('tbody[id^="normalthread"] tr')
diff --git a/lib/routes/dsndsht23/index.js b/lib/routes/dsndsht23/index.js
index e3ff5c431..d7c656f44 100644
--- a/lib/routes/dsndsht23/index.js
+++ b/lib/routes/dsndsht23/index.js
@@ -21,18 +21,13 @@ const forumIdMaps = {
module.exports = async (ctx) => {
const subformName = ctx.params.subforumid || 'gqzwzm';
const subformId = subformName in forumIdMaps ? forumIdMaps[subformName] : subformName;
- const typefilter = ctx.params.type ? `&filter=type&typeid=${ctx.params.type}` : '';
+ const typefilter = ctx.params.type ? `&filter=typeid&typeid=${ctx.params.type}` : '';
const link = `${host}forum.php?mod=forumdisplay&fid=${subformId}${typefilter}`;
const response = await got.get(link);
const $ = cheerio.load(response.data);
- const list = $('#threadlisttableid tbody')
- .slice(1, 21)
- .filter(function() {
- // 去除置顶帖子和分割线
- const threadID = $(this).attr('id');
- return typeof threadID !== 'undefined' && threadID !== 'separatorline' && !threadID.startsWith('stickthread');
- })
+ const list = $('#threadlisttableid tbody[id^=normalthread]')
+ .slice(0, 11)
.map(function() {
const info = {
title:
diff --git a/lib/routes/github/file.js b/lib/routes/github/file.js
index 660944928..06d0cf959 100644
--- a/lib/routes/github/file.js
+++ b/lib/routes/github/file.js
@@ -1,5 +1,6 @@
const got = require('@/utils/got');
const config = require('@/config').value;
+const queryString = require('query-string');
module.exports = async (ctx) => {
const user = ctx.params.user;
@@ -14,6 +15,10 @@ module.exports = async (ctx) => {
headers.Authorization = `token ${config.github.access_token}`;
}
const res = await got.get(`https://api.github.com/repos/${user}/${repo}/commits`, {
+ searchParams: queryString.stringify({
+ sha: branch,
+ path: filepath,
+ }),
headers,
});
const list = res.data;
diff --git a/lib/routes/haohaozhu/discover.js b/lib/routes/haohaozhu/discover.js
new file mode 100644
index 000000000..ebc681327
--- /dev/null
+++ b/lib/routes/haohaozhu/discover.js
@@ -0,0 +1,42 @@
+const got = require('@/utils/got');
+
+module.exports = async (ctx) => {
+ const keyword = ctx.params.keyword && ctx.params.keyword !== 'all' && ctx.params.keyword !== '全部' ? ctx.params.keyword : '';
+
+ const url = 'https://www.haohaozhu.cn/community/discover';
+
+ const response = await got({
+ method: 'post',
+ url: 'https://www.haohaozhu.cn/f/y/api/Share/AllPhotoInPc',
+ headers: {
+ Referer: url,
+ },
+ form: {
+ keyword: keyword,
+ page: 1,
+ time: new Date().getTime(),
+ },
+ });
+
+ const list = response.data.data.rows;
+
+ ctx.state.data = {
+ title: `好好住 - 发现${keyword ? ' - ' + keyword : ''}`,
+ link: url,
+ item: list
+ .map((item) => {
+ if (item.is_advertisement !== 0 || !item.photo || !item.photo.photo_info) {
+ return '';
+ }
+ return {
+ title: item.photo.photo_info.remark,
+ author: item.photo.user_info.nick,
+ description: item.photo.photo_info.image_list.map((image) => `
`).join(''),
+ link: url,
+ guid: item.photo.photo_info.id,
+ pubDate: new Date(item.photo.photo_info.addtime * 1000),
+ };
+ })
+ .filter((item) => item !== ''),
+ };
+};
diff --git a/lib/routes/haohaozhu/whole-house.js b/lib/routes/haohaozhu/whole-house.js
new file mode 100644
index 000000000..921ccbf57
--- /dev/null
+++ b/lib/routes/haohaozhu/whole-house.js
@@ -0,0 +1,75 @@
+const got = require('@/utils/got');
+const cheerio = require('cheerio');
+
+module.exports = async (ctx) => {
+ const keyword = ctx.params.keyword && ctx.params.keyword !== 'all' && ctx.params.keyword !== '全部' ? ctx.params.keyword : '';
+
+ const url = 'https://www.haohaozhu.cn/community/whole-house';
+
+ const response = await got({
+ method: 'post',
+ url: 'https://www.haohaozhu.cn/f/y/api/Share/GetArticle',
+ headers: {
+ Referer: url,
+ },
+ form: {
+ keyword: keyword,
+ page: 1,
+ },
+ });
+
+ const list = response.data.data.rows;
+
+ const parseContent = (htmlString) => {
+ const $ = cheerio.load(htmlString);
+
+ const content = $('.whole-header').parent();
+ $('.whole-title').remove();
+ $('.whole-user').remove();
+ $('.question').appendTo(content);
+
+ return {
+ description: content.html(),
+ };
+ };
+
+ const out = await Promise.all(
+ list.map(async (item, index) => {
+ const link = `https://www.haohaozhu.cn/community/whole-house-detail/${item.article_id}`;
+
+ const time = new Date();
+ time.setMinutes(time.getMinutes() - index);
+
+ const cache = await ctx.cache.get(link);
+ if (cache) {
+ return Promise.resolve(JSON.parse(cache));
+ }
+
+ const rssitem = {
+ title: item.article_info.title,
+ link: link,
+ author: item.user_info.nick,
+ pubDate: time,
+ };
+
+ try {
+ const response = await got.get(link);
+ const result = parseContent(response.data);
+ if (!result.description) {
+ return Promise.resolve('');
+ }
+ rssitem.description = result.description;
+ } catch (err) {
+ return Promise.resolve('');
+ }
+ ctx.cache.set(link, JSON.stringify(rssitem));
+ return Promise.resolve(rssitem);
+ })
+ );
+
+ ctx.state.data = {
+ title: `好好住 - 整屋案例${keyword ? ' - ' + keyword : ''}`,
+ link: url,
+ item: out.filter((item) => item !== ''),
+ };
+};
diff --git a/lib/routes/p-articles/contributors.js b/lib/routes/p-articles/contributors.js
new file mode 100644
index 000000000..2554416d1
--- /dev/null
+++ b/lib/routes/p-articles/contributors.js
@@ -0,0 +1,48 @@
+const got = require('@/utils/got');
+const cheerio = require('cheerio');
+const url = require('url');
+const utils = require('./utils');
+
+const host = 'https://p-articles.com/';
+
+module.exports = async (ctx) => {
+ const author = ctx.params.author;
+
+ const link = `https://p-articles.com/contributors/${author}`;
+
+ const response = await got.get(link);
+ const $ = cheerio.load(response.data);
+
+ const list = $('div.contect_box_05in > a')
+ .map(function() {
+ const info = {
+ title: $(this)
+ .find('h3')
+ .text()
+ .trim(),
+ link: url.resolve(host, $(this).attr('href')),
+ };
+ return info;
+ })
+ .get();
+
+ const out = await Promise.all(
+ list.map(async (info) => {
+ const link = info.link;
+
+ const cache = await ctx.cache.get(link);
+ if (cache) {
+ return Promise.resolve(JSON.parse(cache));
+ }
+ const response = await got.get(link);
+
+ return utils.ProcessFeed(ctx, info, response.data);
+ })
+ );
+
+ ctx.state.data = {
+ title: `虛詞作者-${author}`,
+ link: link,
+ item: out,
+ };
+};
diff --git a/lib/routes/p-articles/section.js b/lib/routes/p-articles/section.js
new file mode 100644
index 000000000..0fc3a30c2
--- /dev/null
+++ b/lib/routes/p-articles/section.js
@@ -0,0 +1,56 @@
+const got = require('@/utils/got');
+const cheerio = require('cheerio');
+const url = require('url');
+const utils = require('./utils');
+
+const host = 'https://p-articles.com/';
+
+module.exports = async (ctx) => {
+ let section_name = ctx.params.section;
+ section_name = section_name.replace('-', '/');
+ section_name += '/';
+
+ const link = url.resolve(host, section_name);
+
+ const response = await got.get(link);
+ const $ = cheerio.load(response.data);
+
+ const top_info = {
+ title: $('div.inner_top_title_01 > h1 > a').text(),
+ link: url.resolve(host, $('div.inner_top_title_01 > h1 > a').attr('href')),
+ };
+
+ const list = $('div.contect_box_04 > a')
+ .map(function() {
+ const info = {
+ title: $(this)
+ .find('h1')
+ .text()
+ .trim(),
+ link: url.resolve(host, $(this).attr('href')),
+ };
+ return info;
+ })
+ .get();
+
+ list.unshift(top_info);
+
+ const out = await Promise.all(
+ list.map(async (info) => {
+ const link = info.link;
+
+ const cache = await ctx.cache.get(link);
+ if (cache) {
+ return Promise.resolve(JSON.parse(cache));
+ }
+ const response = await got.get(link);
+
+ return utils.ProcessFeed(ctx, info, response.data);
+ })
+ );
+ ctx.state.data = {
+ title: `虛詞版块-${section_name}`,
+ link: link,
+ item: out,
+ };
+};
diff --git a/lib/routes/p-articles/utils.js b/lib/routes/p-articles/utils.js
new file mode 100644
index 000000000..c5fff630a
--- /dev/null
+++ b/lib/routes/p-articles/utils.js
@@ -0,0 +1,33 @@
+const date = require('@/utils/date');
+const cheerio = require('cheerio');
+
+const ProcessFeed = (ctx, info, data) => {
+ const title = info.title;
+ const itemUrl = info.link;
+
+ const $ = cheerio.load(data);
+
+ const author = $('div.detail_title_02 > h4 > a:nth-child(2)')
+ .text()
+ .trim();
+
+ const date_value = $('div.detail_title_02 > h4 ')
+ .text()
+ .trim();
+
+ const description = $('div.detail_contect_01').html();
+
+ const single = {
+ title: title,
+ link: itemUrl,
+ description: description,
+ author: author,
+ pubDate: date(date_value, 8),
+ };
+ ctx.cache.set(itemUrl, JSON.stringify(single));
+ return Promise.resolve(single);
+};
+
+module.exports = {
+ ProcessFeed,
+};
diff --git a/lib/routes/universities/neu/news.js b/lib/routes/universities/neu/news.js
new file mode 100644
index 000000000..ee4db7854
--- /dev/null
+++ b/lib/routes/universities/neu/news.js
@@ -0,0 +1,63 @@
+const got = require('@/utils/got');
+const cheerio = require('cheerio');
+
+const baseUrl = 'http://neunews.neu.edu.cn';
+module.exports = async (ctx) => {
+ const type = ctx.params.type;
+ const newsUrl = `${baseUrl}/${type}/list.htm`;
+ const response = await got({
+ method: 'get',
+ url: newsUrl,
+ });
+
+ const data = response.data;
+ const $ = cheerio.load(data);
+
+ const title = $('title').text();
+ const items = $('.column-news-list > .news_list > .news > .news_title')
+ .slice(0, 10)
+ .children();
+ const results = [];
+ items.each(async (index, item) => {
+ const label = $(item);
+ const title = $(label).attr('title');
+ const url = baseUrl + $(label).attr('href');
+ const description = await ctx.cache.tryGet(url, async () => {
+ const result = await got.get(url);
+ const $ = cheerio.load(result.data);
+ // 处理部分格式
+ $('article')
+ .find('span')
+ .each(function() {
+ const temp = $(this).text();
+ $(this).replaceWith(temp);
+ });
+ $('article')
+ .find('div')
+ .each(function() {
+ const temp = $(this).html();
+ $(this).replaceWith(temp);
+ });
+ $('article')
+ .find('a')
+ .remove();
+ $('article')
+ .find('p')
+ .each(function() {
+ $(this).removeAttr('style');
+ $(this).removeAttr('class');
+ });
+ return $('article').html();
+ });
+ const result = {
+ title: title,
+ description: description,
+ link: url,
+ };
+ results.push(result);
+ });
+ ctx.state.data = {
+ title: title,
+ item: results,
+ };
+};
diff --git a/lib/routes/universities/ouc/it.js b/lib/routes/universities/ouc/it.js
new file mode 100644
index 000000000..fc28f4a61
--- /dev/null
+++ b/lib/routes/universities/ouc/it.js
@@ -0,0 +1,54 @@
+const got = require('@/utils/got');
+const cheerio = require('cheerio');
+const url = require('url');
+
+const host = 'https://it.ouc.edu.cn/';
+const typelist = ['学院要闻', '学院公告', '学术活动'];
+const urlList = ['xyyw/list.psp', 'xygg/list.psp', 'xshd/list.psp'];
+
+module.exports = async (ctx) => {
+ const type = parseInt(ctx.params.type) || 0;
+ const link = url.resolve(host, urlList[type]);
+ const response = await got.get(link);
+ const $ = cheerio.load(response.data);
+
+ const dateDict = {};
+ const list = $('#wp_news_w33')
+ .find('li')
+ .slice(0, 9)
+ .map((i, e) => {
+ const divs = $(e).children();
+ const tlink = host + divs.find('a')[0].attribs.href.substring(1);
+ dateDict[tlink] = new Date($($(divs.children()[0]).find('p')[0]).text()).toUTCString();
+ return tlink;
+ })
+ .get();
+ const out = await Promise.all(
+ list.map(async (itemUrl) => {
+ const cache = await ctx.cache.get(itemUrl);
+ if (cache) {
+ return Promise.resolve(JSON.parse(cache));
+ }
+ const response = await got.get(itemUrl);
+ const $ = cheerio.load(response.data);
+
+ const single = {
+ title: $('.content-tittle')
+ .text()
+ .trim(),
+ author: '中国海洋大学信息科学与工程学院',
+ description: $('.wp_articlecontent').html(),
+ pubDate: dateDict[itemUrl],
+ link: itemUrl,
+ };
+ ctx.cache.set(itemUrl, JSON.stringify(single));
+ return Promise.resolve(single);
+ })
+ );
+
+ ctx.state.data = {
+ title: `中国海洋大学信息科学与工程学院${typelist[type]}`,
+ link,
+ item: out,
+ };
+};