'use strict'; const unprint = require('unprint'); const http = require('../utils/http'); const slugify = require('../utils/slugify'); const { feetInchesToCm, lbsToKg } = require('../utils/convert'); function scrapeAll(scenes, channel, _options) { return scenes.map(({ query }) => { const release = {}; release.url = query.url('a.scene-title, a.scene-img', { origin: channel.url }); release.entryId = query.attribute('article[data-scene-id]', 'data-scene-id') || new URL(release.url).pathname.match(/^\/(\d+)/)?.[1]; release.title = query.content('.scene-title')?.trim(); release.duration = query.duration('.scene-length'); release.actors = query.content('.scene-performer-names')?.split(/[,&]/).map((actor) => actor.trim()); release.poster = query.sourceSet('.screenshot', 'data-srcset'); const sceneId = query.attribute('article[data-scene-id]', 'data-scene-id'); const masterId = query.attribute('article[data-master-id]', 'data-master-id'); if (sceneId && masterId) { release.teaser = `https://video.adultempire.com/hls/previewscene/${masterId}/${sceneId}/index-f1-v1.m3u8`; } return release; }); } const photoRegex = /(\/\w\/\d+\/)\d+/; async function scrapeRelease({ query, html, element }, { url, entity, baseRelease, parameters }) { const release = {}; const type = query.exists('.scene-list-header') ? 'movie' : 'scene'; release.entryId = new URL(url).pathname.match(/\/(\d+)/)[1]; const title = query.content('.scene-page .description, .video-page .description'); if (/^scene \d+$/i.test(title)) { release.sceneIndex = unprint.extractNumber(title); } else { release.title = title; } release.date = query.date('.release-date:first-child', 'MMM DD, YYYY', /\w{3} \d{2}, \d{4}/); release.duration = query.duration('.release-date:last-child'); release.actors = query.all('.video-performer').map((el) => { const avatar = unprint.query.img(el, 'img', 'data-bgsrc'); return { name: unprint.query.content(el, 'span').trim(), url: unprint.query.url(el, 'a', { origin: entity.url }), avatar: [ avatar.replace(/\/actor\/\d+/, '/actor/1600'), avatar, ], }; }); release.tags = query.contents('.tags a, .categories a'); release.studio = parameters?.studio === false ? null : slugify(query.content('.studio span:last-child, .studio a'), ''); if (type === 'scene') { release.director = query.text('.director'); release.duration = query.number('.release-date:last-child') * 60; release.poster = baseRelease?.poster || query.url('link[rel="image_src"]') || query.meta('property="og:image"'); } if (type === 'movie') { release.director = query.content('.director a'); release.covers = [query.sourceSet('.carousel-item .boxcover-image', 'data-srcset')]; release.scenes = scrapeAll(unprint.initAll(element, '#scenes .grid-item'), entity); } if (query.exists('.video-title .movie-title')) { release.movie = { title: query.content('#viewLargeBoxcover .modal-title a'), url: query.url('#viewLargeBoxcover .modal-title a', 'href', { origin: entity.url }), entryId: query.url('#viewLargeBoxcover .modal-title a')?.match(/(\d+)\//)[1], covers: query.imgs('#viewLargeBoxcover #viewLargeBoxcoverCarousel .carousel-item > img'), }; } release.caps = query.imgs('#dv_frames a > img', { attribute: 'data-src' }).map((photo) => [ photo.replace(photoRegex, (match, path) => `${path}1920`), photo.replace(photoRegex, (match, path) => `${path}1280`), photo, ]); const trailerId = html.match(/item: (\d+),/)?.[1]; if (trailerId) { release.trailer = `https://trailer.adultempire.com/hls/trailer/${trailerId}/master.m3u8`; } if (query.exists('.user-actions .btn-4k')) { release.qualities = [2160]; } return release; } async function scrapeProfile({ query }) { const profile = {}; const bio = query.contents('#profileModal .well li').reduce((acc, info) => { const [key, value] = info.split(':'); return { ...acc, [slugify(key, '_')]: value.trim(), }; }, {}); const bioText = query.content('#profileModal .well'); profile.description = query.content('#profileModal .modal-body') .slice(bioText.length) .replace(/Biography Text ©Adult DVD Empire/i, '') .trim(); profile.measurements = bio.measurements?.replace(/["\s]+/g, ''); profile.hair = bio.hair; profile.eyes = bio.eyes; profile.ethnicity = bio.ethnicity; profile.height = feetInchesToCm(bio.height); profile.weight = lbsToKg(bio.weight); const avatar = query.img('picture img, .performer-image-container img'); if (avatar) { profile.avatar = [ avatar .replace('_bust', '_body') .replace(/\/actor\/\d+\//i, '/actor/1000/'), avatar, ]; } return profile; } async function fetchLatest(channel, page, options) { // const res = await qu.getAll(`${channel.url}/watch-newest-clips-and-scenes.html?page=${page}&hybridview=member`, '.item-grid-scene .grid-item'); const res = await unprint.get(options.parameters?.latest ? `${options.parameters.latest}?page=${page}&view=grid` : `${channel.url}/watch-newest-clips-and-scenes.html?page=${page}&view=grid`, { selectAll: '.item-grid-scene .grid-item' }); if (res.ok) { return scrapeAll(res.context, channel, options); } return res.status; } async function fetchProfilePage(actorUrl) { const res = await unprint.get(actorUrl, { select: '#content', rejectUnauthorized: false, }); if (res.ok) { return scrapeProfile(res.context); } return res.status; } async function fetchProfile(baseActor, channel, include) { if (baseActor.url) { const profile = await fetchProfilePage(baseActor, channel, include); if (typeof profile === 'object') { return profile; } } const searchRes = await http.get(`https://www.adultempire.com/search/SearchAutoComplete_Agg_EmpireDTRank?search_type=Pornstars&rows=9&name_startsWith=${slugify(baseActor.name, '+')}`); if (searchRes.ok && searchRes.body.Results) { const actorResult = searchRes.body.Results.find((result) => /performer/i.test(result.BasicResponseGroup?.displaytype) && new RegExp(baseActor.name, 'i').test(result.BasicResponseGroup?.description)); if (actorResult) { const url = `https://www.adultempire.com/${actorResult.BasicResponseGroup.id}`; return fetchProfilePage(url); } return null; } return searchRes.status; } module.exports = { fetchLatest, // fetchMovies, fetchProfile, scrapeScene: scrapeRelease, scrapeMovie: scrapeRelease, };