mirror of
https://github.com/DIYgod/RSSHub.git
synced 2025-12-09 06:30:40 +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': {
|
||||
_name: '旅法师营地',
|
||||
www: [
|
||||
|
||||
@@ -696,3 +696,8 @@ RSSHub 支持使用访问密钥 / 码,白名单和黑名单三种方式进行
|
||||
| <https://pic1.xuehuaimg.com/proxy/> | cloudflare |
|
||||
| <https://cors.netnr.workers.dev/> | cloudflare |
|
||||
| <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"/>
|
||||
|
||||
## 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: {
|
||||
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();
|
||||
|
||||
@@ -4140,6 +4140,11 @@ router.get('/tongli/news/:type', lazyloadRouteHandler('./routes/tongli/news'));
|
||||
// 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'));
|
||||
|
||||
|
||||
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