128 lines
3.8 KiB
JavaScript
Executable File
128 lines
3.8 KiB
JavaScript
Executable File
'use strict';
|
|
|
|
const unprint = require('unprint');
|
|
|
|
const slugify = require('../utils/slugify');
|
|
|
|
function scrapeAll(scenes, _channel) {
|
|
return scenes.map(({ query, element }) => {
|
|
const release = {};
|
|
|
|
release.url = query.url('.card__link');
|
|
release.entryId = new URL(release.url).pathname.match(/\/en\/(.*)/)[1];
|
|
|
|
release.title = query.content('.card__link');
|
|
release.duration = query.duration('.card__img_badge.bottom-right');
|
|
|
|
release.poster = query.img('.card__img img');
|
|
release.teaser = unprint.query.dataset(element, null, 'video');
|
|
|
|
return release;
|
|
});
|
|
}
|
|
|
|
async function fetchLatest(channel, page = 1) {
|
|
const res = await unprint.get(`${channel.origin}/en/videos?page=${page}`, { selectAll: '.card--item' });
|
|
|
|
if (res.ok) {
|
|
return scrapeAll(res.context, channel);
|
|
}
|
|
|
|
return res.status;
|
|
}
|
|
|
|
function scrapeScene({ query }, url, channel) {
|
|
const release = {};
|
|
|
|
release.entryId = new URL(url).pathname.match(/\/en\/(.*)/)[1];
|
|
|
|
release.title = query.content('h1.h2');
|
|
release.description = query.attribute('meta[property="og:description"]', 'content'); // not usually used, if ever
|
|
|
|
release.date = query.date('meta[property="video:release_date"]', 'YYYY-MM-DD', { attribute: 'content' });
|
|
release.duration = query.number('meta[property="video:duration"]', { attribute: 'content' });
|
|
|
|
release.actors = query.all('.video-info .mini-avatars a').map((actorEl) => ({
|
|
name: unprint.query.content(actorEl),
|
|
url: unprint.query.url(actorEl, null, { origin: channel.origin }),
|
|
avatar: [
|
|
unprint.query.img(actorEl, 'img')?.replace('-video_actor_avatar', '-actor_detail'),
|
|
unprint.query.img(actorEl, 'img'),
|
|
],
|
|
}));
|
|
|
|
release.tags = query.contents('.video-info a[href*="?category"]').map((tag) => tag.replace('#', '').trim());
|
|
release.qualities = query.numbers('.download-dropdown-menu li div', { attribute: 'data-res' });
|
|
|
|
release.poster = [
|
|
query.img('.video-player', { attribute: 'data-poster' }),
|
|
query.img('meta[property="og:image"]', { attribute: 'content' }),
|
|
];
|
|
|
|
release.trailer = query.all('.video-player source').map((videoEl) => ({
|
|
src: unprint.query.video(videoEl, null),
|
|
quality: unprint.query.number(videoEl, null, { attribute: 'size' }),
|
|
}));
|
|
|
|
release.photos = query.all('.image .gallery-popup').map((imgEl) => [
|
|
unprint.query.img(imgEl, null, { attribute: 'href' }),
|
|
unprint.query.img(imgEl, 'img'),
|
|
]);
|
|
|
|
release.channel = slugify(query.attribute('meta[property="og:site_name"]', 'content'), '');
|
|
|
|
return release;
|
|
}
|
|
|
|
async function fetchScene(url, channel) {
|
|
const res = await unprint.get(url);
|
|
|
|
if (res.ok) {
|
|
return scrapeScene(res.context, url, channel);
|
|
}
|
|
|
|
return res.status;
|
|
}
|
|
|
|
function scrapeProfile({ query }, url, _entity) {
|
|
const profile = { url };
|
|
const bio = Object.fromEntries(query.all('.model-info__item').map((bioEl) => [
|
|
slugify(unprint.query.content(bioEl, 'span:first-child'), '_'),
|
|
unprint.query.content(bioEl, 'span:last-child'),
|
|
]));
|
|
|
|
profile.avatar = query.img('.actor-img');
|
|
|
|
profile.gender = bio.gender;
|
|
profile.birthCountry = bio.nationality;
|
|
profile.ethnicity = bio.ethnicity;
|
|
profile.age = bio.age;
|
|
|
|
profile.hairColor = bio.hair_color;
|
|
|
|
if (!bio.breast_size?.includes('-')) profile.cup = bio.breast_size; // larger than F is defined as F-Z, not too useful
|
|
if (/natural/i.test(bio.breast_type)) profile.naturalBoobs = true;
|
|
if (/fake/i.test(bio.breast_type)) profile.naturalBoobs = false;
|
|
if (/no/i.test(bio.tattoo)) profile.hasTattoos = false;
|
|
if (/yes/i.test(bio.tattoo)) profile.hasTattoos = true;
|
|
|
|
return profile;
|
|
}
|
|
|
|
async function fetchProfile(baseActor, entity) {
|
|
const url = `${new URL(entity.url).origin}/en/pornstars/${baseActor.slug}`;
|
|
const res = await unprint.get(`${new URL(entity.url).origin}/en/pornstars/${baseActor.slug}`);
|
|
|
|
if (res.ok) {
|
|
return scrapeProfile(res.context, url, entity);
|
|
}
|
|
|
|
return res.status;
|
|
}
|
|
|
|
module.exports = {
|
|
fetchLatest,
|
|
fetchScene,
|
|
fetchProfile,
|
|
};
|