diff --git a/assets/components/actors/actor.vue b/assets/components/actors/actor.vue index 7923540e..0a405a54 100644 --- a/assets/components/actors/actor.vue +++ b/assets/components/actors/actor.vue @@ -301,7 +301,7 @@ export default { .header-gender { display: inline-block; - margin: 0 0 0 .25rem; + margin: 0 0 0 .5rem; transform: translate(0, .1rem); .icon { diff --git a/assets/js/actors/actions.js b/assets/js/actors/actions.js index cf98a78a..e948b3d6 100644 --- a/assets/js/actors/actions.js +++ b/assets/js/actors/actions.js @@ -65,6 +65,7 @@ function initActorActions(store, _router) { bust waist hip + naturalBoobs heightMetric: height(units:METRIC) heightImperial: height(units:IMPERIAL) weightMetric: weight(units:METRIC) diff --git a/src/scrapers/boobpedia.js b/src/scrapers/boobpedia.js new file mode 100644 index 00000000..d0d85e83 --- /dev/null +++ b/src/scrapers/boobpedia.js @@ -0,0 +1,84 @@ +'use strict'; + +const bhttp = require('bhttp'); + +const { ex } = require('../utils/q'); + +function scrapeProfile(html) { + const { q, qa, qd, qi } = ex(html); /* eslint-disable-line object-curly-newline */ + const profile = {}; + + const bio = qa('.infobox tr[valign="top"]') + .map(detail => qa(detail, 'td', true)) + .reduce((acc, [key, value]) => ({ ...acc, [key.slice(0, -1).replace(/[\s+|/]/g, '_')]: value }), {}); + + const catlinks = qa('#mw-normal-catlinks a', true); + const isTrans = catlinks.some(link => link.match(/shemale|transgender/i)); + + profile.gender = isTrans ? 'transsexual' : 'female'; + profile.birthdate = qd('.bday', 'YYYY-MM-DD'); + + profile.description = q('#mw-content-text > p', true); + + if (bio.Born) profile.birthPlace = bio.Born.slice(bio.Born.lastIndexOf(')') + 1); + if (bio.Ethnicity) profile.ethnicity = bio.Ethnicity; + + if (bio.Measurements) { + const [bust, waist, hip] = bio.Measurements + .match(/\d+(\w+)?-\d+-\d+/g) + .slice(-1)[0] // allow for both '34C-25-36' and '86-64-94 cm / 34-25-37 in' + .split('-'); + + if (/[a-zA-Z]/.test(bust)) profile.bust = bust; // only use bust if cup size is included + + profile.waist = Number(waist); + profile.hip = Number(hip); + } + + if (bio.Bra_cup_size) { + const bust = bio.Bra_cup_size.match(/^\d+\w+/); + if (bust) [profile.bust] = bust; + } + + if (bio.Boobs === 'Enhanced') profile.naturalBoobs = false; + if (bio.Boobs === 'Natural') profile.naturalBoobs = true; + + if (bio.Height) profile.height = Number(bio.Height.match(/\d+\.\d+/g).slice(-1)[0]) * 100; + if (bio.Weight) profile.weight = Number(bio.Weight.match(/\d+/g)[1]); + + if (bio.Eye_color) profile.eyes = bio.Eye_color; + if (bio.Hair) [profile.hair] = bio.Hair.split(','); + + if (bio.Blood_group) profile.blood = bio.Blood_group; + if (bio.Also_known_as) profile.aliases = bio.Also_known_as.split(', '); + + const avatars = qi('.image img'); + + if (avatars.length > 0) { + const [avatarThumbPath] = avatars; + const avatarPath = avatarThumbPath.slice(0, avatarThumbPath.lastIndexOf('/')).replace('thumb/', ''); + + profile.avatar = `http://www.boobpedia.com${avatarPath}`; + } + + const socials = qa('.infobox a.external'); + + console.log(socials); + + // return profile; +} + +async function fetchProfile(actorName) { + const actorSlug = actorName.replace(/\s+/, '_'); + const res = await bhttp.get(`http://www.boobpedia.com/boobs/${actorSlug}`); + + if (res.statusCode === 200) { + return scrapeProfile(res.body.toString()); + } + + return null; +} + +module.exports = { + fetchProfile, +}; diff --git a/src/scrapers/ddfnetwork.js b/src/scrapers/ddfnetwork.js index a12017f3..380213dc 100644 --- a/src/scrapers/ddfnetwork.js +++ b/src/scrapers/ddfnetwork.js @@ -5,8 +5,6 @@ const cheerio = require('cheerio'); const { JSDOM } = require('jsdom'); const moment = require('moment'); -const knex = require('../knex'); - /* eslint-disable newline-per-chained-call */ function scrapeLatest(html, site) { const $ = cheerio.load(html, { normalizeWhitespace: true }); diff --git a/src/scrapers/scrapers.js b/src/scrapers/scrapers.js index 9c108d97..b32cd800 100644 --- a/src/scrapers/scrapers.js +++ b/src/scrapers/scrapers.js @@ -33,6 +33,7 @@ const twentyonesextury = require('./21sextury'); const xempire = require('./xempire'); // profiles +const boobpedia = require('./boobpedia'); const freeones = require('./freeones'); const freeonesLegacy = require('./freeones_legacy'); const pornhub = require('./pornhub'); @@ -77,6 +78,7 @@ module.exports = { blowpass, julesjordan, brazzers, + boobpedia, legalporno, pornhub, freeones, diff --git a/src/utils/q.js b/src/utils/q.js index 547558be..732e89ad 100644 --- a/src/utils/q.js +++ b/src/utils/q.js @@ -79,12 +79,18 @@ const funcs = { qt: qtrailer, }; -function ctx(element) { +function ctx(element, window) { const contextFuncs = Object.entries(funcs) // dynamically attach methods with context - .reduce((acc, [key, func]) => ({ ...acc, [key]: (...args) => func(element, ...args) }), {}); + .reduce((acc, [key, func]) => ({ + ...acc, + [key]: (...args) => (window && args[0] instanceof window.HTMLElement // allow for different context + ? func(...args) + : func(element, ...args)), + }), {}); return { element, + ...(window && { window }), ...contextFuncs, }; } @@ -94,9 +100,9 @@ function ctxa(context, selector) { } function ex(html) { - const { document } = new JSDOM(html).window; + const { window } = new JSDOM(html); - return ctx(document); + return ctx(window.document, window); } module.exports = {