158 lines
3.9 KiB
JavaScript
158 lines
3.9 KiB
JavaScript
'use strict';
|
|
|
|
const qu = require('../utils/qu');
|
|
const slugify = require('../utils/slugify');
|
|
const { feetInchesToCm, lbsToKg } = require('../utils/convert');
|
|
|
|
const channelCodes = {
|
|
ao: 'analoverdose',
|
|
bb: 'bangingbeauties',
|
|
cbj: 'chocolatebjs',
|
|
oo: 'oraloverdose',
|
|
uha: 'upherasshole',
|
|
};
|
|
|
|
const qualities = {
|
|
v4k: 2160,
|
|
vFullHD: 1080,
|
|
vHD: 720,
|
|
vSD: 480,
|
|
};
|
|
|
|
const channelRegExp = new RegExp(Object.keys(channelCodes).join('|'), 'i');
|
|
|
|
function scrapeAll(scenes, entity) {
|
|
return scenes.map(({ query }) => {
|
|
const release = {};
|
|
|
|
release.url = query.url('.videoPic a');
|
|
release.entryId = query.q('.videoPic img', 'id').match(/set-target-(\d+)/)[1];
|
|
|
|
release.title = query.cnt('h3 a');
|
|
release.description = query.cnt('.runtime + p');
|
|
|
|
release.date = query.date('.date', 'MM-DD-YYYY');
|
|
release.duration = query.dur('.runtime');
|
|
|
|
release.actors = query.cnts('.tour_update_models a');
|
|
|
|
release.poster = query.img('.videoPic img');
|
|
release.entity = entity;
|
|
|
|
return release;
|
|
});
|
|
}
|
|
|
|
function scrapeScene({ query }, channel) {
|
|
const release = {};
|
|
|
|
release.entryId = query.q('.trailerLeft img', 'id').match(/set-target-(\d+)/)[1];
|
|
|
|
release.title = query.cnt('.infoHeader h1');
|
|
release.description = query.cnt('.description');
|
|
release.duration = query.duration('.tRuntime');
|
|
|
|
release.actors = query.cnts('.infoBox .tour_update_models a');
|
|
release.tags = query.cnts('.tagcats a');
|
|
release.qualities = query.imgs('.avaiFormate img').map((src) => qualities[src.match(/\/(\w+)\.png/)[1]]).filter(Boolean);
|
|
|
|
release.poster = query.img('.posterimg');
|
|
release.photos = query.imgs('.trailerSnaps img').slice(1); // first photo is poster in lower quality
|
|
|
|
const trailer = query.q('script')?.textContent.match(/\/trailers\/.+\.mp4/)?.[0];
|
|
|
|
if (trailer) {
|
|
release.trailer = `${channel.url}${trailer}`;
|
|
release.channel = channelCodes[release.trailer.match(channelRegExp)?.[0]];
|
|
}
|
|
|
|
return release;
|
|
}
|
|
|
|
function scrapeProfile({ query }) {
|
|
const profile = {};
|
|
|
|
const bio = query.all('.moreInfo li').reduce((acc, el) => ({
|
|
...acc,
|
|
[slugify(query.cnt(el, 'span'), '_')]: query.text(el),
|
|
}), {});
|
|
|
|
profile.description = query.cnt('.aboutModel p');
|
|
profile.dateOfBirth = qu.extractDate(bio.date_of_birth, ['MMMM D, YYYY', 'DD-MMM-YY']);
|
|
|
|
profile.birthPlace = bio.birth_location;
|
|
profile.ethnicity = bio.ethnicity;
|
|
|
|
profile.height = feetInchesToCm(bio.height);
|
|
profile.weight = lbsToKg(bio.weight);
|
|
|
|
profile.eyes = bio.eye_color;
|
|
profile.hairColor = bio.hair_color;
|
|
|
|
profile.avatar = query.img('.starPic img');
|
|
profile.releases = scrapeAll(qu.initAll(query.all('.aboutScenes .videoBlock')));
|
|
|
|
return profile;
|
|
}
|
|
|
|
function getLatestUrl(channel, page) {
|
|
if (channel.parameters?.siteId) {
|
|
return `https://pervcity.com/search.php?site[]=${channel.parameters.siteId}&page=${page}`;
|
|
}
|
|
|
|
if (channel.parameters?.native) {
|
|
return `${channel.url}/search.php?site[]=&page=${page}`;
|
|
}
|
|
|
|
return null;
|
|
}
|
|
|
|
async function fetchLatest(channel, page = 1) {
|
|
const url = getLatestUrl(channel, page);
|
|
|
|
if (url) {
|
|
const res = await qu.getAll(url, '.videoBlock');
|
|
|
|
return res.ok ? scrapeAll(res.items, channel) : res.status;
|
|
}
|
|
|
|
return [];
|
|
}
|
|
|
|
async function fetchUpcoming(channel) {
|
|
const res = await qu.getAll(channel.url, '.upcoming .videoBlock');
|
|
|
|
return res.ok ? scrapeAll(res.items, channel.parameters?.native ? channel : channel.parent) : res.status;
|
|
}
|
|
|
|
async function fetchScene(url, entity) {
|
|
const res = await qu.get(url, '.trailerArea');
|
|
|
|
return res.ok ? scrapeScene(res.item, entity) : res.status;
|
|
}
|
|
|
|
async function fetchProfile({ name: actorName }) {
|
|
const url = `https://pervcity.com/models/${slugify(actorName)}.html`;
|
|
const res = await qu.get(url);
|
|
|
|
if (res.ok) {
|
|
return scrapeProfile(res.item);
|
|
}
|
|
|
|
const url2 = `https://pervcity.com/models/${slugify(actorName, '')}.html`;
|
|
const res2 = await qu.get(url2);
|
|
|
|
if (res2.ok) {
|
|
return scrapeProfile(res2.item);
|
|
}
|
|
|
|
return res2.status;
|
|
}
|
|
|
|
module.exports = {
|
|
fetchLatest,
|
|
fetchScene,
|
|
fetchProfile,
|
|
fetchUpcoming,
|
|
};
|