Files
traxxx/src/scrapers/freeones.js
2026-02-06 06:44:03 +01:00

121 lines
3.0 KiB
JavaScript
Executable File

'use strict';
const unprint = require('unprint');
const slugify = require('../utils/slugify');
function scrapeProfile({ query }) {
const profile = {};
const bio = Object.fromEntries(query.all('.profile-meta-list li').map((bioEl) => [
slugify(unprint.query.content(bioEl, 'span:first-child'), '_'),
unprint.query.content(bioEl, 'span:last-child'),
]).filter(([_key, value]) => value?.toLowerCase() !== 'unknown'));
profile.description = query.content('#description div[data-test="biography"]');
profile.dateOfBirth = unprint.extractDate(bio.date_of_birth, 'MMMM D, YYYY');
profile.age = unprint.extractNumber(bio.age);
profile.birthPlace = bio.place_of_birth;
profile.nationality = bio.nationality;
profile.ethnicity = bio.ethnicity;
profile.eyes = bio.eye_color;
profile.hairColor = bio.hair_color;
[profile.bust, profile.cup] = bio.bra?.match(/(\d+)([a-z]+)/i)?.slice(1) || [];
// TODO: differentiate between bust and bra band size
if (!profile.bust) {
profile.bust = bio.bust;
}
if (!profile.cup) {
profile.cup = bio.cup;
}
profile.bust = unprint.extractNumber(bio.bra);
profile.cup = bio.cup;
profile.waist = unprint.extractNumber(bio.waist);
profile.hip = unprint.extractNumber(bio.hip);
profile.height = unprint.extractNumber(bio.height);
profile.weight = unprint.extractNumber(bio.weight);
profile.foot = unprint.extractNumber(bio.shoe_size);
profile.socials = query.urls('.profile-meta-item .teaser__link');
if (/yes/i.test(bio.tattoos)) profile.hasTattoos = true;
if (/no/i.test(bio.tattoos)) profile.hasTattoos = false;
profile.tattoos = bio.tattoo_locations;
if (/yes/i.test(bio.piercings)) profile.hasPiercings = true;
if (/no/i.test(bio.piercings)) profile.hasPiercings = false;
profile.piercings = bio.piercing_locations;
if (/natural/i.test(bio.boobs)) profile.naturalBoobs = true;
if (/fake/i.test(bio.boobs)) profile.naturalBoobs = false;
if (/natural/i.test(bio.butt)) profile.naturalButt = true;
if (/fake/i.test(bio.butt)) profile.naturalButt = false;
const avatar = query.img('.dashboard-image-container img');
if (!avatar?.match(/placeholder/i)) {
profile.avatar = avatar;
}
return profile;
}
async function getActorUrl(actor) {
if (actor.url) {
return actor.url;
}
const res = await unprint.post('https://www.freeones.com/xhr/search', {
performerTypes: ['babe', 'male', 'trans'],
query: actor.name,
recipe: 'subject',
size: 12,
});
if (res.ok) {
const model = res.data.hits?.find((result) => slugify(result.name) === actor.slug);
if (model?.url) {
return `https://www.freeones.com${model.url}/bio`;
}
}
return null;
}
async function fetchProfile(actor) {
const res = await unprint.get(`https://freeones.com/${actor.slug}/bio`);
if (res.ok) {
return scrapeProfile(res.context);
}
const actorUrl = await getActorUrl(actor);
if (actorUrl) {
const actorRes = await unprint.get(actorUrl);
if (actorRes.ok) {
return scrapeProfile(actorRes.context);
}
}
return null;
}
module.exports = {
fetchProfile,
};