170 lines
4.4 KiB
JavaScript
Executable File
170 lines
4.4 KiB
JavaScript
Executable File
'use strict';
|
|
|
|
const unprint = require('unprint');
|
|
|
|
const slugify = require('../utils/slugify');
|
|
const capitalize = require('../utils/capitalize');
|
|
const tryUrls = require('../utils/try-urls');
|
|
|
|
function scrapeAll(scenes, channel, discard = true) {
|
|
return scenes.reduce((acc, { query, element }) => {
|
|
const release = {};
|
|
|
|
release.url = unprint.query.url(element, null, { attribute: 'href', origin: channel.url });
|
|
|
|
const { hostname, pathname } = new URL(release.url);
|
|
|
|
release.entryId = pathname.match(/_(\d+)/)?.[1];
|
|
release.channel = hostname.match(/(\w+)\.com/)?.[1];
|
|
|
|
if (discard && release.channel !== channel.slug) {
|
|
acc.unextracted.concat(release);
|
|
|
|
return acc;
|
|
}
|
|
|
|
release.title = query.content('.title, .informations h3');
|
|
release.duration = query.duration('.duration, .timer, .infos');
|
|
|
|
release.actors = query.content('.sub')?.split(/,\s*/);
|
|
|
|
release.poster = query.img('.thumb, picture img');
|
|
|
|
acc.scenes = acc.scenes.concat(release);
|
|
|
|
return acc;
|
|
}, {
|
|
scenes: [],
|
|
unextracted: [],
|
|
});
|
|
}
|
|
|
|
async function fetchLatest(channel, page) {
|
|
const res = await unprint.get(channel.parameters?.latest
|
|
? `${channel.parameters.latest}?page=${page}`
|
|
: `${channel.url}/videos?page=${page}`, { selectAll: '.items .scene' });
|
|
|
|
if (res.ok) {
|
|
return scrapeAll(res.context, channel);
|
|
}
|
|
|
|
return res.status;
|
|
}
|
|
|
|
function scrapeScene({ query, html }, { url, entity }) {
|
|
const release = {};
|
|
|
|
release.entryId = new URL(url).pathname.match(/_(\d+)/)?.[1];
|
|
|
|
const title = query.content('.page_title h1, h2');
|
|
const wunfTitle = title.match(/wunf \d+/i)?.[0];
|
|
|
|
release.title = wunfTitle ? wunfTitle.toUpperCase() : title;
|
|
release.description = query.content('.info_container .description');
|
|
|
|
release.date = query.date('.info_container .info_line:nth-child(1)', 'YYYY-MM-DD')
|
|
|| query.date('.description', 'D MMMM YYYY', { match: /\d{1,2} \w+ \d{4}/ });
|
|
|
|
release.actors = query.all('.girl_item, .starring .item').map((actorEl) => {
|
|
const avatar = unprint.query.img(actorEl);
|
|
|
|
return {
|
|
name: capitalize(unprint.query.content(actorEl, '.name, .informations p'), { uncapitalize: true }),
|
|
url: unprint.query.url(actorEl, null, { origin: entity.url }),
|
|
avatar,
|
|
};
|
|
});
|
|
|
|
release.duration = query.duration('.infos .description');
|
|
|
|
if (!release.duration) {
|
|
const duration = query.content('.info_container .info_line:nth-child(2)');
|
|
|
|
release.duration = (duration.match(/(\d+) hour/)?.[1] || 0) * 3600
|
|
+ (duration.match(/(\d+) minutes/)?.[1] || 0) * 60;
|
|
}
|
|
|
|
release.tags = query.contents('.tags a:not(.more_tag)');
|
|
release.poster = html.match(/image: "(.*?)"/)?.[1];
|
|
|
|
release.trailer = html.match(/url: "(.*mp4.*)"/g)?.map((src) => ({
|
|
src: src.match(/"(.*)"/)?.[1],
|
|
quality: Number(src.match(/[-/](\d+)p/)?.[1]),
|
|
}));
|
|
|
|
if (query.exists('.download-icon-4k')) {
|
|
release.qualities = [2160];
|
|
}
|
|
|
|
return release;
|
|
}
|
|
|
|
function scrapeProfile({ query }, url, entity) {
|
|
const profile = { url };
|
|
|
|
profile.avatar = query.img('.actor img, .avatar img');
|
|
profile.nationality = query.content(['.nationality, .nationnality', '//strong[contains(text(), "Nationnality")]'])?.replace(/nationn?ality\s*:/i, '').trim(); // sic
|
|
|
|
profile.scenes = scrapeAll(unprint.initAll(query.all('.videos .item, .list .scene.item')), entity, false);
|
|
|
|
return profile;
|
|
}
|
|
|
|
async function getActorUrl(actor) {
|
|
if (actor.url) {
|
|
return [actor.url];
|
|
}
|
|
|
|
const res = await unprint.get('https://www.woodmancastingx.com');
|
|
|
|
if (!res.ok) {
|
|
return res.status;
|
|
}
|
|
|
|
const searchUrl = unprint.prefixUrl(res.context.html.match(/"(.*searchCompletion\.js)"/)?.[1], 'https://www.woodmancastingx.com');
|
|
|
|
if (!searchUrl) {
|
|
return null;
|
|
}
|
|
|
|
const searchRes = await unprint.get(searchUrl);
|
|
|
|
if (!searchRes.ok) {
|
|
return searchRes.status;
|
|
}
|
|
|
|
const [actorId] = searchRes.data.actors.find(([_actorId, actorName]) => slugify(actorName) === actor.slug) || [];
|
|
|
|
if (!actorId) {
|
|
return null;
|
|
}
|
|
|
|
// WUNF has the same avatars at higher quality, but not all performers
|
|
return [
|
|
`https://www.wakeupnfuck.com/actor/${actor.slug}_${actorId}`,
|
|
`https://www.woodmancastingx.com/girl/${actor.slug}_${actorId}`,
|
|
];
|
|
}
|
|
|
|
async function fetchProfile(actor, entity) {
|
|
const actorUrls = await getActorUrl(actor);
|
|
|
|
if (!Array.isArray(actorUrls)) {
|
|
return actorUrls;
|
|
}
|
|
|
|
const { res, url } = await tryUrls(actorUrls);
|
|
|
|
if (res.ok) {
|
|
return scrapeProfile(res.context, url, entity);
|
|
}
|
|
|
|
return res.status;
|
|
}
|
|
|
|
module.exports = {
|
|
fetchLatest,
|
|
scrapeScene,
|
|
fetchProfile,
|
|
};
|