'use strict'; const qu = require('../utils/qu'); function scrapeAll(scenes) { return scenes.map(({ query }) => { const release = {}; const href = query.url('.shoot-thumb-info > a'); release.url = `https://kink.com${href}`; release.shootId = href.split('/').slice(-1)[0]; release.entryId = release.shootId; release.title = query.q('.shoot-thumb-title a', true); release.date = query.date('.date', 'MMM DD, YYYY'); release.actors = query.all('.shoot-thumb-models a', true); release.stars = query.q('.average-rating', 'data-rating') / 10; release.poster = query.img('.adimage'); release.photos = query.imgs('.rollover .roll-image', 'data-imagesrc').map((photo) => [ photo.replace('410/', '830/'), photo, ]); release.duration = query.dur('.video span'); return release; }); } async function scrapeScene({ query }, url) { const release = { url }; release.shootId = new URL(url).pathname.split('/')[2]; release.entryId = release.shootId; release.title = query.q('.shoot-title span.favorite-button', 'data-title'); release.description = query.q('.description-text', true); release.date = query.date('.shoot-date', 'MMMM DD, YYYY'); release.actors = query.all('.names a', true).map((actor) => actor.replace(/,\s*/, '')); release.director = query.q('.director-name', true); release.photos = query.imgs('.gallery .thumb img, #gallerySlider .gallery-img', 'data-image-file'); release.poster = query.poster(); release.tags = query.all('.tag-list a[href*="/tag"]', true).map((tag) => tag.replace(/,\s*/, '')); const trailer = query.q('.player span[data-type="trailer-src"]', 'data-url'); if (trailer) { release.trailer = [ { src: trailer.replace('480p', '1080p'), quality: 1080, }, { src: trailer.replace('480p', '720p'), quality: 720, }, { src: trailer, quality: 480, }, { src: trailer.replace('480p', '360p'), quality: 360, }, ]; } release.channel = query.url('.shoot-logo a').split('/').slice(-1)[0]; return release; } async function fetchActorReleases(actorUrl, page = 1, accReleases = []) { const res = await qu.get(`${actorUrl}?page=${page}`); if (res.ok) { const releases = scrapeAll(qu.initAll(res.item.el, '.shoot-list .shoot')); const hasNextPage = res.item.query.exists('.paginated-nav li:last-child:not(.disabled)'); if (hasNextPage) { return fetchActorReleases(actorUrl, page + 1, accReleases.concat(releases)); } return accReleases.concat(releases); } return accReleases; } async function scrapeProfile({ query }, actorUrl, include) { const profile = {}; profile.description = query.q('.bio #expand-text', true); const tags = query.all('.bio-tags a', true); if (tags.includes('brunette') || tags.includes('brunet')) profile.hairColor = 'brown'; if (tags.includes('blonde') || tags.includes('blond')) profile.hairColor = 'blonde'; if (tags.includes('black hair')) profile.hairColor = 'black'; if (tags.includes('redhead')) profile.hairColor = 'red'; if (tags.includes('natural boobs')) profile.naturalBoobs = true; if (tags.includes('fake boobs')) profile.naturalBoobs = false; if (tags.includes('white')) profile.ethnicity = 'white'; if (tags.includes('latin')) profile.ethnicity = 'latin'; if (tags.includes('Black')) profile.ethnicity = 'black'; if (tags.includes('pierced nipples')) profile.hasPiercings = true; if (tags.includes('tattoo')) profile.hasTattoos = true; if (tags.includes('foreskin')) profile.hasForeskin = true; if ((tags.includes('big dick') || tags.includes('foreskin')) && (tags.includes('fake boobs') || tags.includes('big tits'))) profile.gender = 'transsexual'; profile.avatar = query.img('.bio-slider-img, .bio-img:not([src*="Missing"])'); profile.social = query.urls('a.social-link'); if (include.releases) { profile.releases = await fetchActorReleases(actorUrl); } return profile; } async function fetchLatest(site, page = 1) { // const res = await qu.getAll(`${site.url}/latest/page/${page}`, '.shoot-list .shoot', { // const res = await qu.getAll(`https://www.kink.com/channel/bound-gang-bangs/latest/page/${page}`, '.shoot-list .shoot', { const res = await qu.getAll(`https://www.kink.com/search?type=shoots&channelIds=${site.slug}&sort=published&page=${page}`, '.shoot-list .shoot', { ct: 2, }, { includeDefaultHeaders: false, followRedirects: false, }); if (res.ok) { return scrapeAll(res.items, site); } return res.status; } async function fetchProfile({ name: actorName }, entity, include) { const searchRes = await qu.getAll(`https://kink.com/search?type=performers&q=${actorName}`, '.model'); if (searchRes.ok) { const actorItem = searchRes.items.find((item) => item.query.exists(`.model-link img[alt="${actorName}"]`)); if (actorItem) { const actorPath = actorItem.query.url('.model-link'); const actorUrl = `https://kink.com${actorPath}`; const actorRes = await qu.get(actorUrl); if (actorRes.ok) { return scrapeProfile(actorRes.item, actorUrl, include); } return actorRes.status; } return null; } return searchRes.status; } module.exports = { fetchLatest, fetchProfile, scrapeScene, };