traxxx/src/scrapers/porndoe.js

132 lines
4.0 KiB
JavaScript
Raw Normal View History

'use strict';
const qu = require('../utils/qu');
const slugify = require('../utils/slugify');
function scrapeAll(scenes) {
return scenes.map(({ query }) => {
const release = {};
release.url = query.url('a');
release.entryId = release.url.match(/\/watch\/(\d+)/)[1];
release.title = query.q('.bottom h4', true);
release.date = query.date('.extra-info:not(.actors)', 'DD MMMM YYYY');
release.actors = query.all('.actors a strong', true);
const poster = query.img('.thumb img');
release.poster = [
poster.replace('512x288', '1472x828'),
poster,
];
release.teaser = { src: query.video('video-preview') };
release.channel = slugify(query.q('.bottom a[href*="/channels"]', 'title'), '');
return release;
});
}
function scrapeScene({ query }, url) {
const release = {};
release.title = query.q('h1', true);
release.entryId = url.match(/\/watch\/(\d+)/)[1];
release.description = query.meta('name=description') || query.q('read-even-more', true);
release.date = query.date('.h5-published', 'DD MMMM YYYY', /\d{1,2} \w+ \d{4}/);
release.actors = query.all('.video-top-details .actors a[href*="/models"]', true);
release.duration = query.dur('meta[itemprop="duration"]', null, 'content');
release.tags = query.all('.video-top-details a[href*="/categories"], .video-top-details a[href*="/tags"]', true);
release.poster = query.img('.poster img') || query.meta('itemprop=thumbnailUrl');
release.photos = query.imgs('#gallery-thumbs picture img').slice(1).map(photo => [ // first image is poster
photo.replace('512x288', '1472x828'),
photo,
]);
release.trailer = {
src: query.meta('itemprop=contentURL'),
};
release.channel = slugify(query.q('.video-top-details .actors a[href*="/channels"] strong', true), '');
return release;
}
async function fetchActorReleases({ query }, url, page = 1, accReleases = []) {
const releases = scrapeAll(qu.initAll(query.all('.main-content .card-video')));
const hasNextPage = query.exists('.pages a.active + a');
if (hasNextPage) {
const res = await qu.get(`${url}?page=${page + 1}`);
if (res.ok) {
return fetchActorReleases(res.item, url, page + 1, accReleases.concat(releases));
}
}
return accReleases.concat(releases);
}
async function scrapeProfile({ query }, url, include) {
const profile = {};
const keys = query.all('.col .h4:not(.more-less-actors)', true);
const values = query.all('.col .h4-big', true);
const bio = keys.reduce((acc, key, index) => ({ ...acc, [slugify(key, '_')]: values[index] }), {});
const tags = query.all('.more-less-actors a[href*="/tags"], .more-less-actors a[href*="/categories"]', true);
profile.nationality = bio.nationality;
profile.placeOfBirth = bio.birth_place;
if (/enhanced/i.test(bio.tits_type)) profile.naturalBoobs = false;
if (/natural/i.test(bio.tits_type)) profile.naturalBoobs = true;
if (tags.includes('brunette') || tags.includes('brown hair')) profile.hairColor = 'brown';
if (tags.includes('blonde')) profile.hairColor = 'blonde';
if (tags.includes('tattoo') || tags.includes('tattoos')) profile.hasTattoos = true;
if (tags.includes('piercing') || tags.includes('piercings')) profile.hasPiercings = true;
profile.description = query.q('.more-less-actors read-even-more', true);
profile.avatar = query.img('.avatar .thumb img') || null;
if (include.releases) {
profile.releases = await fetchActorReleases({ query }, url);
}
console.log(profile);
return profile;
}
async function fetchLatest(channel, page = 1) {
const res = await qu.getAll(`${channel.url}?page=${page}`, '.main-content .card-video');
return res.ok ? scrapeAll(res.items, channel) : res.status;
}
async function fetchScene(url, channel) {
const res = await qu.get(url, '.main-content');
return res.ok ? scrapeScene(res.item, url, channel) : res.status;
}
async function fetchProfile(actorName, entity, include) {
const url = `http://letsdoeit.com/models/${slugify(actorName)}.en.html`;
const res = await qu.get(url);
return res.ok ? scrapeProfile(res.item, url, include) : res.status;
}
module.exports = {
fetchLatest,
fetchScene,
fetchProfile,
};