forked from DebaucheryLibrarian/traxxx
150 lines
4.7 KiB
JavaScript
150 lines
4.7 KiB
JavaScript
'use strict';
|
|
|
|
const { get, geta, initAll, formatDate } = require('../utils/qu');
|
|
const slugify = require('../utils/slugify');
|
|
|
|
const { feetInchesToCm } = require('../utils/convert');
|
|
|
|
function scrapeAll(scenes, site) {
|
|
return scenes.map(({ qu }) => {
|
|
const release = {};
|
|
|
|
release.title = qu.q('h3 a', true);
|
|
release.url = qu.url('h3 a');
|
|
|
|
release.date = qu.date('.item-meta li', 'MMMM D, YYYY', /\w+ \d{1,2}, \d{4}/);
|
|
release.duration = qu.dur('.item-meta li:nth-child(2)');
|
|
release.description = qu.q('.description', true);
|
|
|
|
release.actors = qu.all('a[href*="/models"]', true);
|
|
if (/bts/i.test(release.title)) release.tags = ['behind the scenes'];
|
|
|
|
[release.poster, ...release.photos] = qu.all('.item-thumbs img')
|
|
.map(source => [
|
|
source.getAttribute('src0_3x'),
|
|
source.getAttribute('src0_2x'),
|
|
source.getAttribute('src0_1x'),
|
|
]
|
|
.filter(Boolean)
|
|
.map(fallback => (/^http/.test(fallback) ? fallback : `${site.url}${fallback}`)));
|
|
|
|
release.entryId = `${formatDate(release.date, 'YYYY-MM-DD')}-${slugify(release.title)}`;
|
|
|
|
return release;
|
|
});
|
|
}
|
|
|
|
function scrapeScene({ html, qu }, url, site) {
|
|
const release = { url };
|
|
|
|
release.title = qu.q('.item-episode h4 a', true);
|
|
release.date = qu.date('.item-meta li', 'MMMM D, YYYY', /\w+ \d{1,2}, \d{4}/);
|
|
release.duration = qu.dur('.item-meta li:nth-child(2)');
|
|
release.description = qu.q('.description', true);
|
|
|
|
release.actors = qu.all('.item-episode a[href*="/models"]', true);
|
|
if (/bts/i.test(release.title)) release.tags = ['behind the scenes'];
|
|
|
|
const posterPath = html.match(/poster="(.*.jpg)"/)?.[1];
|
|
const trailerPath = html.match(/video src="(.*.mp4)"/)?.[1];
|
|
|
|
if (posterPath) {
|
|
const poster = /^http/.test(posterPath) ? posterPath : `${site.url}${posterPath}`;
|
|
release.poster = [
|
|
poster.replace('-1x', '-3x'),
|
|
poster.replace('-1x', '-2x'),
|
|
poster,
|
|
];
|
|
}
|
|
|
|
if (trailerPath) {
|
|
const trailer = /^http/.test(trailerPath) ? trailerPath : `${site.url}${trailerPath}`;
|
|
release.trailer = { src: trailer };
|
|
}
|
|
|
|
release.entryId = `${formatDate(release.date, 'YYYY-MM-DD')}-${slugify(release.title)}`;
|
|
|
|
return release;
|
|
}
|
|
|
|
async function fetchActorReleases(actorId, site, page = 1, accScenes = []) {
|
|
const url = `${site.url}/sets.php?id=${actorId}&page=${page}`;
|
|
const res = await get(url);
|
|
|
|
if (!res.ok) return [];
|
|
|
|
const quReleases = initAll(res.item.el, '.item-episode');
|
|
const releases = scrapeAll(quReleases, site);
|
|
|
|
const nextPage = res.item.qu.q(`a[href*="page=${page + 1}"]`);
|
|
|
|
if (nextPage) {
|
|
return fetchActorReleases(actorId, site, page + 1, accScenes.concat(releases));
|
|
}
|
|
|
|
return accScenes.concat(releases);
|
|
}
|
|
|
|
async function scrapeProfile({ qu }, site, withScenes) {
|
|
const profile = {};
|
|
|
|
const bio = qu.all('.stats li', true).reduce((acc, row) => {
|
|
const [key, value] = row.split(':');
|
|
return { ...acc, [slugify(key, '_')]: value.trim() };
|
|
}, {});
|
|
|
|
if (bio.height) profile.height = feetInchesToCm(bio.height);
|
|
if (bio.measurements) {
|
|
const [bust, waist, hip] = bio.measurements.split('-');
|
|
|
|
if (bust) profile.bust = bust;
|
|
if (waist) profile.waist = Number(waist);
|
|
if (hip) profile.hip = Number(hip);
|
|
}
|
|
|
|
profile.avatar = [
|
|
qu.q('.profile-pic img', 'src0_3x'),
|
|
qu.q('.profile-pic img', 'src0_2x'),
|
|
qu.q('.profile-pic img', 'src0_1x'),
|
|
].filter(Boolean).map(source => (/^http/.test(source) ? source : `${site.url}${source}`));
|
|
|
|
if (withScenes) {
|
|
const actorId = qu.q('.profile-pic img', 'id')?.match(/set-target-(\d+)/)?.[1];
|
|
|
|
if (actorId) {
|
|
profile.releases = await fetchActorReleases(actorId, site);
|
|
}
|
|
}
|
|
|
|
return profile;
|
|
}
|
|
|
|
async function fetchLatest(site, page = 1) {
|
|
const url = `${site.url}/categories/movies/${page}/latest/`;
|
|
const res = await geta(url, '.item-episode');
|
|
|
|
return res.ok ? scrapeAll(res.items, site) : res.status;
|
|
}
|
|
|
|
async function fetchScene(url, site) {
|
|
const res = await get(url);
|
|
|
|
return res.ok ? scrapeScene(res.item, url, site) : res.status;
|
|
}
|
|
|
|
async function fetchProfile(actorName, scraperSlug, site, include) {
|
|
const actorSlugA = slugify(actorName, '');
|
|
const actorSlugB = slugify(actorName);
|
|
|
|
const resA = await get(`${site.url}/models/${actorSlugA}.html`);
|
|
const res = resA.ok ? resA : await get(`${site.url}/models/${actorSlugB}.html`);
|
|
|
|
return res.ok ? scrapeProfile(res.item, site, include.scenes) : res.status;
|
|
}
|
|
|
|
module.exports = {
|
|
fetchLatest,
|
|
fetchScene,
|
|
fetchProfile,
|
|
};
|