RSSHub/lib/v2/nhentai/util.js

148 lines
4.9 KiB
JavaScript
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

const cheerio = require('cheerio');
const got = require('@/utils/got');
const config = require('@/config').value;
const { parseDate } = require('@/utils/parse-date');
const { art } = require('@/utils/render');
const path = require('path');
const baseUrl = 'https://nhentai.net';
const getCookie = async (username, password, cache) => {
const loginUrl = 'https://nhentai.net/login/';
const cacheKey = 'nhentai:cookie';
const cachedCookie = await cache.get(cacheKey);
if (cachedCookie) {
const { cookie, time } = JSON.parse(cachedCookie);
const now = new Date().getTime();
if (now - time < 86400 * 3 * 1000) {
// 不考虑缓存过期的话有效期最多允许3天
return cookie;
}
}
const { data, headers } = await got(loginUrl);
const csrfTokenMiddleware = data.match(/name="csrfmiddlewaretoken" value="(.*?)"/)[1];
const csrfTokenCookie = headers['set-cookie'].map((c) => c.split(';')[0]).join('; ');
const login = await got.post(loginUrl, {
headers: {
referer: loginUrl,
cookie: csrfTokenCookie,
},
form: {
csrfmiddlewaretoken: csrfTokenMiddleware,
username_or_email: username,
password,
next: '',
},
followRedirect: false,
});
if (login.statusCode !== 302) {
cache.set(
cacheKey,
JSON.stringify({
cookie: '',
time: new Date().getTime(),
})
);
return '';
}
const userTokenCookie = login.headers['set-cookie'].map((c) => c.split(';')[0]).join('; ');
cache.set(
cacheKey,
JSON.stringify({
cookie: userTokenCookie,
time: new Date().getTime(),
})
);
return userTokenCookie;
};
const gotByIp = (url, ...options) =>
// credit: https://github.com/sinkaroid/jandapress/pull/23
got(url.replace(/^https:\/\/nhentai.net\//, 'http://129.150.63.211:3002/'), {
...options,
headers: {
host: 'nhentai.net',
},
});
const getSimple = async (url) => {
const { data } = await gotByIp(url);
const $ = cheerio.load(data);
return $('.gallery a.cover')
.toArray()
.map((ele) => parseSimpleDetail($(ele)));
};
const getDetails = (cache, simples, limit) => Promise.all(simples.slice(0, limit).map((simple) => cache.tryGet(simple.link, () => getDetail(simple))));
const getTorrents = async (cache, simples, limit) => {
if (!config.nhentai || !config.nhentai.username || !config.nhentai.password) {
throw Error('nhentai RSS with torrents is disabled due to the lack of <a href="https://docs.rsshub.app/en/install/#configuration-route-specific-configurations">relevant config</a>');
}
const cookie = await getCookie(config.nhentai.username, config.nhentai.password, cache);
if (!cookie) {
throw Error('Invalid username (or email) or password for nhentai torrent download');
}
return getTorrentWithCookie(cache, simples, cookie, limit);
};
const getTorrentWithCookie = (cache, simples, cookie, limit) => Promise.all(simples.slice(0, limit).map((simple) => cache.tryGet(simple.link + 'download', () => getTorrent(simple, cookie))));
const parseSimpleDetail = ($ele) => {
const link = new URL($ele.attr('href'), baseUrl).href;
const thumb = $ele.children('img');
const thumbSrc = thumb.attr('data-src') || thumb.attr('src');
const highResoThumbSrc = thumbSrc.replace('thumb', '1').replace(/t(\d+)\.nhentai\.net/, 'i$1.nhentai.net');
return {
title: $ele.children('.caption').text(),
link,
description: `<img src="${highResoThumbSrc}">`,
};
};
const getTorrent = async (simple, cookie) => {
const { link } = simple;
const response = await gotByIp(link + 'download', { followRedirect: false, responseType: 'buffer', headers: { Cookie: cookie } });
return {
...simple,
enclosure_url: response.data,
enclosure_type: 'application/x-bittorrent',
};
};
const getDetail = async (simple) => {
const { link } = simple;
const { data } = await gotByIp(link);
const $ = cheerio.load(data);
const galleryImgs = $('.gallerythumb img')
.toArray()
.map((ele) => new URL($(ele).attr('data-src'), baseUrl).href)
.map((src) => src.replace(/(.+)(\d+)t\.(.+)/, (_, p1, p2, p3) => `${p1}${p2}.${p3}`)) // thumb to high-quality
.map((src) => src.replace(/t(\d+)\.nhentai\.net/, 'i$1.nhentai.net'));
return {
...simple,
title: $('div#info > h2').text() || $('div#info > h1').text(),
pubDate: parseDate($('time').attr('datetime')),
description: art(path.join(__dirname, 'templates/desc.art'), {
length: galleryImgs.length,
images: galleryImgs,
}),
};
};
module.exports = {
baseUrl,
getSimple,
getDetails,
getTorrents,
};