traxxx/src/scrapers/pervcity.js

127 lines
3.2 KiB
JavaScript
Raw Normal View History

'use strict';
const qu = require('../utils/qu');
const slugify = require('../utils/slugify');
const { feetInchesToCm, lbsToKg } = require('../utils/convert');
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.q('h3 a', true);
release.description = query.q('.runtime + p', true);
release.date = query.date('.date', 'MM-DD-YYYY');
release.duration = query.dur('.runtime');
release.actors = query.all('.tour_update_models a', true);
release.poster = query.img('.videoPic img');
release.entity = entity;
return release;
});
}
function scrapeScene({ query }) {
const release = {};
release.entryId = query.q('.trailerLeft img', 'id').match(/set-target-(\d+)/)[1];
release.title = query.q('.infoHeader h1', true);
release.description = query.q('.infoBox p', true);
release.actors = query.all('.tour_update_models a', true);
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 = {
src: `https://pervcity.com${trailer}`,
};
}
return release;
}
function scrapeProfile({ query }) {
const profile = {};
const bio = query.all('.moreInfo li').reduce((acc, el) => ({
...acc,
[slugify(query.q(el, 'span', true), '_')]: query.text(el),
}), {});
profile.description = query.q('.aboutModel p', true);
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;
}
async function fetchLatest(channel, page = 1) {
if (channel.parameters?.siteId) {
const url = `https://pervcity.com/search.php?site[]=${channel.parameters.siteId}&page=${page}`;
const res = await qu.getAll(url, '.videoBlock');
return res.ok ? scrapeAll(res.items, channel) : res.status;
}
return null;
}
async function fetchUpcoming(channel) {
const url = 'https://pervcity.com';
const res = await qu.getAll(url, '.upcoming .videoBlock');
return res.ok ? scrapeAll(res.items, 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(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,
};