feat: remove notOperational routes - reading

This commit is contained in:
DIYgod
2023-12-21 23:12:31 +08:00
parent 3eecd1d063
commit 78001402b5
30 changed files with 0 additions and 1238 deletions
-1
View File
@@ -144,7 +144,6 @@
},
],
},
'zhaishuyuan.com': { _name: '斋书苑', '.': [{ title: '最新章节', docs: 'https://docs.rsshub.app/routes/reading#zhai-shu-yuan', source: ['/book/:id', '/read/:id'], target: '/novel/zhaishuyuan/:id' }] },
'hbut.edu.cn': {
_name: '湖北工业大学',
www: [
-3
View File
@@ -133,9 +133,6 @@ const calculateValue = () => {
bupt: {
portal_cookie: envs.BUPT_PORTAL_COOKIE,
},
chuiniu: {
member: envs.CHUINIU_MEMBER,
},
civitai: {
cookie: envs.CIVITAI_COOKIE,
},
-11
View File
@@ -441,17 +441,6 @@ module.exports = {
},
],
},
'zhaishuyuan.com': {
_name: '斋书苑',
'.': [
{
title: '最新章节',
docs: 'https://docs.rsshub.app/routes/reading#zhai-shu-yuan',
source: ['/book/:id', '/read/:id'],
target: '/novel/zhaishuyuan/:id',
},
],
},
'hbut.edu.cn': {
_name: '湖北工业大学',
www: [
-35
View File
@@ -120,9 +120,6 @@ router.get('/miui/:device/:type?/:region?', lazyloadRouteHandler('./routes/mi/mi
// 纵横
router.get('/zongheng/chapter/:id', lazyloadRouteHandler('./routes/zongheng/chapter'));
// 刺猬猫
router.get('/ciweimao/chapter/:id', lazyloadRouteHandler('./routes/ciweimao/chapter'));
// 维基百科 Wikipedia
router.get('/wikipedia/mainland', lazyloadRouteHandler('./routes/wikipedia/mainland'));
@@ -159,10 +156,6 @@ router.get('/mafengwo/ziyouxing/:code', lazyloadRouteHandler('./routes/mafengwo/
// router.get('/novel/biquge/:id', lazyloadRouteHandler('./routes/novel/biquge'));
// router.get('/novel/biqugeinfo/:id/:limit?', lazyloadRouteHandler('./routes/novel/biqugeinfo'));
router.get('/novel/uukanshu/:uid', lazyloadRouteHandler('./routes/novel/uukanshu'));
router.get('/novel/wenxuemi/:id1/:id2', lazyloadRouteHandler('./routes/novel/wenxuemi'));
router.get('/novel/booksky/:id', lazyloadRouteHandler('./routes/novel/booksky'));
router.get('/novel/ptwxz/:id1/:id2', lazyloadRouteHandler('./routes/novel/ptwxz'));
router.get('/novel/zhaishuyuan/:id', lazyloadRouteHandler('./routes/novel/zhaishuyuan'));
// 中国气象网
router.get('/weatheralarm/:province?', lazyloadRouteHandler('./routes/weatheralarm'));
@@ -936,10 +929,6 @@ router.get('/cfan/news', lazyloadRouteHandler('./routes/cfan/news'));
// engadget
router.get('/engadget/:lang?', lazyloadRouteHandler('./routes/engadget/home'));
// 吹牛部落
router.get('/chuiniu/column/:id', lazyloadRouteHandler('./routes/chuiniu/column'));
router.get('/chuiniu/column_list', lazyloadRouteHandler('./routes/chuiniu/column_list'));
// leemeng
router.get('/leemeng', lazyloadRouteHandler('./routes/blogs/leemeng'));
@@ -1139,14 +1128,6 @@ router.get('/lastfm/top/:country?', lazyloadRouteHandler('./routes/lastfm/top'))
router.get('/piapro/user/:pid', lazyloadRouteHandler('./routes/piapro/user'));
router.get('/piapro/public/:type/:tag?/:category?', lazyloadRouteHandler('./routes/piapro/public'));
// 第一版主
router.get('/novel/d1bz/:category/:id', lazyloadRouteHandler('./routes/d1bz/novel'));
// 爱下电子书
router.get('/axdzs/:novel', lazyloadRouteHandler('./routes/novel/axdzs'));
// deprecated
router.get('/axdzs/:id1/:id2', lazyloadRouteHandler('./routes/novel/axdzs'));
// HackerOne
router.get('/hackerone/hacktivity', lazyloadRouteHandler('./routes/hackerone/hacktivity'));
router.get('/hackerone/search/:search', lazyloadRouteHandler('./routes/hackerone/search'));
@@ -1162,9 +1143,6 @@ router.get('/p-articles/contributors/:author', lazyloadRouteHandler('./routes/p-
router.get('/haohaozhu/whole-house/:keyword?', lazyloadRouteHandler('./routes/haohaozhu/whole-house'));
router.get('/haohaozhu/discover/:keyword?', lazyloadRouteHandler('./routes/haohaozhu/discover'));
// 稻草人书屋
router.get('/dcrsw/:name/:count?', lazyloadRouteHandler('./routes/novel/dcrsw'));
// 魔法纪录
router.get('/magireco/announcements', lazyloadRouteHandler('./routes/magireco/announcements'));
router.get('/magireco/event_banner', lazyloadRouteHandler('./routes/magireco/event_banner'));
@@ -1315,10 +1293,6 @@ router.get('/umass/amherst/ipostories', lazyloadRouteHandler('./routes/umass/amh
router.get('/kuai', lazyloadRouteHandler('./routes/kuai/index'));
router.get('/kuai/:id', lazyloadRouteHandler('./routes/kuai/id'));
// 生物帮
router.get('/biobio/:id', lazyloadRouteHandler('./routes/biobio/index'));
router.get('/biobio/:column/:id', lazyloadRouteHandler('./routes/biobio/others'));
// 199it
router.get('/199it', lazyloadRouteHandler('./routes/199it/index'));
router.get('/199it/category/:caty', lazyloadRouteHandler('./routes/199it/category'));
@@ -1343,9 +1317,6 @@ router.get('/stork/keyword/:trackID/:displayKey', lazyloadRouteHandler('./routes
// arXiv
router.get('/arxiv/:query', lazyloadRouteHandler('./routes/arxiv/query'));
// 生物谷
router.get('/shengwugu/:uid?', lazyloadRouteHandler('./routes/shengwugu/index'));
// 环球律师事务所文章
router.get('/law/hq', lazyloadRouteHandler('./routes/law/hq'));
@@ -1597,9 +1568,6 @@ router.get('/manictime/releases', lazyloadRouteHandler('./routes/manictime/relea
// Deutsche Welle 德国之声
router.get('/dw/:lang?/:caty?', lazyloadRouteHandler('./routes/dw/index'));
// Amazon
router.get('/amazon/ku/:type?', lazyloadRouteHandler('./routes/amazon/ku'));
// Citavi 中文网站论坛
router.get('/citavi/:caty?', lazyloadRouteHandler('./routes/citavi/index'));
@@ -1875,9 +1843,6 @@ router.get('/furaffinity/favorites/:username/:nsfw?', lazyloadRouteHandler('./ro
router.get('/furaffinity/submission_comments/:id', lazyloadRouteHandler('./routes/furaffinity/submission_comments'));
router.get('/furaffinity/journal_comments/:id', lazyloadRouteHandler('./routes/furaffinity/journal_comments'));
// 博客来
router.get('/bookscomtw/newbooks/:category', lazyloadRouteHandler('./routes/bookscomtw/newbooks'));
// Trakt.tv
router.get('/trakt/collection/:username/:type?', lazyloadRouteHandler('./routes/trakt/collection'));
-57
View File
@@ -1,57 +0,0 @@
const got = require('@/utils/got');
const cheerio = require('cheerio');
const config = {
this: '2037295071',
back: '2330861071',
next: '2037296071',
};
module.exports = async (ctx) => {
const type = ctx.params.type || 'this';
const node = config[type];
if (!node) {
throw Error('Bad type. See <a href="https://docs.rsshub.app/routes/reading#kindle-unlimited-hui-yuan-xian-shi-mian-fei-du-shu-dan">docs</a>');
}
const rootUrl = `https://www.amazon.cn/b?node=${node}`;
const response = await got({
method: 'get',
url: rootUrl,
});
const $ = cheerio.load(response.data);
const list = $('.apb-browse-searchresults-product .a-spacing-top-small a')
.map((_, item) => {
item = $(item);
return {
link: 'https://www.amazon.cn' + item.attr('href'),
title: item.text().trim(),
};
})
.get();
const items = await Promise.all(
list.map((item) =>
ctx.cache.tryGet(item.link, async () => {
const detailResponse = await got({
method: 'get',
url: item.link,
});
const content = cheerio.load(detailResponse.data);
item.author = content('span.author').text();
item.description = content('#ebooks-img-canvas').html() + content('#detailBullets_feature_div').html();
return item;
})
)
);
ctx.state.data = {
title: `KU会员限时免费读 - ${$('title').text().split('-')[1]}`,
link: rootUrl,
item: items,
};
};
-40
View File
@@ -1,40 +0,0 @@
const cheerio = require('cheerio');
const got = require('@/utils/got');
module.exports = async (ctx) => {
const url = `http://www.bio1000.com/${ctx.params.id}`;
const res = await got.get(url);
const $ = cheerio.load(res.data);
const list = $('.excerpt-1').get();
const out = await Promise.all(
list.slice(0, 5).map(async (item) => {
const $ = cheerio.load(item);
const time = $('.meta').text();
const title = $('header h2 a').attr('title');
const partial = $('header h2 a').attr('href');
const address = partial;
const cache = await ctx.cache.get(address);
if (cache) {
return Promise.resolve(JSON.parse(cache));
}
const res = await got.get(address);
const get = cheerio.load(res.data);
const contents = get('.article-content').html();
const single = {
title,
pubDate: time,
description: contents,
link: address,
guid: address,
};
ctx.cache.set(address, JSON.stringify(single));
return Promise.resolve(single);
})
);
ctx.state.data = {
title: '生物帮',
link: url,
item: out,
};
};
-45
View File
@@ -1,45 +0,0 @@
const cheerio = require('cheerio');
const got = require('@/utils/got');
const { isValidHost } = require('@/utils/valid-host');
module.exports = async (ctx) => {
if (!isValidHost(ctx.params.column)) {
throw Error('Invalid column');
}
const url = `http://${ctx.params.column}.bio1000.com/${ctx.params.id}`;
const res = await got.get(url);
const $ = cheerio.load(res.data);
const list = $('.excerpt-1').get();
const out = await Promise.all(
list.slice(0, 5).map(async (item) => {
const $ = cheerio.load(item);
const time = $('.meta').text();
const title = $('header h2 a').attr('title');
const partial = $('header h2 a').attr('href');
const address = partial;
const cache = await ctx.cache.get(address);
if (cache) {
return Promise.resolve(JSON.parse(cache));
}
const res = await got.get(address);
const get = cheerio.load(res.data);
const contents = get('.article-content').html();
const single = {
title,
pubDate: time,
description: contents,
link: address,
guid: address,
};
ctx.cache.set(address, JSON.stringify(single));
return Promise.resolve(single);
})
);
ctx.state.data = {
title: '生物帮',
link: url,
item: out,
};
};
-37
View File
@@ -1,37 +0,0 @@
const got = require('@/utils/got');
const cheerio = require('cheerio');
module.exports = async (ctx) => {
const url = `https://www.books.com.tw/web/${ctx.params.category}/`;
const { data } = await got({
method: 'get',
url,
});
const $ = cheerio.load(data);
const list = $('div.mod_a div.wrap div.item');
const items = list
.map((i, item) => {
item = $(item);
const title = item.find('h4').text().trim();
let imgLink = item.find('a img.cover').attr('src').trim();
imgLink = imgLink.slice(imgLink.indexOf('https', 1), imgLink.indexOf('.jpg') + 4);
const link = item.find('a').attr('href');
const desc = item.find('div.txt_cont p').text().trim();
const author = item.find('li.info>a').text();
const publisher = item.find('li.info span>a').text();
const pubInfo = item.find('li.info').text();
let price = item.find('ul.price li.set2 strong');
price = price.length === 1 ? parseInt(price.text().trim()) : parseInt(price.eq(0).text() > 10 ? ((price.eq(1).text() * 100) / price.eq(0).text()).toFixed() : ((price.eq(1).text() * 10) / price.eq(0).text()).toFixed());
return {
title,
description: `${desc}<br><img src="${imgLink}" alt="${title}"><br>NT$${price}元<br>${pubInfo}`,
link: link.slice(0, link.indexOf('?')),
author: `${author} / ${publisher}`,
};
})
.get();
ctx.state.data = {
title: $('title').text(),
link: URL,
item: items,
};
};
-89
View File
@@ -1,89 +0,0 @@
const got = require('@/utils/got');
const config = require('@/config').value;
module.exports = async (ctx) => {
const url = 'http://chuiniu.duanshu.com';
const column_id = ctx.params.id;
let response = await got({
method: 'get',
url: 'http://oss-web.duanshu.com/shop/chuiniu-duanshu-com/config.json',
headers: {
Origin: url,
Referer: url,
},
});
const shop_id = response.data.shop_id;
response = await got({
method: 'get',
url: `http://api.duanshu.com/h5/content/free/column/detail/${column_id}?shop_id=${shop_id}`,
headers: {
Referer: url,
'x-platform': 'h5',
},
});
const title = response.data.response.data.title;
const description = response.data.response.data.brief;
response = await got({
method: 'get',
url: `http://api.duanshu.com/h5/content/column/contents?page=1&count=10&column_id=${column_id}&shop_id=${shop_id}`,
headers: {
Referer: url,
},
});
const list = response.data.response.data;
const out = await Promise.all(
list.map(async (item) => {
const title = item.title;
const brief = item.brief;
const up_time = item.up_time;
const content_id = item.content_id;
const item_link = `http://chuiniu.duanshu.com/#/brief/article/${content_id}`;
const cache = await ctx.cache.get(item_link);
if (cache) {
return Promise.resolve(JSON.parse(cache));
}
const member = config.chuiniu.member;
let content;
if (member === undefined) {
content = brief + '<br>...<br>正文内容需会员登录后查看';
} else {
try {
const response = await got({
method: 'get',
url: `http://api.duanshu.com/h5/content/detail/${content_id}?shop_id=${shop_id}`,
headers: {
Referer: url,
'x-member': member,
},
});
content = response.data.response.data.content;
} catch (error) {
content = brief + '<br>...<br>正文内容需会员登录后查看';
}
}
const single = {
pubDate: new Date(up_time).toUTCString(),
link: item_link,
title,
description: content,
};
ctx.cache.set(item_link, JSON.stringify(single));
return Promise.resolve(single);
})
);
ctx.state.data = {
title,
description,
link: url,
item: out,
};
};
-36
View File
@@ -1,36 +0,0 @@
const got = require('@/utils/got');
module.exports = async (ctx) => {
const url = 'http://chuiniu.duanshu.com/#/list/column';
let response = await got({
method: 'get',
url: 'http://api.duanshu.com/fairy/api/v1/shop/identifier/',
headers: {
Origin: url,
Referer: url,
},
});
const shop_id = response.data.shop_id;
response = await got({
method: 'get',
url: `http://api.duanshu.com/h5/content/column/lists?page=1&count=12&shop_id=${shop_id}`,
headers: {
Referer: url,
},
});
const list = response.data.response.data;
const out = list.map((item) => ({
link: `http://chuiniu.duanshu.com/#/brief/column/${item.column_id}`,
title: item.title,
description: item.brief,
}));
ctx.state.data = {
title: '吹牛部落专栏列表',
link: url,
item: out,
};
};
-34
View File
@@ -1,34 +0,0 @@
const got = require('@/utils/got');
const cheerio = require('cheerio');
module.exports = async (ctx) => {
const id = ctx.params.id;
const selector = cheerio.load((await got.get(`https://www.ciweimao.com/book/${id}`)).data);
const name = selector('.book-info h3.title').text();
const description = selector('.book-intro').html();
const response = await got({
method: 'post',
url: `https://www.ciweimao.com/chapter/get_chapter_list_in_chapter_detail`,
form: {
book_id: id,
chapter_id: 0,
orderby: 0,
},
});
const $ = cheerio.load(response.data);
const item = $('.book-chapter-box>ul>li>a')
.map((index, ele) => ({
title: $(ele).text(),
link: $(ele).attr('href'),
}))
.get();
ctx.state.data = {
title: `刺猬猫 ${name}`,
link: `http://www.ciweimao.com/book/${id}`,
description,
item,
};
};
-72
View File
@@ -1,72 +0,0 @@
const got = require('@/utils/got');
const cheerio = require('cheerio');
const iconv = require('iconv-lite');
// function changeStr(str, index, changeStr) {
// return str.substr(0, index) + changeStr + str.substr(index + changeStr.length);
// }
//
// function find(str, cha, num) {
// let x = str.indexOf(cha);
// for (let i = 0; i < num; i++) {
// x = str.indexOf(cha, x + 1);
// }
// return x;
// }
const gbk2utf8 = (s) => iconv.decode(s, 'gbk');
module.exports = async (ctx) => {
const category = ctx.params.category.toLowerCase();
const id = ctx.params.id.toLowerCase();
const baseUrl = 'http://www.dybz9.net';
const novelUrl = `${baseUrl}/${category}/${id}/`;
const response = await got.get(novelUrl, {
responseType: 'buffer',
});
// const response = await got.get(novelUrl);
const $ = cheerio.load(gbk2utf8(new Buffer.from(response.data)));
const lists = $('.container .chapter-list .bd ul li').slice(0, 3);
const chapter_item = lists
.find('a')
.map((_, e) => ({
title: e.children[0].data,
link: baseUrl + e.attribs.href,
}))
.get();
const title = chapter_item.title;
const items = await Promise.all(
chapter_item.map(async (item) => {
const cache = await ctx.cache.get(item.link);
if (cache) {
return Promise.resolve(JSON.parse(cache));
}
const response = await got.get(item.link, {
responseType: 'buffer',
});
const responseHtml = iconv.decode(response.data, 'GBK');
const $ = cheerio.load(responseHtml);
const description = $('.page-content').html();
const single = {
title: item.title,
description,
link: item.link,
};
ctx.cache.set(item.link, JSON.stringify(single));
return Promise.resolve(single);
})
);
ctx.state.data = {
title,
link: novelUrl,
item: items,
};
};
-67
View File
@@ -1,67 +0,0 @@
const got = require('@/utils/got');
const cheerio = require('cheerio');
const baseUrl = 'https://www.aixdzs.com';
module.exports = async (ctx) => {
if (ctx.params.id2) {
const redirect = await got.head(`https://read.aixdzs.com/${ctx.params.id1}/${ctx.params.id2}/`, { followRedirect: false });
const redirectUrl = redirect.headers.location;
const novel = redirectUrl.substring(1 + redirectUrl.lastIndexOf('/'));
ctx.status = 301;
ctx.redirect(`/axdzs/${novel}`);
return;
}
const novel = ctx.params.novel;
const novelUrl = `${baseUrl}/novel/${novel}/`;
const response = await got.get(novelUrl);
const data = response.data;
const $ = cheerio.load(data);
const title = $('h1').text();
const description = $('meta[name="description"]').attr('content');
const lastChapter = $('.chapter').last().children();
const secondChapter = $('.chapter').last().prev().children();
let lastChapterUrl = lastChapter.attr('href');
let secondChapterUrl = secondChapter.attr('href');
if (lastChapterUrl.startsWith('/')) {
lastChapterUrl = baseUrl + lastChapterUrl;
secondChapterUrl = baseUrl + secondChapterUrl;
}
const lastChapterContent = await ctx.cache.tryGet(lastChapterUrl, async () => {
const res = await got.get(lastChapterUrl);
const $ = cheerio.load(res.data, { decodeEntities: false });
return $('.content').html();
});
// 以下需要判断最新章节是否已填充内容
let chapterTitle, chapterUrl, chapterContent;
// 判断新章节内是否存在无内容的提示信息,如存在则请求上一章节数据
if (lastChapterContent.indexOf('鍦ㄦ洿鏂颁腑锛岃绋嶅悗鍒锋') === -1) {
chapterTitle = lastChapter.text();
chapterUrl = lastChapterUrl;
chapterContent = lastChapterContent;
} else {
chapterTitle = secondChapter.text();
chapterUrl = secondChapterUrl;
chapterContent = await ctx.cache.tryGet(secondChapterUrl, async () => {
const secondChapter = await got.get(secondChapterUrl);
const $ = cheerio.load(secondChapter.data, { decodeEntities: false });
return $('.content').html();
});
}
ctx.state.data = {
title: `爱下电子书-${title}`,
description,
link: novelUrl,
item: [
{
title: chapterTitle,
link: chapterUrl,
description: chapterContent,
},
],
};
};
-44
View File
@@ -1,44 +0,0 @@
const got = require('@/utils/got');
const cheerio = require('cheerio');
const iconv = require('iconv-lite');
const baseUrl = 'http://booksky.so/BookDetail.aspx?Level=1&bid=';
module.exports = async (ctx) => {
const id = ctx.params.id;
const response = await got({
method: 'get',
url: `${baseUrl}${id}`,
headers: {
Host: 'booksky.so',
Referer: 'http://booksky.so/',
},
responseType: 'buffer',
});
const responseHtml = iconv.decode(response.data, 'GBK');
const $ = cheerio.load(responseHtml);
const list = $('tr[class=b]').attr('height', '25');
const title = $('font').attr('color', 'red').text();
ctx.state.data = {
title,
link: `${baseUrl}${id}`,
description: '',
item:
list &&
list
.map((index, item) => {
item = $(item);
return {
title: item.find('.s').text(),
description: item.find('.t').eq(1).text(),
pubDate: new Date(item.find('.t').eq(2).text()).toUTCString(),
link: `http://booksky.so/${item.find('.s').children('a').attr('href')}`,
};
})
.get(),
};
};
-58
View File
@@ -1,58 +0,0 @@
const got = require('@/utils/got');
const cheerio = require('cheerio');
const baseUrl = 'https://www.daocaorenshuwu.com';
module.exports = async (ctx) => {
const name = ctx.params.name;
const count = ctx.params.count || 3;
const novelUrl = `${baseUrl}/book/${name}`;
const response = await got({
method: 'get',
url: novelUrl,
});
const data = response.data;
const $ = cheerio.load(data);
const title = $('h1.book-name').children().text();
const description = $('div.book-detail').text();
const chapters = $('.col-md-6').slice(0, count).get();
const results = await Promise.all(
chapters.map(async (item) => {
const $ = cheerio.load(item);
const chapterTitle = $('a').text();
const chapterUrl = 'https:' + $('a').attr('href');
const chapterContent = await ctx.cache.tryGet(chapterUrl, async () => {
let result = '';
let temp = chapterUrl;
while (temp !== '') {
// eslint-disable-next-line no-await-in-loop
const chapter = await got.get(temp);
const $ = cheerio.load(chapter.data);
$('div.cont-text > script').remove();
result += $('div.cont-text').html();
// 如果有下一页则访问下一页
if ($('a:contains("下一页")').length > 0) {
temp = baseUrl + $('a:contains("下一页")').last().attr('href');
} else {
temp = '';
}
}
return result;
});
return Promise.resolve({
title: chapterTitle,
link: chapterUrl,
description: chapterContent,
});
})
);
ctx.state.data = {
title: `稻草人书屋-${title}`,
description,
link: novelUrl,
item: results,
};
};
-76
View File
@@ -1,76 +0,0 @@
const got = require('@/utils/got');
const cheerio = require('cheerio');
const iconv = require('iconv-lite');
const baseUrl = 'https://www.ptwxz.com/bookinfo/';
const timezone = require('@/utils/timezone');
const { parseDate } = require('@/utils/parse-date');
// 获取小说的最新章节列表
module.exports = async (ctx) => {
// 小说id
const id1 = ctx.params.id1;
const id2 = ctx.params.id2;
const id = id1 + '/' + id2;
const response = await got({
method: 'get',
url: `${baseUrl}${id}.html`,
headers: {
Referer: `${baseUrl}${id}.html`,
},
responseType: 'buffer',
});
const responseHtml = iconv.decode(response.data, 'gbk');
const $ = cheerio.load(responseHtml);
const title = $('span>h1').text();
const chapter_item = $('#content li a')
.map((_, item) => {
item = $(item);
const date = item.attr('title').match(/更新时间:(.*)/)[1]; // "10-04 00:17"
return {
title: item.text(),
link: item.attr('href'),
pubDate: timezone(parseDate(date, 'MM-DD HH:mm'), +8),
};
})
.get();
const items = await Promise.all(
chapter_item.map((item) =>
ctx.cache.tryGet(item.link, async () => {
const response = await got({
method: 'get',
url: `https://www.ptwxz.com/${item.link}`,
responseType: 'buffer',
});
const responseHtml = iconv.decode(response.data, 'GBK');
const $ = cheerio.load(responseHtml);
// remove all unwanted elements
// TODO: cleaner solution to rip text from body
$('div').remove();
$('h1').remove();
$('table').remove();
$('center').remove();
$('table').remove();
$('script').remove();
const description = $('body').html();
const single = {
title: item.title,
description,
link: item.link,
pubDate: item.pubDate,
};
return single;
})
)
);
ctx.state.data = {
title,
link: `${baseUrl}${id}.html`,
description: '',
item: items,
};
};
-63
View File
@@ -1,63 +0,0 @@
const got = require('@/utils/got');
const cheerio = require('cheerio');
const iconv = require('iconv-lite');
const mbaseUrl = 'https://m.wenxuemi.com/files/article/html';
const baseUrl = 'https://www.wenxuemi.com';
// 获取小说的最新章节列表
module.exports = async (ctx) => {
const id1 = ctx.params.id1; // 小说id
const id2 = ctx.params.id2;
const id = '/' + id1 + '/' + id2;
const got_ins = got.extend({
headers: {
Referer: `${mbaseUrl}${id}/`,
},
responseType: 'buffer',
});
const response = await got_ins.get(`${mbaseUrl}${id}/`);
const responseHtml = iconv.decode(response.data, 'GBK');
const $ = cheerio.load(responseHtml);
const title = $('h2', '.block_txt2').find('a').text();
const description = $('.intro_info').text();
const cover_url = $('img', '.block_img2').attr('src');
const list = $('li', '.chapter').slice(0, 5);
const resultItems = await Promise.all(
list.toArray().map(async (item) => {
const $item = $(item);
const link = baseUrl + $item.find('a').attr('href');
let resultItem = {};
const value = await ctx.cache.get(link);
if (value) {
resultItem = JSON.parse(value);
} else {
const articleHtml = await got_ins.get(link);
const article = iconv.decode(articleHtml.data, 'GBK');
const $1 = cheerio.load(article);
const res = $1('div#content');
resultItem = {
title: $item.text(),
description: res.html(),
link,
};
if (res.text().includes('正在手打中') === false) {
ctx.cache.set(link, JSON.stringify(resultItem));
}
}
return Promise.resolve(resultItem);
})
);
ctx.state.data = {
title,
link: `${baseUrl}/files/article/html${id}/`,
image: cover_url,
description,
item: resultItems,
};
};
-84
View File
@@ -1,84 +0,0 @@
const got = require('@/utils/got');
const cheerio = require('cheerio');
const iconv = require('iconv-lite');
const encodeMap = {
$$$: '7',
$$$$: 'f',
$$$_: 'e',
$$_: '6',
$$_$: 'd',
$$__: 'c',
$_$: '5',
$_$$: 'b',
$_$_: 'a',
$__: '4',
$__$: '9',
$___: '8',
_: 'u',
_$$: '3',
_$_: '2',
__$: '1',
___: '0',
};
const tokenPattern = /[A-Z]\.([$_]+)|(\/?\\+)/g;
const contentPattern = /\\74\\160\\76[0-9a-fu/\\]+?\\74\/\\160\\76/g;
const regex16 = /\\u([\d\w]{4})/gi;
const regex8 = /\\([\d]{1,4})/gi;
module.exports = async (ctx) => {
const id = ctx.params.id;
const url = 'https://www.zhaishuyuan.com';
const link = `${url}/book/${id}`;
let extendedGot = got.extend({ headers: { Referer: url }, responseType: 'buffer' });
const response = await extendedGot.get(link);
const html = iconv.decode(response.data, 'gb2312');
const $ = cheerio.load(html);
const title = $('.booktitle > h1').text();
const description = $('#bookintro > p').text();
const image = $('#bookimg > img').attr('src');
const list = $('#newlist > ul > li')
.find('a')
.map((_, { attribs: { title, href } }) => ({ title, link: `${url}${href}` }))
.get();
extendedGot = got.extend({ headers: { Referer: link }, responseType: 'buffer' });
const item = await Promise.all(
list.map(({ title, link }) =>
ctx.cache.tryGet(link, async () => {
const response = await extendedGot.get(link);
const html = iconv.decode(response.data, 'gb2312');
const $ = cheerio.load(html);
const content = $('#content');
const encoded = $('#content > div');
if (encoded) {
// 提取编码后的正文内容进行复原
const rawText = html;
let rawContent = '';
for (const match of rawText.matchAll(tokenPattern)) {
if (match[1] in encodeMap) {
rawContent += encodeMap[match[1]];
}
if (match[2]) {
rawContent += match[2].replace('\\\\\\\\', '\\').replace('\\\\', '\\');
}
}
const decodedContentArr = [];
for (const contentPar of rawContent.matchAll(contentPattern)) {
const decodedStr = contentPar[0].replace(regex16, (match, grp) => String.fromCharCode(parseInt(grp, 16))).replace(regex8, (match, grp) => String.fromCharCode(parseInt(grp, 8)));
decodedContentArr.push(decodedStr);
}
encoded.before(decodedContentArr);
encoded.remove();
}
const description = content.html();
const spanList = $('.title > span');
const author = spanList.eq(0).find('a').text();
const pubDate = spanList.eq(2).text();
return { title, link, description, author, pubDate };
})
)
);
ctx.state.data = { title, link, description, image, item };
};
-41
View File
@@ -1,41 +0,0 @@
const cheerio = require('cheerio');
const got = require('@/utils/got');
module.exports = async (ctx) => {
const url = `http://news.bioon.com/${ctx.params.uid}`;
const res = await got.get(url);
const $ = cheerio.load(res.data);
const list = $('.cntx').get();
const out = await Promise.all(
list.slice(0, 3).map(async (item) => {
const $ = cheerio.load(item);
const title = $('.cntx h4 a').text();
const partial = $('.cntx h4 a').attr('href');
const address = partial;
const time = $('.fl huise').text();
const cache = await ctx.cache.get(address);
if (cache) {
return Promise.resolve(JSON.parse(cache));
}
const res = await got.get(address);
const get = cheerio.load(res.data);
const contents = get('.text3').html();
const single = {
title,
pubDate: time,
description: contents,
link: address,
guid: address,
};
ctx.cache.set(address, JSON.stringify(single));
return Promise.resolve(single);
})
);
ctx.state.data = {
title: $('title').text(),
link: url,
item: out,
};
};
-54
View File
@@ -1,54 +0,0 @@
const got = require('@/utils/got');
const cheerio = require('cheerio');
const { parseDate } = require('@/utils/parse-date');
module.exports = async (ctx) => {
const id = ctx.params.id;
const limit = parseInt(ctx.query.limit) || 5;
const work_url = `https://kakuyomu.jp/works/${id}`;
const $ = cheerio.load(await get(work_url));
const work_title = $('#workTitle').text();
const introduction = $('#introduction').text();
const episode_list = $('a.widget-toc-episode-episodeTitle')
.map((_, episode) => {
const $_episode = $(episode);
return {
title: $_episode.find('span').text(),
link: $_episode.attr('href'),
pubDate: parseDate($_episode.find('time').attr('datetime')),
};
})
.toArray()
.sort((a, b) => (a.pubDate <= b.pubDate ? 1 : -1))
.slice(0, limit);
const item_list = await Promise.all(
episode_list.map((episode) =>
ctx.cache.tryGet(episode.link, async () => {
episode.link = `https://kakuyomu.jp${episode.link}`;
const content = cheerio.load(await get(episode.link));
episode.description = content('.widget-episodeBody').html();
return episode;
})
)
);
ctx.state.data = {
title: work_title,
link: work_url,
description: introduction,
language: 'ja',
item: item_list,
};
};
const get = async (url) => {
const response = await got({
method: 'get',
url,
});
return response.data;
};
-3
View File
@@ -1,3 +0,0 @@
module.exports = {
'/episode/:id': ['huangliangshusheng'],
};
-13
View File
@@ -1,13 +0,0 @@
module.exports = {
'kakuyomu.jp': {
_name: 'kakuyomu',
'.': [
{
title: '章节更新',
docs: 'https://docs.rsshub.app/routes/reading#kakuyomu-zhang-jie-geng-xin',
source: ['/works/:id'],
target: '/kakuyomu/episode/:id',
},
],
},
};
-1
View File
@@ -1 +0,0 @@
module.exports = (router) => router.get('/episode/:id', require('./episode.js'));
-87
View File
@@ -1,87 +0,0 @@
const got = require('@/utils/got');
const cheerio = require('cheerio');
const timezone = require('@/utils/timezone');
const { parseDate } = require('@/utils/parse-date');
module.exports = async (ctx) => {
const category = ctx.params.category ?? 'shouding';
const type = ctx.params.type ?? (category === 'shouding' ? '' : '1');
const isHistory = /t|y/i.test(ctx.params.is_history ?? 'false');
const today = new Date();
today.setTime(new Date().getTime() - 24 * 60 * 60 * 1000);
const yesterday = `${today.getFullYear()}-${today.getMonth() + 1}-${today.getDate()}`;
const rootUrl = 'https://www.qidiantu.com';
const currentUrl = `${rootUrl}/${category === 'shouding' ? `${category}/` : `bang/${category}/${type}/${isHistory ? '' : yesterday}`}`;
const response = await got({
method: 'get',
url: currentUrl,
});
const $ = cheerio.load(response.data);
$('a[role="button"]').remove();
let items = $(isHistory ? 'ul li a' : 'tbody tr')
.slice(0, ctx.query.limit ? parseInt(ctx.query.limit) : 25)
.toArray()
.map((item) => {
item = $(item);
return isHistory
? {
title: item.text(),
link: `${rootUrl}${item.attr('href')}`,
}
: {
author: item.find('td').eq(3).text(),
title: item.find('td[value]').first().text(),
link: `${rootUrl}${item.find('td a').first().attr('href').replace(/\/d$/, '')}`,
category: item
.find(`td${category === 'shouding' ? '[value]' : ''}`)
.eq(1)
.text(),
};
});
items = await Promise.all(
items.map((item) =>
ctx.cache.tryGet(isHistory ? item.link : `${item.link}-${yesterday}`, async () => {
const detailResponse = await got({
method: 'get',
url: item.link,
});
const content = cheerio.load(detailResponse.data);
content('#demo').next().remove();
if (isHistory) {
item.description = content('.table-responsive').html();
item.pubDate = parseDate(item.link.split('/').pop());
} else {
item.description = content('.media').html() + content('.panel-body').html();
item.pubDate = timezone(
parseDate(
content('tbody tr')
.last()
.text()
.match(/刷新时间:(\d{4}-\d{2}-\d{2} \d{2}:\d{2})/)[1]
),
+8
);
}
return item;
})
)
);
ctx.state.data = {
title: `${$('.panel-heading').text()} - 起点图`,
link: currentUrl,
item: items,
};
};
-4
View File
@@ -1,4 +0,0 @@
module.exports = {
'/:category?/:type?/:is_history?': ['nczitzk'],
'/shouding': ['nczitzk'],
};
-19
View File
@@ -1,19 +0,0 @@
module.exports = {
'qidiantu.com': {
_name: '起点图',
'.': [
{
title: '首订',
docs: 'https://docs.rsshub.app/routes/reading#qi-dian-tu-shou-ding',
source: ['/shouding', '/'],
target: '/qidiantu/shouding',
},
{
title: '榜单',
docs: 'https://docs.rsshub.app/routes/reading#qi-dian-tu-bang-dan',
source: ['/bang/:category/:type', '/'],
target: '/qidiantu/:category?/:type?/:is_history?',
},
],
},
};
-3
View File
@@ -1,3 +0,0 @@
module.exports = function (router) {
router.get('/:category?/:type?/:is_history?', require('./index'));
};
-10
View File
@@ -515,16 +515,6 @@ In addition, we have prepared a Node.js script to help you use proxies to create
3. 找到 `https://bbs.pku.edu.cn/v2/home.php` 请求
4. 找到请求头中的 Cookie
### 吹牛部落
用于栏目
- `CHUINIU_MEMBER`: 吹牛部落登录后的 x-member,获取方式
1. 登陆后点开文章正文
2. 打开控制台,刷新
3. 找到 `http://api.duanshu.com/h5/content/detail` 开头的请求
4. 找到请求头中的 x-member
### 滴答清单
- `DIDA365_USERNAME`: 滴答清单用户名
-141
View File
@@ -38,24 +38,6 @@
<Route author="EthanWng97" example="/inoreader/rss/1005137674/user-favorites" path="/inoreader/rss/:user/:tag" paramsDesc={['user id, the interger after user/ in the example URL','tag, the string after tag/ in the example URL']} />
## kakuyomu {#kakuyomu}
### episode {#kakuyomu-episode}
<Route author="huangliangshusheng" example="/kakuyomu/episode/1177354054883783581" path="/kakuyomu/episode/:id" paramsDesc={['Novel id, can be found in URL']} notOperational="1">
Eg: [https://kakuyomu.jp/works/1177354054883783581](https://kakuyomu.jp/works/1177354054883783581)
</Route>
## Kindle Unlimited {#kindle-unlimited}
### 会员限时免费读书单 {#kindle-unlimited-hui-yuan-xian-shi-mian-fei-du-shu-dan}
<Route author="nczitzk" example="/amazon/ku/this" path="/amazon/ku/:type?" paramsDesc={['书单类型,见下表']} notOperational="1">
| 本月书单 | 好评返场 | 次月预告 |
| -------- | -------- | -------- |
| this | back | next |
</Route>
## Literotica {#literotica}
### New Stories {#literotica-new-stories}
@@ -162,12 +144,6 @@
| ---- | ---- | ---- | ---- | ---- | ---- | ---- | ---- | ---- | ---- | ---- | ---- |
</Route>
## 爱下电子书 {#ai-xia-dian-zi-shu}
### 最新章节 {#ai-xia-dian-zi-shu-zui-xin-zhang-jie}
<Route author="JeasonLau Maecenas" example="/axdzs/诡秘之主" path="/axdzs/:novel" paramsDesc={['小说的中文名, 可在对应小说页 URL 中找到']} />
## 笔趣阁 {#bi-qu-ge}
:::tip
@@ -216,12 +192,6 @@
:::
</Route>
## 博客来 {#bo-ke-lai}
### 新书出版 {#bo-ke-lai-xin-shu-chu-ban}
<Route author="CokeMine" example="/bookscomtw/newbooks/books_nbtopm_15" path="/bookscomtw/newbooks/:category" paramsDesc={['书籍类型 category, 可在对应博客来新书页 URL 中找到']} notOperational="1" />
## 超星 {#chao-xing}
### 期刊 {#chao-xing-qi-kan}
@@ -242,26 +212,6 @@
:::
</Route>
## 吹牛部落 {#chui-niu-bu-luo}
### 栏目 {#chui-niu-bu-luo-lan-mu}
<Route author="LogicJake" example="/chuiniu/column/0b1c4cf6e7f24e8da11e37882de73704" path="/chuiniu/column/:id" paramsDesc={['栏目 id, 可在对应栏目页 URL 中找到']} notOperational="1">
:::warning
正文内容需要用户登录后的 x-member 值,详情见部署页面的配置模块。若无相关配置或 x-member 失效,则只显示文章摘要。
:::
</Route>
### 专栏列表 {#chui-niu-bu-luo-zhuan-lan-lie-biao}
<Route author="LogicJake" example="/chuiniu/column_list" path="/chuiniu/column_list" notOperational="1" />
## 刺猬猫 {#ci-wei-mao}
### 章节 {#ci-wei-mao-zhang-jie}
<Route author="Netrvin" example="/ciweimao/chapter/100045750" path="/ciweimao/chapter/:id" paramsDesc={['小说 id, 可在对应小说页 URL 中找到']} notOperational="1" />
## 单向空间 {#dan-xiang-kong-jian}
### 单读 {#dan-xiang-kong-jian-dan-du}
@@ -272,22 +222,6 @@
| 0 | 1 | 2 | 3 | 4 | 6 |
</Route>
## 稻草人书屋 {#dao-cao-ren-shu-wu}
### 章节更新 {#dao-cao-ren-shu-wu-zhang-jie-geng-xin}
<Route author="JeasonLau" example="/dcrsw/zhongjidouluo/2" path="/dcrsw/:name/:count?" paramsDesc={['小说名,可在对应小说页URL中找到', '显示的章节数,缺省为`3`']} notOperational="1">
:::warning
count 的取值范围为 1-12,为防止请求次数过多,推荐设置为 5 以下。
:::
</Route>
## 第一版主 {#di-yi-ban-zhu}
### 小说 {#di-yi-ban-zhu-xiao-shuo}
<Route author="x1a0xv4n" example="/novel/d1bz/2/2608_6" path="/novel/d1bz/:category/:id" paramsDesc={['小说分类,可在对应小说页 URL 中找到,例如`2`', '小说id,可在对应小说页 URL 中找到,例如`2608_6`']} notOperational="1" />
## 东立出版 {#dong-li-chu-ban}
### NEWS 资讯 {#dong-li-chu-ban-news-zi-xun}
@@ -339,28 +273,12 @@
<Route author="nczitzk" example="/kongfz/shop/238901/1" path="/kongfz/shop/:id/:cat?" paramsDesc={['店铺 id, 可在对应店铺页 URL 中找到', '分类 id,可在对应分类页 URL 中找到,默认为店铺最新上架']} />
## 快眼看书 {#kuai-yan-kan-shu}
### 小说更新 {#kuai-yan-kan-shu-xiao-shuo-geng-xin}
<Route author="squkw" example="/novel/booksky/98619" path="/novel/booksky/:id" paramsDesc={['小说 id, 可在对应小说页 URL 中找到, 例如 `98619`']} notOperational="1">
举例网址:`http://booksky.so/BookDetail.aspx?Level=1&bid=98619`
</Route>
## 哩哔轻小说 {#li-bi-qing-xiao-shuo}
### 小说更新 {#li-bi-qing-xiao-shuo-xiao-shuo-geng-xin}
<Route author="misakicoca" path="/linovelib/novel/:id" example="/linovelib/novel/2547" paramsDesc={['小说 id,对应书架开始阅读 URL 中找到']} anticrawler="1" />
## 飘天文学 {#piao-tian-wen-xue}
### 章节 {#piao-tian-wen-xue-zhang-jie}
<Route author="LJason77" example="/novel/ptwxz/10/10272" path="/novel/ptwxz/:id1/:id2" paramsDesc={['小说网站链接倒数第二部分的数字, 可在对应小说页 URL 中找到, 例如 `10`', '小说网站链接最后的数字, 可在对应小说页 URL 中找到, 例如 `10272`']} notOperational="1">
举例网址:`https://www.ptwxz.com/bookinfo/10/10272.html`
</Route>
## 起点 {#qi-dian}
### 章节 {#qi-dian-zhang-jie}
@@ -383,24 +301,6 @@
<Route author="miles170" example="/qidian/author/9639927" path="/qidian/author/:id" paramsDesc={['作者 id, 可在作者页面 URL 找到']} />
## 起点图 {#qi-dian-tu}
### 首订 {#qi-dian-tu-shou-ding}
<Route author="nczitzk" example="/qidiantu/shouding" path="/qidiantu/shouding" notOperational="1" />
### 榜单 {#qi-dian-tu-bang-dan}
<Route author="nczitzk" example="/qidiantu" path="/qidiantu/:category?/:type?/:is_history?" paramsDesc={['分类', '类型', '是否查看历史榜单,填写 true/yes 表示是,默认否']} notOperational="1">
:::tip
参数 **是否查看历史榜单** 设置为 `true` `yes` `t` `y` 等值后,RSS 会返回历史榜单。
如 [`/qidiantu/1/1/t`](https://rsshub.app/qidiantu/1/1/t) 将会返回 [起点首页 - 封推 的历史推荐记录](https://www.qidiantu.com/bang/1/1/) 的结果。
而 [`/qidiantu/1/1`](https://rsshub.app/qidiantu/1/1) 将会返回最新一期 [收藏增长 (起点首页 - 封推)](https://www.qidiantu.com/bang/1/1/2021-12-14) 的结果(编写文档时最新一期为 2021-12-14)。
:::
</Route>
## 青空文庫 {#qing-kong-wen-ku}
### 青空文庫新着リスト {#qing-kong-wen-ku-qing-kong-wen-ku-xin-zhe-%E3%83%AA%E3%82%B9%E3%83%88}
@@ -437,31 +337,6 @@
<Route author="eternasuno" example="/yomujp/n1" path="/yomujp/:level?" paramsDesc={['等级,n1~n6,为空默认全部']} />
## 生物帮 {#sheng-wu-bang}
### 所有栏目 {#sheng-wu-bang-suo-you-lan-mu}
<Route author="xfangbao" example="/biobio/nature/cell-reports" path="/biobio/:column/:id" paramsDesc={['', '']} notOperational="1" />
具体栏目编号,去网站上看标签
| 网址 | 对应路由 |
| ------------------------------------------------ | ----------------------------------- |
| `http://science.bio1000.com/ecology-environment` | /biobio/science/ecology-environment |
| `http://www.bio1000.com/gnjz` | /biobio/gnjz |
## 生物谷 {#sheng-wu-gu}
### 所有栏目 {#sheng-wu-gu-suo-you-lan-mu}
<Route author="xfangbao" example="/shengwugu/biology" path="/shengwugu/:uid/" paramsDesc={['分栏代码, 可在 URL 找到']} notOperational="1" />
具体栏目编号,去网站上看标签
| 网址 | 对应路由 |
| ------------------------------- | ------------------ |
| `http://news.bioon.com/biology` | /shengwugu/biology |
## 书伴 {#shu-ban}
### 分类 {#shu-ban-fen-lei}
@@ -472,14 +347,6 @@
| weekly | skills | books | news | essay |
</Route>
## 文学迷 {#wen-xue-mi}
### 小说更新 {#wen-xue-mi-xiao-shuo-geng-xin}
<Route author="lengthmin" example="/novel/wenxuemi/6/6144" path="/novel/wenxuemi/:id1/:id2" paramsDesc={['小说网站链接倒数第二部分的数字, 可在对应小说页 URL 中找到, 例如 `6`', '小说网站链接最后的数字, 可在对应小说页 URL 中找到, 例如 `6144`']} notOperational="1">
举例网址:`https://www.wenxuemi.com/files/article/html/6/6144/`
</Route>
## 虛詞 {#xu-ci}
### 版块 {#xu-ci-ban-kuai}
@@ -490,14 +357,6 @@
<Route author="LogicJake" example="/p-articles/contributors/朗天" path="/p-articles/contributors/:author" paramsDesc={['作者 id, 可在作者页面 URL 找到']} />
## 斋书苑 {#zhai-shu-yuan}
### 最新章节 {#zhai-shu-yuan-zui-xin-zhang-jie}
<Route author="suiyuran" example="/novel/zhaishuyuan/17858" path="/novel/zhaishuyuan/:id" paramsDesc={['小说 id, 可在对应小说页 URL 中找到, 例如 `17858`']} radar="1" notOperational="1">
举例网址:`https://www.zhaishuyuan.com/book/17858`
</Route>
## 纵横 {#zong-heng}
### 章节 {#zong-heng-zhang-jie}
@@ -499,16 +499,6 @@ RSSHub 支持使用访问密钥 / 码,允许清单和拒绝清单三种方式
3. 找到 `https://bbs.pku.edu.cn/v2/home.php` 请求
4. 找到请求头中的 Cookie
### 吹牛部落
用于栏目
- `CHUINIU_MEMBER`: 吹牛部落登录后的 x-member,获取方式
1. 登陆后点开文章正文
2. 打开控制台,刷新
3. 找到 `http://api.duanshu.com/h5/content/detail` 开头的请求
4. 找到请求头中的 x-member
### 滴答清单
- `DIDA365_USERNAME`: 滴答清单用户名