Refactored Bam Visions to use unprint.
This commit is contained in:
parent
db7e9702dd
commit
0ae834ccf0
|
|
@ -1,87 +1,112 @@
|
|||
'use strict';
|
||||
|
||||
const format = require('template-format');
|
||||
const unprint = require('unprint');
|
||||
|
||||
const { get, geta, initAll, formatDate } = require('../utils/qu');
|
||||
const slugify = require('../utils/slugify');
|
||||
const tryUrls = require('../utils/try-urls');
|
||||
|
||||
const { feetInchesToCm } = require('../utils/convert');
|
||||
const { convert } = require('../utils/convert');
|
||||
|
||||
function scrapeAll(scenes, site) {
|
||||
return scenes.map(({ qu }) => {
|
||||
return scenes.map(({ query }) => {
|
||||
const release = {};
|
||||
|
||||
release.title = qu.q('h3 a', true);
|
||||
release.url = qu.url('h3 a');
|
||||
release.url = query.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.title = query.content('h3 a');
|
||||
release.description = query.content('.description');
|
||||
|
||||
release.actors = qu.all('a[href*="/models"]', true);
|
||||
if (/bts/i.test(release.title)) release.tags = ['behind the scenes'];
|
||||
release.date = query.date('.item-meta li', 'MMMM D, YYYY');
|
||||
release.duration = query.duration('.item-meta li:nth-child(2)');
|
||||
|
||||
[release.poster, ...release.photos] = qu.all('.item-thumbs img')
|
||||
release.actors = query.all('a[href*="/models"]').map((actorEl) => ({
|
||||
name: unprint.query.content(actorEl),
|
||||
url: unprint.query.url(actorEl, null),
|
||||
}));
|
||||
|
||||
[release.poster, ...release.photos] = query.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}`)));
|
||||
.map((fallback) => unprint.prefixUrl(fallback, site.url)));
|
||||
|
||||
release.entryId = `${formatDate(release.date, 'YYYY-MM-DD')}-${slugify(release.title)}`;
|
||||
release.entryId = `${unprint.formatDate(release.date, 'YYYY-MM-DD')}-${slugify(release.title)}`;
|
||||
|
||||
return release;
|
||||
});
|
||||
}
|
||||
|
||||
function scrapeScene({ html, qu }, url, site) {
|
||||
const release = { url };
|
||||
async function fetchLatest(site, page = 1) {
|
||||
const url = `${site.url}/categories/movies/${page}/latest/`;
|
||||
const res = await unprint.get(url, { selectAll: '.item-episode' });
|
||||
|
||||
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);
|
||||
if (res.ok) {
|
||||
return scrapeAll(res.context, site);
|
||||
}
|
||||
|
||||
release.actors = qu.all('.item-episode a[href*="/models"]', true);
|
||||
if (/bts/i.test(release.title)) release.tags = ['behind the scenes'];
|
||||
return res.status;
|
||||
}
|
||||
|
||||
function scrapeScene({ html, query }, site) {
|
||||
const release = {};
|
||||
|
||||
release.title = query.content('.item-episode h4 a');
|
||||
release.description = query.content('.description');
|
||||
|
||||
release.date = query.date('.item-meta li', 'MMMM D, YYYY');
|
||||
release.duration = query.duration('.item-meta li:nth-child(2)');
|
||||
|
||||
release.actors = query.all('.item-episode a[href*="/models"]').map((actorEl) => ({
|
||||
name: unprint.query.content(actorEl),
|
||||
url: unprint.query.url(actorEl, null),
|
||||
}));
|
||||
|
||||
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,
|
||||
];
|
||||
posterPath.replace('-1x', '-3x'),
|
||||
posterPath.replace('-1x', '-2x'),
|
||||
posterPath,
|
||||
].map((poster) => unprint.prefixUrl(poster, site.url));
|
||||
}
|
||||
|
||||
if (trailerPath) {
|
||||
const trailer = /^http/.test(trailerPath) ? trailerPath : `${site.url}${trailerPath}`;
|
||||
release.trailer = { src: trailer };
|
||||
release.trailer = /^http/.test(trailerPath)
|
||||
? trailerPath
|
||||
: `${site.url}${trailerPath}`;
|
||||
}
|
||||
|
||||
release.entryId = `${formatDate(release.date, 'YYYY-MM-DD')}-${slugify(release.title)}`;
|
||||
release.photoCount = query.number('.item-meta li:last-child');
|
||||
release.entryId = `${unprint.formatDate(release.date, 'YYYY-MM-DD')}-${slugify(release.title)}`;
|
||||
|
||||
return release;
|
||||
}
|
||||
|
||||
async function fetchScene(url, site) {
|
||||
const res = await unprint.get(url);
|
||||
|
||||
if (res.ok) {
|
||||
return scrapeScene(res.context, site);
|
||||
}
|
||||
|
||||
return res.status;
|
||||
}
|
||||
|
||||
async function fetchActorReleases(actorId, site, page = 1, accScenes = []) {
|
||||
const url = site.parameters?.sets
|
||||
? `${site.parameters.sets}?id=${actorId}&page=${page}`
|
||||
: `${site.url}/sets.php?id=${actorId}&page=${page}`;
|
||||
const url = `${site.url}/sets.php?id=${actorId}&page=${page}`;
|
||||
const res = await unprint.get(url, { selectAll: '.item-episode' });
|
||||
|
||||
const res = await get(url);
|
||||
if (!res.ok) {
|
||||
return [];
|
||||
}
|
||||
|
||||
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}"]`);
|
||||
const releases = scrapeAll(res.context, site);
|
||||
const nextPage = res.context.query.url(`a[href*="page=${page + 1}"]`);
|
||||
|
||||
if (nextPage) {
|
||||
return fetchActorReleases(actorId, site, page + 1, accScenes.concat(releases));
|
||||
|
|
@ -90,36 +115,30 @@ async function fetchActorReleases(actorId, site, page = 1, accScenes = []) {
|
|||
return accScenes.concat(releases);
|
||||
}
|
||||
|
||||
async function scrapeProfile({ qu }, site, withScenes) {
|
||||
if (!qu.exists('.content')) {
|
||||
async function scrapeProfile({ query }, url, site, withScenes) {
|
||||
if (!query.exists('.content')) {
|
||||
// page probably returned a 404 with a 200 HTTP code
|
||||
return null;
|
||||
}
|
||||
|
||||
const profile = {};
|
||||
const profile = { url };
|
||||
|
||||
const bio = qu.all('.stats li', true).reduce((acc, row) => {
|
||||
const [key, value] = row.split(':');
|
||||
return { ...acc, [slugify(key, '_')]: value.trim() };
|
||||
}, {});
|
||||
const bio = Object.fromEntries(query.all('.stats li').map((bioEl) => [
|
||||
slugify(unprint.query.content(bioEl, 'strong'), '_'),
|
||||
unprint.query.text(bioEl),
|
||||
]));
|
||||
|
||||
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.height = convert(bio.height, 'cm');
|
||||
profile.measurements = bio.measurements;
|
||||
|
||||
profile.avatar = [
|
||||
qu.q('.profile-pic img', 'src0_3x'),
|
||||
qu.q('.profile-pic img', 'src0_2x'),
|
||||
qu.q('.profile-pic img', 'src0_1x'),
|
||||
query.img('.profile-pic img', { attribute: 'src0_3x' }),
|
||||
query.img('.profile-pic img', { attribute: 'src0_2x' }),
|
||||
query.img('.profile-pic img', { attribute: '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];
|
||||
const actorId = query.attribute('.profile-pic img', 'id')?.match(/set-target-(\d+)/)?.[1];
|
||||
|
||||
if (actorId) {
|
||||
profile.releases = await fetchActorReleases(actorId, site);
|
||||
|
|
@ -129,37 +148,18 @@ async function scrapeProfile({ qu }, site, withScenes) {
|
|||
return profile;
|
||||
}
|
||||
|
||||
async function fetchLatest(site, page = 1) {
|
||||
const url = site.parameters?.latest
|
||||
? format(site.parameters.latest, { page })
|
||||
: `${site.url}/categories/movies/${page}/latest/`;
|
||||
const res = await geta(url, '.item-episode');
|
||||
async function fetchProfile({ name: actorName, url: actorUrl }, { channel }, include) {
|
||||
const { res, url } = await tryUrls([
|
||||
actorUrl,
|
||||
`${channel.url}/models/${slugify(actorName, '-')}.html`,
|
||||
`${channel.url}/models/${slugify(actorName, '')}.html`,
|
||||
]);
|
||||
|
||||
return res.ok ? scrapeAll(res.items, site) : res.status;
|
||||
}
|
||||
if (res.ok) {
|
||||
return scrapeProfile(res.context, url, channel, include.scenes);
|
||||
}
|
||||
|
||||
async function fetchScene(url, site) {
|
||||
const res = await get(url);
|
||||
|
||||
return res.ok ? scrapeScene(res.item, url, site) : res.status;
|
||||
}
|
||||
|
||||
async function fetchProfile({ name: actorName }, { site }, include) {
|
||||
const actorSlugA = slugify(actorName, '');
|
||||
const actorSlugB = slugify(actorName);
|
||||
|
||||
const urlA = site.parameters?.profile
|
||||
? format(site.parameters.profile, { slug: actorSlugA })
|
||||
: `${site.url}/models/${actorSlugA}.html`;
|
||||
|
||||
const urlB = site.parameters?.profile
|
||||
? format(site.parameters.profile, { slug: actorSlugB })
|
||||
: `${site.url}/models/${actorSlugB}.html`;
|
||||
|
||||
const resA = await get(urlA);
|
||||
const res = resA.ok ? resA : await get(urlB);
|
||||
|
||||
return res.ok ? scrapeProfile(res.item, site, include.scenes) : res.status;
|
||||
return res.status;
|
||||
}
|
||||
|
||||
module.exports = {
|
||||
|
|
|
|||
|
|
@ -115,6 +115,7 @@ const actors = [
|
|||
// perv city
|
||||
{ entity: 'pervcity', name: 'Brooklyn Gray', fields: ['avatar', 'description', 'dateOfBirth', 'birthPlace', 'ethnicity', 'height', 'weight', 'eyes', 'hairColor'] },
|
||||
{ entity: 'dpdiva', name: 'Liz Jordan', fields: ['avatar', 'description', 'dateOfBirth', 'birthPlace', 'ethnicity', 'height', 'weight', 'eyes', 'hairColor'] },
|
||||
{ entity: 'bamvisions', name: 'Abella Danger', fields: ['avatar', 'height', 'measurements'] },
|
||||
// radical
|
||||
{ entity: 'bjraw', name: 'Nikki Knightly', fields: ['avatar', 'description', 'gender', 'dateOfBirth', 'birthPlace', 'measurements', 'height', 'weight', 'eyes', 'hairColor'] },
|
||||
{ entity: 'gotfilled', name: 'Alexa Chains', fields: ['avatar', 'description', 'gender', 'dateOfBirth', 'birthPlace', 'measurements', 'height', 'weight', 'eyes', 'hairColor'] },
|
||||
|
|
@ -164,6 +165,9 @@ const actors = [
|
|||
{ entity: '2poles1hole', name: 'Bambi Blitz', url: 'https://2poles1hole.com/model/425', fields: ['avatar', 'entryId', 'description', 'gender', 'age', 'dateOfBirth', 'measurements', 'height', 'foot', 'hairColor', 'eyeColor'] },
|
||||
{ entity: 'creampiled', name: 'Nicole Aria', url: 'https://creampiled.com/model/616', fields: ['avatar', 'entryId', 'description', 'gender', 'age', 'dateOfBirth', 'measurements', 'height', 'foot', 'hairColor', 'eyeColor'] },
|
||||
{ entity: 'popuporgies', name: 'Nicole Aria', url: 'https://popuporgies.com/model/616', fields: ['avatar', 'entryId', 'description', 'gender', 'age', 'dateOfBirth', 'measurements', 'height', 'foot', 'hairColor', 'eyeColor'] },
|
||||
// missax
|
||||
{ entity: 'missax', name: 'Alexis Fawx', fields: ['avatar', 'description'] },
|
||||
{ entity: 'allherluv', name: 'Krissy Lynn', fields: ['avatar', 'description'] },
|
||||
// etc.
|
||||
{ entity: 'analvids', name: 'Veronica Leal', fields: ['avatar', 'gender', 'birthCountry', 'nationality', 'age', 'aliases', 'nationality'] },
|
||||
{ entity: 'archangel', name: 'Summer Brielle', fields: ['avatar', 'description', 'dateOfBirth', 'age', 'measurements', 'height', 'aliases'] },
|
||||
|
|
|
|||
Loading…
Reference in New Issue