diff --git a/src/scrapers/babepedia.js b/src/scrapers/babepedia.js new file mode 100644 index 00000000..e593cb67 --- /dev/null +++ b/src/scrapers/babepedia.js @@ -0,0 +1,168 @@ +'use strict'; + +const qu = require('../utils/q'); +const slugify = require('../utils/slugify'); +const moment = require('moment'); + +function scrapeProfile({ query, el }, actorName, entity, include) { + let profile = { name: actorName }; + + if (!query) return {}; + + const name = query.cnt('#babename') + + if (!name) return {}; + + if (actorName !== name) { + profile.aliasFor = name; + } + + const avatar = query.url('#profimg a'); + if (avatar) profile.avatar = { src: `${entity.url}${avatar}`, credit: 'Babepedia' }; + + const aka = query.cnt('#aka'); + if (aka) profile.aliases = aka?.replace('aka ', '')?.split('/').map(alias => alias.trim()); + + function measurementsFromString(str){ + const [bra, waist, hip] = str.split("-"); + if (bra && waist && hip) { + const measurements = {}; + measurements.bust = parseInt(bra); + measurements.cup = measurements.bust ? bra.replace(measurements.bust, "") : null; + measurements.waist = Number(waist); + measurements.hip = Number(hip); + return measurements; + } + return null; + } + + const allowedKeys = ['birthPlace', 'eyes', 'hair', 'birthdate', 'weight', + 'height', 'naturalBoobs', 'tattoos', 'piercings'] ; + + const bio = query.all('#biolist li').reduce((acc, item) => { + const keyMatch = query.cnt(item).split(':'); + + if (keyMatch && keyMatch.length === 2) { + let key = keyMatch[0].toLowerCase(); + let value = keyMatch[1].trim(); + + if (key === 'birthplace') key = 'birthPlace'; + if (key === 'eye color') key = 'eyes'; + if (key === 'hair color') key = 'hair'; + + if (key == 'measurements' && value) { + const measurements = measurementsFromString(value); + if (measurements) { + if (measurements.bust) acc.bust = measurements.bust; + if (measurements.cup) acc.cup = measurements.cup; + if (measurements.waist) acc.waist = measurements.waist; + if (measurements.hip) acc.hip = measurements.hip; + } + } + + if (key === 'born' && value) { + key = 'birthdate'; + value = moment.utc(value.replace(' of ', ' '), 'dddd Do MMMM YYYY')?.toDate(); + } + + if (key == 'height' && value) { + const rawHeightMatch = value.match(/\d+ cm/); + const cm = rawHeightMatch ? rawHeightMatch[0] : null; + value = cm ? parseInt(cm.replace("cm", "")) : null; + } + + if (key == 'weight' && value) { + const rawWeightMatch = value.match(/\d+ kg/); + const kg = rawWeightMatch ? rawWeightMatch[0] : null; + value = kg ? parseInt(kg.replace("kg", "")) : null; + } + + if (key == 'boobs' && value) { + if (value.match(/fake/i)) { + key = 'naturalBoobs'; + value = false; + } else if (value.match(/real/i)) { + key = 'naturalBoobs'; + value = true; + } + } + + if (key == 'tattoos' && value) { + if (value.match(/none/i)) { + acc.hasTattoos = false; + value = ''; + } else { + acc.hasTattoos = true; + } + } + + if (key == 'piercings' && value) { + if (value.match(/none/i)) { + acc.hasPiercings = false; + value = ''; + } else { + acc.hasPiercings = true; + } + } + + if (allowedKeys.includes(key)) { + acc[key] = value; + } + } + + return acc; + }, {}); + + profile = Object.assign(profile, bio); + + return profile; +} + +function scrapeSearch({ query, el }, actorName, entity, include) { + + const links = query.all('.results .thumbshot'); + + return links.map(link => { + const linkName = query.cnt(link, 'a'); + const linkUrl = query.url(link, 'a'); + const actorNameMatch = new RegExp( actorName, 'g' ); + + if (linkName?.match(actorNameMatch)) { + return linkUrl; + } + }).filter(Boolean); +} + +async function fetchProfile(actor, entity, include) { + const actorName = actor.name.replace('\'', ''); + + if (actor?.gender === 'male') { + return null; + } + + let url = `${entity.url}/search/${actorName}`; + let res = await qu.get(url); + + // Check if search redirects + let result = res.ok ? scrapeProfile(res.item, actorName, entity, include) : {}; + if (result.name === actorName) { + return result; + } + + if (res.ok) { + const actorPath = scrapeSearch(res.item, actorName, entity, include); + + if (actorPath.length === 1) { + url = `${entity.url}${actorPath[0]}`; + res = await qu.get(url); + + return res.ok ? scrapeProfile(res.item, actorName, entity, include) : res.status; + } + } + + return res.status; +} + +module.exports = { + fetchProfile, +}; diff --git a/src/scrapers/scrapers.js b/src/scrapers/scrapers.js index 4cd518b1..a5bb26ad 100644 --- a/src/scrapers/scrapers.js +++ b/src/scrapers/scrapers.js @@ -64,6 +64,7 @@ const xempire = require('./xempire'); // profiles const boobpedia = require('./boobpedia'); const freeones = require('./freeones'); +const babepedia = require('./babepedia'); const scrapers = { releases: { @@ -155,6 +156,7 @@ const scrapers = { anilos: nubiles, aziani, babes: mindgeek, + babepedia, babevr: badoink, baddaddypov: fullpornnetwork, badoinkvr: badoink,