feat: 添加漫画柜个人订阅 (#10727)

* 1

1

* 添加个人订阅

* Delete 1

* Add files via upload

* 添加mhgui的cookie获取

* 添加manhuagui个人订阅

* Add files via upload

* Update subscribe.js

* Update subscribe.js

* style: auto format

* 修改 manhuagui/selfhost=1

Co-authored-by: Tony <TonyRL@users.noreply.github.com>

* Update docs/anime.md

Co-authored-by: Tony <TonyRL@users.noreply.github.com>

* manhuagui规范文档

* style: auto format

* 添加漫画柜渲染文件

* 使用模板渲染,修改radar格式

* style: auto format

* refactor: migrate to v2

Co-authored-by: github-actions[bot] <41898282+github-actions[bot]@users.noreply.github.com>
This commit is contained in:
shininome
2022-09-07 22:32:41 +08:00
committed by GitHub
parent 7ef62beb65
commit 41e4d7cf84
13 changed files with 150 additions and 256 deletions
-3
View File
@@ -97,9 +97,6 @@
'ishuhui.com': { _name: '鼠绘漫画', www: [{ title: '鼠绘漫画', docs: 'https://docs.rsshub.app/anime.html#shu-hui-man-hua', source: '/comics/anime/:id', target: '/shuhui/comics/:id' }] },
'www.chicagotribune.com': { _name: 'Chicago Tribune', www: [{ title: 'Chicago Tribune', docs: 'https://docs.rsshub.app/traditional_media.html#chicago-tribune', source: '/' }] },
'haimaoba.com': { _name: '海猫吧', www: [{ title: '漫画更新', docs: 'https://docs.rsshub.app/anime.html#hai-mao-ba', source: '/catalog/:id', target: '/haimaoba/:id' }] },
'manhuagui.com': { _name: '漫画柜', www: [{ title: '漫画更新', docs: 'https://docs.rsshub.app/anime.html#kan-man-hua', source: '/comic/:id/', target: '/manhuagui/comic/:id/5' }] },
'mhgui.com': { _name: '漫画柜镜像站', www: [{ title: '漫画更新', docs: 'https://docs.rsshub.app/anime.html#kan-man-hua-jing-xiang-zhan', source: '/comic/:id/', target: '/mhgui/comic/:id/5' }] },
'tw.manhuagui.com': { _name: '漫画柜台湾', www: [{ title: '漫画更新', docs: 'https://docs.rsshub.app/anime.html#kan-man-hua-tai-wan', source: '/comic/:id/', target: '/twmanhuagui/comic/:id' }] },
'copymanga.com': { _name: '拷贝漫画', www: [{ title: '漫画更新', docs: 'https://docs.rsshub.app/anime.html#kao-bei-man-hua', source: '/comic/:id/', target: '/manhuagui/comic/:id/5' }] },
'pgyer.com': { _name: '蒲公英应用分发', www: [{ title: 'app更新', docs: 'https://docs.rsshub.app/program-update.html#pu-gong-ying-ying-yong-fen-fa', source: '/:app', target: '/pgyer/:app' }] },
'wineyun.com': { _name: '酒云网', www: [{ title: '最新商品', docs: 'https://docs.rsshub.app/other.html#jiu-yun-wang', source: ['/:category'], target: '/wineyun/:category' }] },
+15 -6
View File
@@ -567,17 +567,26 @@ Sources
<Route author="MegrezZhu" path="/manhuagui/comic/:id/:chapterCnt?" example="/manhuagui/comic/22942/5" :paramsDesc="['漫画ID','返回章节的数量,默认为0,返回所有章节']" radar="1" rssbud="1"/>
## 看漫画镜像站
### 漫画个人订阅
### 漫画更新
<Route author="shininome" path="/manhuagui/subscribe" example="/manhuagui/subscribe" radar="1" rssbud="1" selfhost="1">
<Route author="btdwv" path="/mhgui/comic/:id/:chapterCnt?" example="/mhgui/comic/13317/5" :paramsDesc="['漫画ID','返回章节的数量,默认为0,返回所有章节']" radar="1" rssbud="1"/>
::: tip 提示
## 看漫画台湾
个人订阅需要自建
环境变量需要添加 MHGUI_COOKIE
### 漫画更新
:::
<Route author="btdwv" path="/twmanhuagui/comic/:id/:chapterCnt?" example="/twmanhuagui/comic/13317/5" :paramsDesc="['漫画ID','返回章节的数量,默认为0,返回所有章节']" radar="1" rssbud="1"/>
</Route>
### 镜像站 - 漫画更新
<Route author="btdwv" path="/manhuagui/mhgui/comic/:id/:chapterCnt?" example="/manhuagui/mhgui/comic/13317/5" :paramsDesc="['漫画ID','返回章节的数量,默认为0,返回所有章节']" radar="1" rssbud="1"/>
### 台湾站 - 漫画更新
<Route author="btdwv" path="/manhuagui/twmanhuagui/comic/:id/:chapterCnt?" example="/manhuagui/twmanhuagui/comic/13317/5" :paramsDesc="['漫画ID','返回章节的数量,默认为0,返回所有章节']" radar="1" rssbud="1"/>
## 拷贝漫画
+3
View File
@@ -185,6 +185,9 @@ const calculateValue = () => {
lastfm: {
api_key: envs.LASTFM_API_KEY,
},
manhuagui: {
cookie: envs.MHGUI_COOKIE,
},
mastodon: {
apiHost: envs.MASTODON_API_HOST,
accessToken: envs.MASTODON_API_ACCESS_TOKEN,
-33
View File
@@ -167,39 +167,6 @@ module.exports = {
},
],
},
'manhuagui.com': {
_name: '漫画柜',
www: [
{
title: '漫画更新',
docs: 'https://docs.rsshub.app/anime.html#kan-man-hua',
source: '/comic/:id/',
target: '/manhuagui/comic/:id',
},
],
},
'mhgui.com': {
_name: '漫画柜镜像站',
www: [
{
title: '漫画更新',
docs: 'https://docs.rsshub.app/anime.html#kan-man-hua-jing-xiang-zhan',
source: '/comic/:id/',
target: '/mhgui/comic/:id',
},
],
},
'tw.manhuagui.com': {
_name: '漫画柜台湾',
www: [
{
title: '漫画更新',
docs: 'https://docs.rsshub.app/anime.html#kan-man-hua-tai-wan',
source: '/comic/:id/',
target: '/twmanhuagui/comic/:id',
},
],
},
'pgyer.com': {
_name: '蒲公英应用分发',
www: [
+5 -4
View File
@@ -996,10 +996,11 @@ router.get('/eeo/:column?/:category?', lazyloadRouteHandler('./routes/eeo/index'
// 腾讯视频
router.get('/tencentvideo/playlist/:id', lazyloadRouteHandler('./routes/tencent/video/playlist'));
// 看漫画
router.get('/manhuagui/comic/:id/:chapterCnt?', lazyloadRouteHandler('./routes/manhuagui/comic'));
router.get('/mhgui/comic/:id/:chapterCnt?', lazyloadRouteHandler('./routes/mhgui/comic'));
router.get('/twmanhuagui/comic/:id/:chapterCnt?', lazyloadRouteHandler('./routes/twmanhuagui/comic'));
// 看漫画 migrated to v2
// router.get('/manhuagui/comic/:id/:chapterCnt?', lazyloadRouteHandler('./routes/manhuagui/comic'));
// router.get('/mhgui/comic/:id/:chapterCnt?', lazyloadRouteHandler('./routes/mhgui/comic'));
// router.get('/twmanhuagui/comic/:id/:chapterCnt?', lazyloadRouteHandler('./routes/twmanhuagui/comic'));
// 拷贝漫画
router.get('/copymanga/comic/:id/:chapterCnt?', lazyloadRouteHandler('./routes/copymanga/comic'));
-99
View File
@@ -1,99 +0,0 @@
const { resolve } = require('url');
const cheerio = require('cheerio');
const got = require('@/utils/got');
const LZString = require('lz-string');
const getChapters = ($) => {
let time_mark = 0;
// 用于一次更新多个新章节的排序
let new_time_mark = 0;
return $('h4')
.toArray()
.map((ele) => {
const categoryName = $(ele).text();
while (!$(ele.next).hasClass('chapter-list')) {
ele = ele.next;
}
ele = ele.next;
return $(ele)
.children('ul')
.toArray()
.reverse()
.reduce((acc, curr) => acc.concat($(curr).children('li').toArray()), [])
.map((ele) => {
const a = $(ele).children('a');
// 通过操作发布时间来对章节进行排序,如果是刚刚更新的单行本或者番外,保留最新更新时间
let pDate = new Date(new Date($.pubDate) - time_mark++ * 1000);
if (a.find('em').length > 0) {
// 对更新的章节也进行排序
pDate = new Date(new Date($.pubDate) - new_time_mark++ * 1000);
$.newChapterCnt++;
}
return {
link: resolve('https://www.mhgui.com/', a.attr('href')),
title: a.attr('title'),
pub_date: pDate,
num: a.find('i').text(),
guid: resolve('https://www.mhgui.com/', a.attr('href')),
category: categoryName,
};
});
})
.reduce((acc, curr) => acc.concat(curr));
};
module.exports = async (ctx) => {
const { id } = ctx.params;
const chapterCnt = Number(ctx.params.chapterCnt || 0);
const { data } = await got.get(`https://www.mhgui.com/comic/${id}/`);
const $ = cheerio.load(data);
if ($('#__VIEWSTATE').length > 0) {
const n = LZString.decompressFromBase64($('#__VIEWSTATE').val());
if (n) {
$('#erroraudit_show').replaceWith(n);
$('#__VIEWSTATE').remove();
}
}
const bookTitle = $('.book-title > h1').text();
const bookIntro = $('#intro-all').text();
const coverImgSrc = $('.book-cover img').attr('src');
// 对最新更新的章节增加了pubDate
const reg = new RegExp('最近于.+更新至');
// 处理已下架的漫画
if ($('.status > span').text().indexOf('已下架') > 0) {
ctx.state.data = {
title: `看漫画 - ${bookTitle} 已下架`,
link: `https://www.mhgui.com/comic/${id}/`,
description: bookIntro,
item: [{ link: `https://www.mhgui.com/comic/${id}/`, title: bookTitle, description: '已下架' }],
};
} else {
const pub_date_str = $('.status > span').text().match(reg)[0].replace('最近于 [', '').replace('] 更新至', '');
// 为了能在闭包内访问到这个日期而不是每次需要处理这个最近更新日期
$.pubDate = new Date(pub_date_str).toUTCString();
$.newChapterCnt = 0;
const chapters = getChapters($);
const genResult = (chapter) => ({
link: chapter.link,
title: chapter.title,
pubDate: chapter.pub_date,
guid: chapter.guid,
category: chapter.category,
description: `
<h1>${chapter.num}</h1>
<img src='${coverImgSrc}' />
`.trim(),
});
const items = chapters.map(genResult);
let itemsLen = items.length;
if (chapterCnt > 0) {
itemsLen = chapterCnt < $.newChapterCnt ? $.newChapterCnt : chapterCnt;
}
ctx.state.data = {
title: `看漫画 - ${bookTitle}`,
link: `https://www.mhgui.com/comic/${id}/`,
description: bookIntro,
item: items.slice(0, itemsLen),
};
}
};
-99
View File
@@ -1,99 +0,0 @@
const { resolve } = require('url');
const cheerio = require('cheerio');
const got = require('@/utils/got');
const LZString = require('lz-string');
const getChapters = ($) => {
let time_mark = 0;
// 用于一次更新多个新章节的排序
let new_time_mark = 0;
return $('h4')
.toArray()
.map((ele) => {
const categoryName = $(ele).text();
while (!$(ele.next).hasClass('chapter-list')) {
ele = ele.next;
}
ele = ele.next;
return $(ele)
.children('ul')
.toArray()
.reverse()
.reduce((acc, curr) => acc.concat($(curr).children('li').toArray()), [])
.map((ele) => {
const a = $(ele).children('a');
// 通过操作发布时间来对章节进行排序,如果是刚刚更新的单行本或者番外,保留最新更新时间
let pDate = new Date(new Date($.pubDate) - time_mark++ * 1000);
if (a.find('em').length > 0) {
// 对更新的章节也进行排序
pDate = new Date(new Date($.pubDate) - new_time_mark++ * 1000);
$.newChapterCnt++;
}
return {
link: resolve('https://tw.manhuagui.com/', a.attr('href')),
title: a.attr('title'),
pub_date: pDate,
num: a.find('i').text(),
guid: resolve('https://tw.manhuagui.com/', a.attr('href')),
category: categoryName,
};
});
})
.reduce((acc, curr) => acc.concat(curr));
};
module.exports = async (ctx) => {
const { id } = ctx.params;
const chapterCnt = Number(ctx.params.chapterCnt || 0);
const { data } = await got.get(`https://tw.manhuagui.com/comic/${id}/`);
const $ = cheerio.load(data);
if ($('#__VIEWSTATE').length > 0) {
const n = LZString.decompressFromBase64($('#__VIEWSTATE').val());
if (n) {
$('#erroraudit_show').replaceWith(n);
$('#__VIEWSTATE').remove();
}
}
const bookTitle = $('.book-title > h1').text();
const bookIntro = $('#intro-all').text();
const coverImgSrc = $('.book-cover img').attr('src');
// 对最新更新的章节增加了pubDate
const reg = new RegExp('最近於.+更新至');
// 处理已下架的漫画
if ($('.status > span').text().indexOf('已下架') > 0) {
ctx.state.data = {
title: `看漫画 - ${bookTitle} 已下架`,
link: `https://tw.manhuagui.com/comic/${id}/`,
description: bookIntro,
item: [{ link: `https://tw.manhuagui.com/comic/${id}/`, title: bookTitle, description: '已下架' }],
};
} else {
const pub_date_str = $('.status > span').text().match(reg)[0].replace('最近於 [', '').replace('] 更新至', '');
// 为了能在闭包内访问到这个日期而不是每次需要处理这个最近更新日期
$.pubDate = new Date(pub_date_str).toUTCString();
$.newChapterCnt = 0;
const chapters = getChapters($);
const genResult = (chapter) => ({
link: chapter.link,
title: chapter.title,
pubDate: chapter.pub_date,
guid: chapter.guid,
category: chapter.category,
description: `
<h1>${chapter.num}</h1>
<img src='${coverImgSrc}' />
`.trim(),
});
const items = chapters.map(genResult);
let itemsLen = items.length;
if (chapterCnt > 0) {
itemsLen = chapterCnt < $.newChapterCnt ? $.newChapterCnt : chapterCnt;
}
ctx.state.data = {
title: `看漫画 - ${bookTitle}`,
link: `https://tw.manhuagui.com/comic/${id}/`,
description: bookIntro,
item: items.slice(0, itemsLen),
};
}
};
@@ -1,7 +1,9 @@
const { resolve } = require('url');
const cheerio = require('cheerio');
const got = require('@/utils/got');
const LZString = require('lz-string');
const { parseDate } = require('@/utils/parse-date');
let baseUrl = '';
const getChapters = ($) => {
let time_mark = 100;
@@ -30,21 +32,29 @@ const getChapters = ($) => {
$.newChapterCnt++;
}
return {
link: resolve('https://www.manhuagui.com/', a.attr('href')),
link: new URL(a.attr('href'), baseUrl).href,
title: a.attr('title'),
pub_date: pDate,
num: a.find('i').text(),
guid: resolve('https://www.manhuagui.com/', a.attr('href')),
category: categoryName,
};
});
})
.reduce((acc, curr) => acc.concat(curr));
};
module.exports = async (ctx) => {
const { id } = ctx.params;
const { id, domain } = ctx.params;
if (domain === 'mhgui') {
baseUrl = 'https://www.mhgui.com';
} else if (domain === 'twmanhuagui') {
baseUrl = 'https://tw.manhuagui.com';
} else {
baseUrl = 'https://www.manhuagui.com';
}
const chapterCnt = Number(ctx.params.chapterCnt || 0);
const { data } = await got.get(`https://www.manhuagui.com/comic/${id}/`);
const { data } = await got(`${baseUrl}/comic/${id}/`);
const $ = cheerio.load(data);
if ($('#__VIEWSTATE').length > 0) {
@@ -54,30 +64,34 @@ module.exports = async (ctx) => {
$('#__VIEWSTATE').remove();
}
}
const bookTitle = $('.book-title > h1').text();
const bookIntro = $('#intro-all').text();
const coverImgSrc = $('.book-cover img').attr('src');
// 对最新更新的章节增加了pubDate
const reg = new RegExp('最近.+更新至');
const reg = new RegExp('最近(?:于|於).+更新至');
// 处理已下架的漫画
if ($('.status > span').text().indexOf('已下架') > 0) {
ctx.state.data = {
title: `看漫画 - ${bookTitle} 已下架`,
link: `https://www.manhuagui.com/comic/${id}/`,
link: `${baseUrl}/comic/${id}/`,
description: bookIntro,
item: [{ link: `https://www.manhuagui.com/comic/${id}/`, title: bookTitle, description: '已下架' }],
item: [{ link: `${baseUrl}/comic/${id}/`, title: bookTitle, description: '已下架' }],
};
} else {
const pub_date_str = $('.status > span').text().match(reg)[0].replace('最近于 [', '').replace('] 更新至', '');
const pub_date_str = $('.status > span')
.text()
.match(reg)[0]
.replace(/最近(?:于|於) \[/, '')
.replace('] 更新至', '');
// 为了能在闭包内访问到这个日期而不是每次需要处理这个最近更新日期
$.pubDate = new Date(pub_date_str).toUTCString();
$.pubDate = parseDate(pub_date_str);
$.newChapterCnt = 0;
const chapters = getChapters($);
const genResult = (chapter) => ({
link: chapter.link,
title: chapter.title,
pubDate: chapter.pub_date,
guid: chapter.guid,
category: chapter.category,
description: `
<h1>${chapter.num}</h1>
@@ -89,9 +103,10 @@ module.exports = async (ctx) => {
if (chapterCnt > 0) {
itemsLen = chapterCnt < $.newChapterCnt ? $.newChapterCnt : chapterCnt;
}
ctx.state.data = {
title: `看漫画 - ${bookTitle}`,
link: `https://www.manhuagui.com/comic/${id}/`,
link: `${baseUrl}/comic/${id}/`,
description: bookIntro,
item: items.slice(0, itemsLen),
};
+6
View File
@@ -0,0 +1,6 @@
module.exports = {
'/comic/:id/:chapterCnt?': ['MegrezZhu'],
'/mhgui/comic/:id/:chapterCnt?': ['btdwv'],
'/subscribe': ['shininome'],
'/twmanhuagui/comic/:id/:chapterCnt?': ['btdwv'],
};
+33
View File
@@ -0,0 +1,33 @@
const rules = [
{
title: '漫画柜个人订阅',
docs: 'https://docs.rsshub.app/anime.html#kan-man-hua',
source: '/user/book/shelf',
target: '/manhuagui/subscribe',
},
{
title: '漫画更新',
docs: 'https://docs.rsshub.app/anime.html#kan-man-hua',
source: '/comic/:id/',
target: '/manhuagui/comic/:id',
},
];
module.exports = {
'manhuagui.com': {
_name: '漫画柜',
www: rules,
tw: [
{
title: '漫画更新',
docs: 'https://docs.rsshub.app/anime.html#kan-man-hua',
source: '/comic/:id/',
target: '/manhuagui/twmanhuagui/comic/:id',
},
],
},
'mhgui.com': {
_name: '漫画柜镜像站',
www: rules,
},
};
+5
View File
@@ -0,0 +1,5 @@
module.exports = function (router) {
router.get('/comic/:id/:chapterCnt?', require('./comic'));
router.get('/:domain?/comic/:id/:chapterCnt?', require('./comic'));
router.get('/subscribe', require('./subscribe'));
};
+54
View File
@@ -0,0 +1,54 @@
const got = require('@/utils/got');
const { parseRelativeDate } = require('@/utils/parse-date');
const cheerio = require('cheerio');
const { art } = require('@/utils/render');
const path = require('path');
const config = require('@/config').value;
const web_url = 'https://www.manhuagui.com/user/book/shelf/1';
module.exports = async (ctx) => {
if (!config.manhuagui || !config.manhuagui.cookie) {
throw 'manhuagui RSS is disabled due to the lack of <a href="https://docs.rsshub.app/install/#pei-zhi-bu-fen-rss-mo-kuai-pei-zhi">relevant config</a>';
}
const cookie = config.manhuagui.cookie;
const response = await got({
method: 'get',
url: web_url,
headers: {
Cookie: cookie,
},
});
const $ = cheerio.load(response.data);
const user_name = $('.avatar-box').find('h3').text();
const title = `${user_name} 的 漫画订阅`;
const link = web_url;
const description = `${user_name} 的 漫画订阅`;
const item = $('.dy_content_li')
.map(function () {
const img_src = $(this).find('img').attr('src'); // 漫画的封面
const manga_title = $(this).find('.co_1.c_space').first().text(); // 最新的一话题目
const title = $(this).find('img').attr('alt'); // 漫画的名字
const link = $(this).find('.co_1.c_space').first().children().attr('href'); // 漫画最新的链接
const description = art(path.join(__dirname, 'templates/manga.art'), {
manga_title,
img_src,
});
const pubDate = $(this).find('.co_1.c_space').first().next().text();
const publishDate = parseRelativeDate(pubDate); // 处理相对时间
const single = {
title,
link,
description,
pubDate: publishDate,
};
return single;
})
.get(); // 这里获取数组= =
ctx.state.data = {
title,
link,
description,
item,
};
};
+2
View File
@@ -0,0 +1,2 @@
<h1>{{manga_title}}</h1>
<img src="{{img_src}}" />