'use strict'; const qu = require('../utils/q'); const slugify = require('../utils/slugify'); const { feetInchesToCm, lbsToKg, femaleFeetUsToEu } = require('../utils/convert'); const { getImageWithFallbacks } = require('./elevatedx'); function composeEntryId(release) { return `${qu.formatDate(release.date, 'YYYY-MM-DD')}-${release.actors.map((actor) => slugify(actor)).join('-')}`; } function scrapeAll(scenes, channel) { return scenes.map(({ query }) => { const release = {}; release.url = query.url('a.item-video-overlay, a.item-episode-overlay'); release.title = query.cnt('.item-title'); release.date = query.date('.video-date', 'MMM D, YYYY'); release.duration = query.duration('.video-time'); release.actors = query.contents('.information a[href*="models/"]').map((actor) => actor.match(/[a-z ]+/i)?.[0].trim()).filter(Boolean); release.poster = getImageWithFallbacks(query.q, 'img.mainThumb', channel); release.teaser = query.video('img.mainThumb', 'data-vid'); release.entryId = composeEntryId(release); return release; }); } function scrapeScene({ query }, url, channel) { const release = {}; release.title = query.content('h1.title'); release.description = query.content('p.description'); release.date = query.date('.date', 'MMM D, YYYY'); release.duration = query.duration('.time'); release.actors = query.contents('.featured .model'); const poster = query.img('.video video', 'poster', { origin: channel.url }); if (poster) { release.poster = [ poster.replace('-4x', '-2x'), // 4x appears to be upscaled beyond original resolution poster.replace('-4x', '-1x'), poster, ]; } release.photos = query.imgs('.photos .thumbs[data-src]'); release.trailer = query.video('.video source'); release.tags = query.contents('.video-tags a[href*="categories/"]'); release.entryId = composeEntryId(release); return release; } function scrapeProfile({ query, el }, url, entity, _include) { const profile = { url }; const bio = Array.from(Array.from(query.html('.stats script').matchAll(/totalStats\.push\(.*\)/g))).reduce((acc, match) => { const { query: statQuery } = qu.extract(match[0].slice(match[0].indexOf('`'), match[0].lastIndexOf('`'))); return { ...acc, [slugify(statQuery.content('span'), '_')]: statQuery.text('p'), }; }, {}); profile.description = query.cnt('.about p'); profile.birthPlace = bio.place_of_birth; profile.dateOfBirth = qu.extractDate(bio.date_of_birth, ['MMMM DD, YYYY', 'MM/DD/YYYY']); profile.ethnicity = bio.ethnicity; profile.measurements = bio.measurements; profile.height = feetInchesToCm(bio.height); profile.weight = lbsToKg(bio.weight); profile.hairColor = bio.hair_color; profile.eyes = bio.eye_color; profile.feet = femaleFeetUsToEu(bio.feet_size); if (/(natural)|(real)/i.test(bio.boob_type || bio.tits_type)) { profile.naturalBoobs = true; } if (/(enhanced)|(fake)/i.test(bio.boob_type || bio.tits_type)) { profile.naturalBoobs = false; } if (bio.tattoos) { profile.hasTattoos = !/none/i.test(bio.tattoos); profile.tattoos = profile.hasTattoos ? bio.tattoos : null; } if (bio.piercings) { profile.hasPiercings = !/none/i.test(bio.piercings); profile.piercings = profile.hasPiercings ? bio.piercings : null; } profile.avatar = query.img('.picture img'); profile.scenes = scrapeAll(qu.initAll(el, '.scene, .latest-scene .item-episode'), entity); console.log(bio); console.log(profile); return profile; } async function fetchLatest(channel, page = 1) { const url = `${channel.url}/tour/categories/movies/${page}/latest/`; const res = await qu.getAll(url, '.main .item-video'); if (res.ok) { return scrapeAll(res.items, channel); } return res.status; } async function fetchProfile({ name: actorName }, entity, include) { const searchRes = await qu.get(`${entity.url}/tour/search.php?model_name=${actorName}`); if (!searchRes.ok) { return searchRes.status; } const actorUrl = searchRes.item.query.url(`.item-portrait a[title="${actorName}"]`); if (!actorUrl) { return null; } const actorRes = await qu.get(actorUrl); if (actorRes.ok) { return scrapeProfile(actorRes.item, actorUrl, entity, include); } return actorRes.status; } module.exports = { fetchLatest, fetchProfile, scrapeScene, };