mirror of
https://github.com/DIYgod/RSSHub.git
synced 2025-12-11 15:47:48 +08:00
feat(route): add e-hentai (#7741)
This commit is contained in:
@@ -3042,6 +3042,34 @@
|
|||||||
},
|
},
|
||||||
],
|
],
|
||||||
},
|
},
|
||||||
|
'e-hentai.org/': {
|
||||||
|
_name: 'E-Hentai',
|
||||||
|
'.': [
|
||||||
|
{
|
||||||
|
title: '收藏',
|
||||||
|
docs: 'https://docs.rsshub.app/picture.html#ehentai',
|
||||||
|
source: '/favorites.php',
|
||||||
|
target: '/ehentai/favorites',
|
||||||
|
},
|
||||||
|
{
|
||||||
|
title: '标签',
|
||||||
|
docs: 'https://docs.rsshub.app/picture.html#ehentai',
|
||||||
|
source: '/tag/:tag',
|
||||||
|
target: '/ehentai/tag/:tag',
|
||||||
|
},
|
||||||
|
{
|
||||||
|
title: '搜索',
|
||||||
|
docs: 'https://docs.rsshub.app/picture.html#ehentai',
|
||||||
|
source: '/',
|
||||||
|
target: (params, url) => {
|
||||||
|
const keyword = new URL(url).searchParams.toString();
|
||||||
|
if (keyword) {
|
||||||
|
return `/ehentai/search/${keyword}`;
|
||||||
|
}
|
||||||
|
},
|
||||||
|
},
|
||||||
|
],
|
||||||
|
},
|
||||||
'iyingdi.com': {
|
'iyingdi.com': {
|
||||||
_name: '旅法师营地',
|
_name: '旅法师营地',
|
||||||
www: [
|
www: [
|
||||||
|
|||||||
@@ -696,3 +696,8 @@ RSSHub 支持使用访问密钥 / 码,白名单和黑名单三种方式进行
|
|||||||
| <https://pic1.xuehuaimg.com/proxy/> | cloudflare |
|
| <https://pic1.xuehuaimg.com/proxy/> | cloudflare |
|
||||||
| <https://cors.netnr.workers.dev/> | cloudflare |
|
| <https://cors.netnr.workers.dev/> | cloudflare |
|
||||||
| <https://netnr-proxy.openode.io/> | digitalocean |
|
| <https://netnr-proxy.openode.io/> | digitalocean |
|
||||||
|
|
||||||
|
- E-Hentai
|
||||||
|
- `EH_IPB_MEMBER_ID`: E-Hentai 账户登录后 cookie 的 `ipb_member_id` 值
|
||||||
|
- `EH_IPB_PASS_HASH`: E-Hentai 账户登录后 cookie 的 `ipb_pass_hash` 值
|
||||||
|
- `EH_SK`: E-Hentai 账户登录后 cookie 中的`sk`值
|
||||||
|
|||||||
@@ -479,3 +479,17 @@ R18 显示
|
|||||||
### 最新主题
|
### 最新主题
|
||||||
|
|
||||||
<Route author="nczitzk" example="/zhutix/latest" path="/zhutix/latest"/>
|
<Route author="nczitzk" example="/zhutix/latest" path="/zhutix/latest"/>
|
||||||
|
|
||||||
|
## E-Hentai
|
||||||
|
|
||||||
|
### 收藏
|
||||||
|
|
||||||
|
<Route author="Howard Yin" example="/ehentai/favorites/0/posted" path="/ehentai/favorites/:favcat?/:order?/:page?/:bittorrent?" :paramsDesc="['收藏夹编号,可选','顺序,可选:posted-按画廊发布时间排序,favorited-按添加收藏的时间排序', '爬获取第多少页的数据', '是否获取种子链接']" anticrawler="1" supportBT="1" />
|
||||||
|
|
||||||
|
### 标签
|
||||||
|
|
||||||
|
<Route author="Howard Yin" example="/ehentai/tag/language:chinese/1" path="/ehentai/tag/:tag/:page?/:bittorrent?" :paramsDesc="['标签', '爬获取第多少页的数据', '是否获取种子链接']" anticrawler="1" supportBT="1" />
|
||||||
|
|
||||||
|
### 搜索
|
||||||
|
|
||||||
|
<Route author="Howard Yin" example="/ehentai/search/:params?/:page?" path="/ehentai/search/:params?/:page?/:bittorrent?" :paramsDesc="['用于搜索的关键词。可在原网站搜索后复制 `https://e-hentai.org/?` 后面的内容', '爬获取第多少页的数据', '是否获取种子链接']" anticrawler="1" supportBT="1" />
|
||||||
|
|||||||
@@ -193,6 +193,11 @@ const calculateValue = () => {
|
|||||||
wordpress: {
|
wordpress: {
|
||||||
cdnUrl: envs.WORDPRESS_CDN,
|
cdnUrl: envs.WORDPRESS_CDN,
|
||||||
},
|
},
|
||||||
|
ehentai: {
|
||||||
|
ipb_member_id: envs.EH_IPB_MEMBER_ID,
|
||||||
|
ipb_pass_hash: envs.EH_IPB_PASS_HASH,
|
||||||
|
sk: envs.EH_SK,
|
||||||
|
},
|
||||||
};
|
};
|
||||||
};
|
};
|
||||||
calculateValue();
|
calculateValue();
|
||||||
|
|||||||
@@ -4140,6 +4140,11 @@ router.get('/tongli/news/:type', lazyloadRouteHandler('./routes/tongli/news'));
|
|||||||
// OR
|
// OR
|
||||||
router.get('/or/:id?', lazyloadRouteHandler('./routes/or'));
|
router.get('/or/:id?', lazyloadRouteHandler('./routes/or'));
|
||||||
|
|
||||||
|
// e-hentai
|
||||||
|
router.get('/ehentai/favorites/:favcat?/:order?/:page?/:bittorrent?', lazyloadRouteHandler('./routes/ehentai/favorites'));
|
||||||
|
router.get('/ehentai/search/:params?/:page?/:bittorrent?', lazyloadRouteHandler('./routes/ehentai/search'));
|
||||||
|
router.get('/ehentai/tag/:tag/:page?/:bittorrent?', lazyloadRouteHandler('./routes/ehentai/tag'));
|
||||||
|
|
||||||
// 字型故事
|
// 字型故事
|
||||||
router.get('/fontstory', require('./routes/fontstory/tw'));
|
router.get('/fontstory', require('./routes/fontstory/tw'));
|
||||||
|
|
||||||
|
|||||||
134
lib/routes/ehentai/ehapi.js
Normal file
134
lib/routes/ehentai/ehapi.js
Normal file
@@ -0,0 +1,134 @@
|
|||||||
|
const got = require('@/utils/got');
|
||||||
|
const cheerio = require('cheerio');
|
||||||
|
const config = require('@/config').value.ehentai;
|
||||||
|
|
||||||
|
const headers = {};
|
||||||
|
const has_cookie = config.ipb_member_id && config.ipb_pass_hash && config.sk;
|
||||||
|
if (has_cookie) {
|
||||||
|
const { ipb_member_id, ipb_pass_hash, sk } = config;
|
||||||
|
headers.cookie = `ipb_member_id=${ipb_member_id};ipb_pass_hash=${ipb_pass_hash};sk=${sk}`;
|
||||||
|
}
|
||||||
|
|
||||||
|
function ehgot(url) {
|
||||||
|
return got({ method: 'get', url: `https://e-hentai.org/${url}`, headers });
|
||||||
|
}
|
||||||
|
|
||||||
|
async function parsePage(cache, data, get_bittorrent = false) {
|
||||||
|
const $ = cheerio.load(data);
|
||||||
|
const table = $('table[class="itg gltc"] tbody');
|
||||||
|
if (!table) {
|
||||||
|
return [];
|
||||||
|
}
|
||||||
|
|
||||||
|
async function parseTableRow(cache, element) {
|
||||||
|
const el = $(element);
|
||||||
|
const el_a = el.find('td[class="gl3c glname"] a');
|
||||||
|
const el_img = el.find('td.gl2c div.glthumb div img');
|
||||||
|
const title = el_a.find('div.glink').html();
|
||||||
|
const thumbnail = el_img.attr('data-src') ? el_img.attr('data-src') : el_img.attr('src');
|
||||||
|
const description = `<img src='${thumbnail}'>`;
|
||||||
|
const pubDate = el.find('div[id^="posted_"]').html();
|
||||||
|
const link = el_a.attr('href');
|
||||||
|
if (title && link) {
|
||||||
|
const item = { title, description, pubDate, link };
|
||||||
|
if (get_bittorrent) {
|
||||||
|
const el_down = el.find('td.gl2c div div.gldown');
|
||||||
|
const bittorrent_page_url = el_down.find('a').attr('href');
|
||||||
|
if (bittorrent_page_url) {
|
||||||
|
const bittorrent_url = await getBittorrent(cache, bittorrent_page_url);
|
||||||
|
if (bittorrent_url) {
|
||||||
|
item.enclosure_url = bittorrent_url;
|
||||||
|
item.enclosure_type = 'application/x-bittorrent';
|
||||||
|
item.bittorrent_page_url = bittorrent_page_url;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return item;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
const item_Promises = [];
|
||||||
|
table.children('tr').each((index, element) => {
|
||||||
|
item_Promises.push(parseTableRow(cache, element));
|
||||||
|
});
|
||||||
|
const items_with_null = await Promise.all(item_Promises);
|
||||||
|
|
||||||
|
const items = [];
|
||||||
|
for (const item of items_with_null) {
|
||||||
|
if (item) {
|
||||||
|
items.push(item);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return items;
|
||||||
|
}
|
||||||
|
|
||||||
|
let p = '';
|
||||||
|
|
||||||
|
function getBittorrent(cache, bittorrent_page_url) {
|
||||||
|
return cache.tryGet(bittorrent_page_url, async () => {
|
||||||
|
try {
|
||||||
|
const response = await got({ method: 'get', url: bittorrent_page_url, headers });
|
||||||
|
const $ = cheerio.load(response.data);
|
||||||
|
const el_forms = $('form').get();
|
||||||
|
let bittorrent_url = undefined;
|
||||||
|
for (const el_form of el_forms) {
|
||||||
|
const el_a = $(el_form).find('a');
|
||||||
|
const onclick = el_a.attr('onclick');
|
||||||
|
if (onclick) {
|
||||||
|
const match = onclick.match(/'(.*?)'/);
|
||||||
|
if (match) {
|
||||||
|
bittorrent_url = match[1];
|
||||||
|
const match_p = bittorrent_url.match(/torrent\?p=(.*?)$/);
|
||||||
|
if (match_p) {
|
||||||
|
p = match_p[1];
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return bittorrent_url;
|
||||||
|
} catch {
|
||||||
|
return undefined;
|
||||||
|
}
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
function updateBittorrent_url(cache, items) {
|
||||||
|
// 下种子文件需要动态密码,密码每几次请求就更新一次
|
||||||
|
for (const item of items) {
|
||||||
|
if (item.enclosure_url) {
|
||||||
|
item.enclosure_url = item.enclosure_url.replace(/torrent\?p=.*$/, `torrent?p=${p}`);
|
||||||
|
cache.set(item.bittorrent_page_url, item.enclosure_url);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return items;
|
||||||
|
}
|
||||||
|
|
||||||
|
async function gatherItemsByPage(cache, url, get_bittorrent = false) {
|
||||||
|
const response = await ehgot(url);
|
||||||
|
const items = await parsePage(cache, response.data, get_bittorrent);
|
||||||
|
return updateBittorrent_url(cache, items);
|
||||||
|
}
|
||||||
|
|
||||||
|
async function getFavoritesItems(cache, page, favcat, inline_set, get_bittorrent = false) {
|
||||||
|
const response = await ehgot(`favorites.php?favcat=${favcat}&inline_set=${inline_set}`);
|
||||||
|
if (parseInt(page) === 0) {
|
||||||
|
const items = await parsePage(cache, response.data, get_bittorrent);
|
||||||
|
return updateBittorrent_url(cache, items);
|
||||||
|
}
|
||||||
|
return gatherItemsByPage(cache, `favorites.php?page=${page}&favcat=${favcat}`, get_bittorrent);
|
||||||
|
}
|
||||||
|
|
||||||
|
function getSearchItems(cache, params, page = undefined, get_bittorrent = false) {
|
||||||
|
if (page) {
|
||||||
|
return gatherItemsByPage(cache, `?page=${page}&${params}`, get_bittorrent);
|
||||||
|
} else {
|
||||||
|
return gatherItemsByPage(cache, `?${params}`, get_bittorrent);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
function getTagItems(cache, tag, page, get_bittorrent = false) {
|
||||||
|
return gatherItemsByPage(cache, `tag/${tag}/${page}`, get_bittorrent);
|
||||||
|
}
|
||||||
|
|
||||||
|
module.exports = { getFavoritesItems, getSearchItems, getTagItems };
|
||||||
19
lib/routes/ehentai/favorites.js
Normal file
19
lib/routes/ehentai/favorites.js
Normal file
@@ -0,0 +1,19 @@
|
|||||||
|
const EhAPI = require('./ehapi');
|
||||||
|
const config = require('@/config').value;
|
||||||
|
|
||||||
|
module.exports = async (ctx) => {
|
||||||
|
if (!config.ehentai || !config.ehentai.ipb_member_id || !config.ehentai.ipb_pass_hash || !config.ehentai.sk) {
|
||||||
|
throw 'Ehentai favorites 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 favcat = ctx.params.favcat ? parseInt(ctx.params.favcat) : 0;
|
||||||
|
const page = ctx.params.page ? parseInt(ctx.params.page) : 0;
|
||||||
|
const bittorrent = ctx.params.bittorrent || false;
|
||||||
|
const inline_set = ctx.params.order === 'posted' ? 'fs_p' : 'fs_f';
|
||||||
|
const items = await EhAPI.getFavoritesItems(ctx.cache, page, favcat, inline_set, bittorrent);
|
||||||
|
|
||||||
|
ctx.state.data = {
|
||||||
|
title: 'E-Hentai Favorites',
|
||||||
|
link: `https://e-hentai.org/favorites.php?favcat=${favcat}&inline_set=${inline_set}`,
|
||||||
|
item: items,
|
||||||
|
};
|
||||||
|
};
|
||||||
20
lib/routes/ehentai/search.js
Normal file
20
lib/routes/ehentai/search.js
Normal file
@@ -0,0 +1,20 @@
|
|||||||
|
const EhAPI = require('./ehapi');
|
||||||
|
|
||||||
|
module.exports = async (ctx) => {
|
||||||
|
const page = ctx.params.page;
|
||||||
|
let params = ctx.params.params;
|
||||||
|
const bittorrent = ctx.params.bittorrent || false;
|
||||||
|
let items;
|
||||||
|
if (page) {
|
||||||
|
// 如果定义了page,就要覆盖params
|
||||||
|
params = params.replace(/&*page=[^&]$/, '').replace(/page=[^&]&/, '');
|
||||||
|
items = await EhAPI.getSearchItems(ctx.cache, params, parseInt(page), bittorrent);
|
||||||
|
} else {
|
||||||
|
items = await EhAPI.getSearchItems(ctx.cache, params, undefined, bittorrent);
|
||||||
|
}
|
||||||
|
ctx.state.data = {
|
||||||
|
title: 'E-Hentai Search',
|
||||||
|
link: `https://e-hentai.org/?${params}`,
|
||||||
|
item: items,
|
||||||
|
};
|
||||||
|
};
|
||||||
13
lib/routes/ehentai/tag.js
Normal file
13
lib/routes/ehentai/tag.js
Normal file
@@ -0,0 +1,13 @@
|
|||||||
|
const EhAPI = require('./ehapi');
|
||||||
|
|
||||||
|
module.exports = async (ctx) => {
|
||||||
|
const page = ctx.params.page ? parseInt(ctx.params.page) : 0;
|
||||||
|
const tag = ctx.params.tag;
|
||||||
|
const bittorrent = ctx.params.bittorrent || false;
|
||||||
|
const items = await EhAPI.getTagItems(ctx.cache, tag, page, bittorrent);
|
||||||
|
ctx.state.data = {
|
||||||
|
title: 'E-Hentai Search',
|
||||||
|
link: `https://e-hentai.org/tag/${tag}`,
|
||||||
|
item: items,
|
||||||
|
};
|
||||||
|
};
|
||||||
Reference in New Issue
Block a user