Refactored Cherry Pimps to use unprint, added series as channels.

This commit is contained in:
DebaucheryLibrarian 2026-01-11 23:19:31 +01:00
parent d0bb56e436
commit b7beea60ce
5 changed files with 284 additions and 127 deletions

View File

@ -2703,32 +2703,160 @@ const sites = [
}, },
// CHERRY PIMPS // CHERRY PIMPS
{ {
slug: 'cherrypimps',
name: 'Cherry Pimps', name: 'Cherry Pimps',
alias: ['cps'], slug: 'cherrypimps',
url: 'https://cherrypimps.com', url: 'https://cherrypimps.com/series/cherrypimps.html',
description: 'CherryPimps your premium porn site to Download and Stream the hottest and most exclusive 4K HD videos and pictures on your phone, tablet, TV or console.',
parent: 'cherrypimps', parent: 'cherrypimps',
parameters: {
extract: true,
},
}, },
{ {
slug: 'wildoncam',
name: 'Wild On Cam', name: 'Wild On Cam',
slug: 'wildoncam',
url: 'https://cherrypimps.com/series/wild-on-cam.html',
alias: ['woc'], alias: ['woc'],
url: 'https://wildoncam.com',
tags: ['live'],
parent: 'cherrypimps', parent: 'cherrypimps',
}, },
{ {
slug: 'britneyamber', name: 'Cherry of the Month',
slug: 'cherryofthemonth',
url: 'https://cherrypimps.com/series/cotm.html',
alias: ['cotm'],
parent: 'cherrypimps',
},
{
name: 'ALT',
slug: 'alt',
url: 'https://cherrypimps.com/series/alt.html',
parent: 'cherrypimps',
},
{
name: 'Big Cock Mood',
slug: 'bigcockmood',
tags: ['bbc'],
alias: ['bcm'],
url: 'https://cherrypimps.com/series/bcm.html',
parent: 'cherrypimps',
},
{
name: 'Bush',
slug: 'bush',
url: 'https://cherrypimps.com/series/bush.html',
parent: 'cherrypimps',
},
{
name: 'Busted',
slug: 'busted',
url: 'https://cherrypimps.com/series/busted.html',
parent: 'cherrypimps',
},
{
name: 'Cheese',
slug: 'cheese',
url: 'https://cherrypimps.com/series/cheese.html',
parent: 'cherrypimps',
},
{
name: 'Confessions',
slug: 'confessions',
url: 'https://cherrypimps.com/series/confessions.html',
parent: 'cherrypimps',
},
{
name: 'Cucked',
slug: 'cucked',
tags: ['cuckold'],
url: 'https://cherrypimps.com/series/cucked.html',
parent: 'cherrypimps',
},
{
name: 'Drilled',
slug: 'drilled',
url: 'https://cherrypimps.com/series/drilled.html',
parent: 'cherrypimps',
},
{
name: 'Ebony',
slug: 'ebony',
tags: ['black'],
url: 'https://cherrypimps.com/series/ebony-xxx.html',
parent: 'cherrypimps',
},
{
name: 'Exotic',
slug: 'exotic',
url: 'https://cherrypimps.com/series/exotic.html',
parent: 'cherrypimps',
},
{
name: 'Femme',
slug: 'femme',
tags: ['lesbian'],
url: 'https://cherrypimps.com/series/femme.html',
parent: 'cherrypimps',
},
{
name: 'Fresh',
slug: 'fresh',
url: 'https://cherrypimps.com/series/fresh.html',
parent: 'cherrypimps',
},
{
name: 'Ginger',
slug: 'ginger',
tags: ['redhead'],
url: 'https://cherrypimps.com/series/ginger.html',
parent: 'cherrypimps',
},
{
name: 'GFE',
slug: 'gfe',
tags: ['vr'],
url: 'https://cherrypimps.com/series/gfe.html',
parent: 'cherrypimps',
},
{
name: 'MILF',
slug: 'milf',
tags: ['milf'],
url: 'https://cherrypimps.com/series/milf-xxx.html',
parent: 'cherrypimps',
},
{
name: 'Pegged',
slug: 'pegged',
tags: ['pegging'],
url: 'https://cherrypimps.com/series/pegged.html',
parent: 'cherrypimps',
},
{
name: 'Petite',
slug: 'petite',
url: 'https://cherrypimps.com/series/petite-xxx.html',
parent: 'cherrypimps',
},
{
name: 'Taboo',
slug: 'taboo',
url: 'https://cherrypimps.com/series/taboo.html',
parent: 'cherrypimps',
},
{
name: 'Cherry Spot',
slug: 'cherryspot',
url: 'https://cherrypimps.com/series/cherry-spot.html',
parent: 'cherrypimps',
},
{
name: 'Archives',
slug: 'cherrypimpsarchives',
url: 'https://cherrypimps.com/series/archives.html',
parent: 'cherrypimps',
},
{
name: 'Britney Amber', name: 'Britney Amber',
slug: 'britneyamber',
delete: true,
url: 'https://www.britneyamber.com', url: 'https://www.britneyamber.com',
parent: 'cherrypimps', parent: 'cherrypimps',
parameters: {
extract: true,
},
}, },
// CLIFF MEDIA / VANESSA CLIFF // CLIFF MEDIA / VANESSA CLIFF
{ {
@ -9127,6 +9255,7 @@ const sites = [
{ {
slug: 'drilledxxx', slug: 'drilledxxx',
name: 'Drilled.XXX', name: 'Drilled.XXX',
delete: true,
url: 'https://drilled.xxx', url: 'https://drilled.xxx',
tags: ['anal'], tags: ['anal'],
parent: 'pimpxxx', parent: 'pimpxxx',
@ -9134,6 +9263,7 @@ const sites = [
{ {
slug: 'cuckedxxx', slug: 'cuckedxxx',
name: 'Cucked.XXX', name: 'Cucked.XXX',
delete: true,
url: 'https://cucked.xxx', url: 'https://cucked.xxx',
tags: ['cuckold'], tags: ['cuckold'],
parent: 'pimpxxx', parent: 'pimpxxx',
@ -9141,6 +9271,7 @@ const sites = [
{ {
slug: 'familyxxx', slug: 'familyxxx',
name: 'Family.XXX', name: 'Family.XXX',
delete: true,
url: 'https://family.xxx', url: 'https://family.xxx',
tags: ['family'], tags: ['family'],
parent: 'pimpxxx', parent: 'pimpxxx',
@ -9148,18 +9279,21 @@ const sites = [
{ {
slug: 'petitexxx', slug: 'petitexxx',
name: 'Petite.XXX', name: 'Petite.XXX',
delete: true,
url: 'https://petite.xxx', url: 'https://petite.xxx',
parent: 'pimpxxx', parent: 'pimpxxx',
}, },
{ {
slug: 'confessionsxxx', slug: 'confessionsxxx',
name: 'Confessions.XXX', name: 'Confessions.XXX',
delete: true,
url: 'https://confessions.xxx', url: 'https://confessions.xxx',
parent: 'pimpxxx', parent: 'pimpxxx',
}, },
{ {
slug: 'bcmxxx', slug: 'bcmxxx',
name: 'BCM.XXX', name: 'BCM.XXX',
delete: true,
url: 'https://bcm.xxx', url: 'https://bcm.xxx',
parent: 'pimpxxx', parent: 'pimpxxx',
}, },

View File

@ -1,92 +1,119 @@
'use strict'; 'use strict';
const qu = require('../utils/qu'); const unprint = require('unprint');
const slugify = require('../utils/slugify'); const slugify = require('../utils/slugify');
const tryUrls = require('../utils/try-urls');
function scrapeAll(scenes, site) { function scrapeAll(scenes) {
return scenes.map(({ query }) => { return scenes.map(({ query }) => {
const url = query.url('.text-thumb a');
const { pathname } = new URL(url);
const channelUrl = query.url('.badge');
if (site?.parameters?.extract && query.q('.badge', true) !== site.name) {
return null;
}
const release = {}; const release = {};
release.url = channelUrl ? `${channelUrl}${pathname}` : url; const url = query.url('.item-title a');
release.entryId = pathname.match(/\/trailers\/(.*).html/)[1];
release.title = query.q('.text-thumb a', true);
release.date = query.date('.date', 'YYYY-MM-DD', /\d{4}-\d{2}-\d{2}/);
release.duration = query.dur('.date', /(\d{2}:)?\d{2}:\d{2}/);
release.actors = query.all('.category a', true);
release.poster = query.img('img.video_placeholder, .video-images img');
release.teaser = { src: query.trailer() };
return release;
}).filter(Boolean);
}
function scrapeScene({ query, html }, url, _site, baseRelease) {
const release = { url };
const { pathname } = new URL(url); const { pathname } = new URL(url);
release.entryId = pathname.match(/\/\d+/)[0].slice(1);
release.title = query.q('.trailer-block_title', true); release.url = url;
release.description = query.q('.info-block:nth-child(3) .text', true); release.entryId = pathname.match(/\/trailers\/(.*).html/)[1];
release.date = query.date('.info-block_data .text', 'MMMM D, YYYY', /\w+ \d{1,2}, \d{4}/);
const duration = baseRelease?.duration || Number(query.q('.info-block_data .text', true).match(/(\d+)\s+min/)?.[1]) * 60; release.title = query.content('.item-title a');
if (duration) release.duration = duration;
release.actors = query.all('.info-block_data a[href*="/models"]', true); release.date = query.date('.item-date', 'MMMM D, YYYY');
release.tags = query.all('.info-block a[href*="/categories"]', true); release.duration = query.duration('.item-date', /(\d{2}:)?\d{2}:\d{2}/);
const posterEl = query.q('.update_thumb'); release.actors = query.all('.item-models a').map((actorEl) => ({
const poster = posterEl?.getAttribute('src0_3x') || posterEl?.getAttribute('src0_2x') || posterEl?.dataset.src; name: unprint.query.content(actorEl),
url: unprint.query.url(actorEl, null),
}));
if (poster && baseRelease?.poster) release.photos = [poster]; release.poster = query.img('.item-video-thumb', { attribute: 'data-videoposter' }) || query.img('img.video_placeholder');
else if (poster) release.poster = poster; release.teaser = query.video('.item-video-thumb', { attribute: 'data-videosrc' });
const trailer = html.match(/video src="(.*?)"/); release.photoCount = query.number('.item-date', { match: /(\d+) photos/i, matchIndex: 1 });
release.channel = slugify(query.content('.item-sitename a'), '');
if (trailer) { return release;
release.trailer = trailer[1]; });
}
async function fetchLatest(channel, page = 1) {
const slug = channel.parameters?.slug || new URL(channel.url).pathname.match(/\/series\/([\w-]+)/)[1];
const res = await unprint.get(`https://cherrypimps.com/categories/${slug}_${page}_d.html`, { selectAll: '.item-updates .item-video' });
if (res.ok) {
return scrapeAll(res.context, channel);
} }
return res.status;
}
function scrapeScene({ query }, url) {
const release = { url };
const { pathname } = new URL(url);
release.entryId = pathname.match(/\/trailers\/(.*).html/)[1];
release.title = query.content('.item-title h1');
release.description = query.content('.update-info-block p');
release.date = query.date('.update-info-row:first-child', 'MMMM D, YYYY');
release.duration = query.duration('.update-info-row:last-child');
release.photoCount = query.number('.update-info-row:last-child', { match: /(\d+) photos/i, matchIndex: 1 });
release.actors = query.all('.models-list-thumbs .model-list-item').map((actorEl) => ({
name: unprint.query.content(actorEl, 'span'),
url: unprint.query.url(actorEl, 'a'),
avatar: [
unprint.query.img(actorEl, 'img', { attribute: 'src0_3x' }),
unprint.query.img(actorEl, 'img', { attribute: 'src0_2x' }),
unprint.query.img(actorEl, 'img', { attribute: 'src0_1x' }),
],
}));
release.tags = query.contents('.update-info-block a[href*="categories/"]');
release.poster = [
query.img('.update_thumb', { attribute: 'src0_3x' }),
query.img('.update_thumb', { attribute: 'src0_2x' }),
query.img('.update_thumb', { attribute: 'src0_1x' }), // usually only this one available
].filter(Boolean);
// faux video trailer player redirects to signup
return release; return release;
} }
function scrapeProfile({ query }) { async function fetchScene(url, site, release) {
const profile = {}; const res = await unprint.get(url);
const keys = query.all('.model-descr_line:not(.model-descr_rait) p.text span', true); if (res.ok) {
const values = query.all('.model-descr_line:not(.model-descr_rait) p.text').map((el) => query.text(el)); return scrapeScene(res.context, url, site, release);
const bio = keys.reduce((acc, key, index) => ({ ...acc, [slugify(key, '_')]: values[index] }), {});
if (bio.height) profile.height = Number(bio.height.match(/\((\d+)\s*cm\)/)?.[1]);
if (bio.weight) profile.weight = Number(bio.weight.match(/\((\d+)kg\)/)?.[1]);
if (bio.race) profile.ethnicity = bio.race;
if (bio.date_of_birth) profile.birthdate = qu.extractDate(bio.date_of_birth, 'MMMM D, YYYY');
if (bio.birthplace) profile.birthPlace = bio.birthplace;
if (bio.measurements) {
const [bust, waist, hip] = bio.measurements.split('-');
if (!/\?/.test(bust)) profile.bust = bust;
if (!/\?/.test(waist)) profile.waist = waist;
if (!/\?/.test(hip)) profile.hip = hip;
} }
if (bio.hair) profile.hair = bio.hair; return res.status;
if (bio.eyes) profile.eyes = bio.eyes; }
if (/various/i.test(bio.tattoos)) profile.hasTattoos = true; function scrapeProfile({ query }, url) {
const profile = { url };
const bio = Object.fromEntries(query.all('.model-stats li').map((bioEl) => [
slugify(unprint.query.content(bioEl, 'strong'), '_'),
unprint.query.text(bioEl),
]));
profile.height = Number(bio.height?.match(/\((\d+)\s*cm\)/)?.[1]) || null;
profile.weight = Number(bio.weight?.match(/\((\d+)\s*kg\)/)?.[1]) || null;
profile.age = parseInt(bio.age, 10) || null;
profile.dateOfBirth = unprint.extractDate(bio.date_of_birth, 'MMMM D, YYYY');
profile.birthPlace = bio.birthplace;
profile.ethnicity = bio.race;
profile.measurements = bio.measurements;
profile.hair = bio.hair_color;
profile.eyes = bio.eye_color;
if (/various|several/i.test(bio.tattoos)) profile.hasTattoos = true;
else if (/none/i.test(bio.tattoos)) profile.hasTattoos = false; else if (/none/i.test(bio.tattoos)) profile.hasTattoos = false;
else if (bio.tattoos) { else if (bio.tattoos) {
profile.hasTattoos = true; profile.hasTattoos = true;
@ -100,47 +127,31 @@ function scrapeProfile({ query }) {
profile.piercings = bio.piercings; profile.piercings = bio.piercings;
} }
if (bio.aliases) profile.aliases = bio.aliases.split(',').map((alias) => alias.trim()); profile.aliases = bio.aliases?.split(',').map((alias) => alias.trim());
const avatar = query.q('.model-img img'); profile.avatar = [
profile.avatar = avatar.getAttribute('src0_3x') || avatar.getAttribute('src0_2x') || avatar.dataset.src; query.img('.model-img img, .model_bio_thumb', { attribute: 'src0_3x' }),
query.img('.model-img img, .model_bio_thumb', { attribute: 'src0_2x' }),
const releases = query.all('.video-thumb'); query.img('.model-img img, .model_bio_thumb', { attribute: 'src0_1x' }),
profile.releases = scrapeAll(qu.initAll(releases)); ];
return profile; return profile;
} }
async function fetchLatest(site, page = 1) { async function fetchProfile({ name: actorName, url: actorUrl }, { channel, network }) {
const url = site.parameters?.extract const origin = new URL(channel?.url || network.url).origin;
? `https://cherrypimps.com/categories/movies_${page}.html`
: `${site.url}/categories/movies_${page}.html`;
const res = await qu.getAll(url, 'div.video-thumb');
return res.ok ? scrapeAll(res.items, site) : res.status; const { res, url } = await tryUrls([
} actorUrl,
`${origin}/models/${slugify(actorName, '')}.html`,
`${origin}/models/${slugify(actorName)}.html`,
]);
async function fetchScene(url, site, release) { if (res.ok) {
const res = await qu.get(url); return scrapeProfile(res.context, url);
}
return res.ok ? scrapeScene(res.item, url, site, release) : res.status; return res.status;
}
async function fetchProfile({ name: actorName }, { site, network, scraper }) {
const actorSlug = slugify(actorName);
const actorSlug2 = slugify(actorName, '');
const origin = site?.url || network.url;
const [url, url2] = ['cherrypimps', 'wildoncam'].includes(scraper)
? [`${origin}/models/${actorSlug}.html`, `${origin}/models/${actorSlug2}.html`]
: [`${origin}/models/${actorSlug}.html`, `${origin}/models/${actorSlug2}.html`];
const res = await qu.get(url);
if (res.ok) return scrapeProfile(res.item);
const res2 = await qu.get(url2);
return res2.ok ? scrapeProfile(res2.item) : res2.status;
} }
module.exports = { module.exports = {

View File

@ -113,7 +113,7 @@ async function scrapeProfile({ query }, url, include) {
if (tags.includes('tattoo') || tags.includes('tattoos')) profile.hasTattoos = true; if (tags.includes('tattoo') || tags.includes('tattoos')) profile.hasTattoos = true;
if (tags.includes('piercing') || tags.includes('piercings')) profile.hasPiercings = true; if (tags.includes('piercing') || tags.includes('piercings')) profile.hasPiercings = true;
profile.description = query.text('[class$="description"] [class*="more-less"]'); profile.description = query.content('[class$="description"] [class*="more-less"]');
profile.avatar = query.img('[class*="poster"] img') || null; profile.avatar = query.img('[class*="poster"] img') || null;
if (include.releases) { if (include.releases) {

View File

@ -60,13 +60,19 @@ function scrapeScene({ query }, { url }) {
return release; return release;
} }
function scrapeProfile({ query }) { function scrapeProfile({ query }, searchAvatar) {
const profile = {}; const profile = {};
profile.nationality = query.content('//h3[contains(text(), "Nationality:")]/span') || null; profile.nationality = query.content('//h3[contains(text(), "Nationality:")]/span') || null;
profile.age = query.number('//h3[contains(text(), "Age:")]/span'); profile.age = query.number('//h3[contains(text(), "Age:")]/span');
profile.avatar = query.img(); const pageAvatar = query.img();
profile.avatar = searchAvatar || pageAvatar;
if (searchAvatar) {
profile.photos = [pageAvatar];
}
return profile; return profile;
} }
@ -94,18 +100,20 @@ async function fetchUpcoming(channel) {
} }
async function fetchProfile({ name: actorName }, entity) { async function fetchProfile({ name: actorName }, entity) {
// don't skip search, avatar not available on actor page
const searchUrl = `${entity.url}/models?name=${actorName}&sort=popularity`; const searchUrl = `${entity.url}/models?name=${actorName}&sort=popularity`;
const searchRes = await unprint.get(searchUrl); const searchRes = await unprint.get(searchUrl);
if (searchRes.ok) { if (searchRes.ok) {
const actorEl = searchRes.context.query.all('.pagination-items .model a').find((resultEl) => unprint.query.attribute(resultEl, null, 'title') === actorName); const actorEl = searchRes.context.query.all('.pagination-items .model a').find((resultEl) => unprint.query.attribute(resultEl, null, 'title') === actorName);
const actorUrl = unprint.query.url(actorEl, null); const actorUrl = unprint.query.url(actorEl, null);
const avatar = unprint.query.img(actorEl, '.card-img');
if (actorUrl) { if (actorUrl) {
const res = await unprint.get(actorUrl, { select: '.model-detail-card' }); const res = await unprint.get(actorUrl, { select: '.model-detail-card' });
if (res.ok) { if (res.ok) {
return scrapeProfile(res.context, actorName, entity); return scrapeProfile(res.context, avatar, entity);
} }
return res.status; return res.status;

View File

@ -13,8 +13,6 @@ const getRecursiveParameters = require('../src/utils/get-recursive-parameters');
const knex = require('../src/knex'); const knex = require('../src/knex');
const actors = [ const actors = [
// jules jordan
{ entity: 'julesjordan', name: 'Vanna Bardot', fields: ['height', 'dateOfBirth', 'measurements', 'description', 'avatar'] },
// vixen // vixen
{ entity: 'vixen', name: 'Abella Danger', fields: ['gender', 'avatar', 'description'] }, { entity: 'vixen', name: 'Abella Danger', fields: ['gender', 'avatar', 'description'] },
{ entity: 'tushy', name: 'Abella Danger', fields: ['gender', 'avatar', 'description'] }, { entity: 'tushy', name: 'Abella Danger', fields: ['gender', 'avatar', 'description'] },
@ -28,8 +26,6 @@ const actors = [
// teamskeet // teamskeet
{ entity: 'teamskeet', name: 'Abella Danger', fields: ['description', 'avatar', 'measurements', 'birthPlace', 'nationality', 'ethnicity', 'height', 'weight', 'hairColor', 'hasPiercings'] }, { entity: 'teamskeet', name: 'Abella Danger', fields: ['description', 'avatar', 'measurements', 'birthPlace', 'nationality', 'ethnicity', 'height', 'weight', 'hairColor', 'hasPiercings'] },
{ entity: 'teamskeet', name: 'Kali Roses', fields: ['description', 'avatar', 'measurements', 'nationality', 'ethnicity', 'hairColor', 'hasPiercings', 'hasTattoos'] }, // tattoos { entity: 'teamskeet', name: 'Kali Roses', fields: ['description', 'avatar', 'measurements', 'nationality', 'ethnicity', 'hairColor', 'hasPiercings', 'hasTattoos'] }, // tattoos
// analvids
{ entity: 'analvids', name: 'Veronica Leal', fields: ['avatar', 'gender', 'birthCountry', 'nationality', 'age', 'aliases', 'nationality'] },
// mike adriano // mike adriano
{ entity: 'trueanal', name: 'Brenna McKenna', fields: ['avatar', 'gender', 'description', 'dateOfBirth', 'birthPlace', 'measurements', 'eyes', 'weight', 'height', 'hairColor', 'hasTattoos'] }, { entity: 'trueanal', name: 'Brenna McKenna', fields: ['avatar', 'gender', 'description', 'dateOfBirth', 'birthPlace', 'measurements', 'eyes', 'weight', 'height', 'hairColor', 'hasTattoos'] },
{ entity: 'analonly', name: 'Lilith Grace', fields: ['avatar', 'gender', 'description', 'dateOfBirth', 'birthPlace', 'measurements', 'eyes', 'weight', 'height', 'hairColor'] }, { entity: 'analonly', name: 'Lilith Grace', fields: ['avatar', 'gender', 'description', 'dateOfBirth', 'birthPlace', 'measurements', 'eyes', 'weight', 'height', 'hairColor'] },
@ -77,8 +73,6 @@ const actors = [
{ entity: 'realityjunkies', name: 'Scarlett Alexis', fields: ['avatar', 'gender'] }, { entity: 'realityjunkies', name: 'Scarlett Alexis', fields: ['avatar', 'gender'] },
{ entity: 'sweetheartvideo', name: 'Lexi Lore', fields: ['avatar', 'gender', 'hairColor', 'ethnicity', 'hasTattoos', 'hasPiercings'] }, { entity: 'sweetheartvideo', name: 'Lexi Lore', fields: ['avatar', 'gender', 'hairColor', 'ethnicity', 'hasTattoos', 'hasPiercings'] },
{ entity: 'sweetsinner', name: 'Anna Claire Clouds', fields: ['avatar', 'gender'] }, { entity: 'sweetsinner', name: 'Anna Claire Clouds', fields: ['avatar', 'gender'] },
// bangros
{ entity: 'bangbros', name: 'Kira Perez', fields: ['avatar', 'gender', 'ethnicity', 'hairColor'] },
// gamma // gamma
{ entity: '21sextury', name: 'Aletta Ocean', fields: ['avatar', 'gender', 'description', 'eyes', 'hairColor'] }, { entity: '21sextury', name: 'Aletta Ocean', fields: ['avatar', 'gender', 'description', 'eyes', 'hairColor'] },
{ entity: 'biphoria', name: 'Cherry Kiss', fields: ['avatar', 'gender'] }, { entity: 'biphoria', name: 'Cherry Kiss', fields: ['avatar', 'gender'] },
@ -120,12 +114,6 @@ const actors = [
{ entity: 'inserted', name: 'Anissa Kate', fields: ['avatar', 'description', 'gender', 'dateOfBirth', 'birthPlace', 'measurements', 'height', 'weight', 'eyes', 'hairColor'] }, { entity: 'inserted', name: 'Anissa Kate', fields: ['avatar', 'description', 'gender', 'dateOfBirth', 'birthPlace', 'measurements', 'height', 'weight', 'eyes', 'hairColor'] },
{ entity: 'topwebmodels', name: 'Lexi Belle', fields: ['avatar', 'gender', 'dateOfBirth', 'birthPlace', 'measurements', 'height', 'weight', 'eyes', 'hairColor'] }, { entity: 'topwebmodels', name: 'Lexi Belle', fields: ['avatar', 'gender', 'dateOfBirth', 'birthPlace', 'measurements', 'height', 'weight', 'eyes', 'hairColor'] },
{ entity: 'purgatoryx', name: 'Kenzie Reeves', fields: ['avatar', 'description', 'gender', 'dateOfBirth', 'birthPlace', 'measurements', 'height', 'weight', 'eyes', 'hairColor'] }, { entity: 'purgatoryx', name: 'Kenzie Reeves', fields: ['avatar', 'description', 'gender', 'dateOfBirth', 'birthPlace', 'measurements', 'height', 'weight', 'eyes', 'hairColor'] },
// etc.
{ entity: 'archangel', name: 'Summer Brielle', fields: ['avatar', 'description', 'dateOfBirth', 'age', 'measurements', 'height', 'aliases'] },
{ entity: 'theflourishxxx', name: 'XWifeKaren', fields: ['avatar', 'description'] },
{ entity: 'hookuphotshot', name: 'Kenzie Reeves', fields: ['avatar', 'description'] },
{ entity: 'tokyohot', name: 'Mai Kawana', url: 'https://my.tokyo-hot.com/cast/2099/', fields: ['avatar', 'birthPlace', 'height', 'cup', 'bust', 'waist', 'hip', 'hairStyle', 'shoeSize', 'bloodType'] },
{ entity: 'teenmegaworld', name: 'Sheri Vi', fields: ['avatar', 'description', 'hairColor', 'eyes'] },
// wankz // wankz
{ entity: 'wankzvr', name: 'Melody Marks', fields: ['avatar', 'gender', 'description', 'birthPlace', 'height', 'measurements', 'age'] }, { entity: 'wankzvr', name: 'Melody Marks', fields: ['avatar', 'gender', 'description', 'birthPlace', 'height', 'measurements', 'age'] },
{ entity: 'milfvr', name: 'Ember Snow', fields: ['avatar', 'gender', 'description', 'measurements', 'birthPlace', 'height', 'age'] }, { entity: 'milfvr', name: 'Ember Snow', fields: ['avatar', 'gender', 'description', 'measurements', 'birthPlace', 'height', 'age'] },
@ -145,6 +133,22 @@ const actors = [
{ entity: 'thatsitcomshow', name: 'Casey Calvert', fields: ['avatar', 'age', 'residencePlace', 'height', 'measurements', 'photos'] }, { entity: 'thatsitcomshow', name: 'Casey Calvert', fields: ['avatar', 'age', 'residencePlace', 'height', 'measurements', 'photos'] },
// porndoe // porndoe
{ entity: 'vipsexvault', name: 'Amirah Adara', fields: ['avatar', 'nationality', 'placeOfBirth', 'age', 'naturalBoobs', 'hairColor', 'description'] }, { entity: 'vipsexvault', name: 'Amirah Adara', fields: ['avatar', 'nationality', 'placeOfBirth', 'age', 'naturalBoobs', 'hairColor', 'description'] },
{ entity: 'amateureuro', name: 'Luna Oara', fields: ['avatar', 'nationality', 'placeOfBirth', 'age', 'naturalBoobs', 'description'] },
{ entity: 'mamacitaz', name: 'Julia De Lucia', fields: ['avatar', 'nationality', 'placeOfBirth', 'age', 'naturalBoobs', 'description', 'hairColor'] },
{ entity: 'transbella', name: 'Kalena Rios', fields: ['avatar', 'nationality', 'placeOfBirth', 'age', 'naturalBoobs', 'description', 'hairColor'] },
// 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'] },
{ entity: 'bangbros', name: 'Kira Perez', fields: ['avatar', 'gender', 'ethnicity', 'hairColor'] },
{ entity: 'hookuphotshot', name: 'Kenzie Reeves', fields: ['avatar', 'description'] },
{ entity: 'julesjordan', name: 'Vanna Bardot', fields: ['height', 'dateOfBirth', 'measurements', 'description', 'avatar'] },
{ entity: 'pornworld', name: 'Veronica Leal', fields: ['avatar', 'nationality', 'age'] },
{ entity: 'private', name: 'Cherry Kiss', fields: ['avatar', 'description', 'nationality', 'measurements', 'height', 'weight', 'hairColor', 'eye', 'hasTattoos', 'tattoos', 'hasPiercings', 'piercings'] },
{ entity: 'teenmegaworld', name: 'Sheri Vi', fields: ['avatar', 'description', 'hairColor', 'eyes'] },
{ entity: 'theflourishxxx', name: 'XWifeKaren', fields: ['avatar', 'description'] },
{ entity: 'tokyohot', name: 'Mai Kawana', url: 'https://my.tokyo-hot.com/cast/2099/', fields: ['avatar', 'birthPlace', 'height', 'cup', 'bust', 'waist', 'hip', 'hairStyle', 'shoeSize', 'bloodType'] },
{ entity: 'rickysroom', name: 'Liz Jordan', fields: ['avatar', 'description', 'birthPlace', 'dateOfBirth', 'measurements', 'height', 'weight', 'eyes', 'hairColor'] },
{ entity: 'cherrypimps', name: 'Andi Avalon', fields: ['avatar', 'height', 'weight', 'dateOfBirth', 'birthPlace', 'ethnicity', 'measurements', 'hair', 'eyes', 'hasTattoos', 'age'] },
]; ];
const actorScrapers = scrapers.actors; const actorScrapers = scrapers.actors;