'use strict'; /* eslint-disable newline-per-chained-call */ const bhttp = require('bhttp'); const cheerio = require('cheerio'); const moment = require('moment'); const knex = require('../knex'); const { matchTags } = require('../tags'); function scrape(html, site, upcoming) { const $ = cheerio.load(html, { normalizeWhitespace: true }); const sceneElements = $('.release-card.scene').toArray(); return sceneElements.reduce((acc, element) => { const isUpcoming = $(element).find('.icon-upcoming.active').length === 1; if ((upcoming && !isUpcoming) || (!upcoming && isUpcoming)) { return acc; } const sceneLinkElement = $(element).find('a'); const url = `https://www.brazzers.com${sceneLinkElement.attr('href')}`; const title = sceneLinkElement.attr('title'); const shootId = url.split('/').slice(-3, -2)[0]; const date = moment.utc($(element).find('time').text(), 'MMMM DD, YYYY').toDate(); const actors = $(element).find('.model-names a').map((actorIndex, actorElement) => $(actorElement).attr('title')).toArray(); const likes = Number($(element).find('.label-rating .like-amount').text()); const dislikes = Number($(element).find('.label-rating .dislike-amount').text()); const poster = `https:${$(element).find('.card-main-img').attr('data-src')}`; const photos = $(element).find('.card-overlay .image-under').map((photoIndex, photoElement) => `https:${$(photoElement).attr('data-src')}`).toArray(); return acc.concat({ url, shootId, title, actors, date, poster, photos, rating: { likes, dislikes, }, site, }); }, []); } async function scrapeScene(html, url, site) { const $ = cheerio.load(html, { normalizeWhitespace: true }); const videoJson = $('script:contains("window.videoUiOptions")').html(); const videoData = JSON.parse(videoJson.slice(videoJson.indexOf('{"stream_info":'), videoJson.lastIndexOf('"},') + 2)); const shootId = url.split('/').slice(-3, -2)[0]; const title = $('.scene-title[itemprop="name"]').text(); const description = $('#scene-description p[itemprop="description"]') .contents() .first() .text() .trim(); const date = moment.utc($('.more-scene-info .scene-date').text(), 'MMMM DD, YYYY').toDate(); const actors = $('.related-model a').map((actorIndex, actorElement) => $(actorElement).text()).toArray(); const duration = Number($('.scene-length[itemprop="duration"]').attr('content').slice(1, -1)) * 60; const likes = Number($('.label-rating .like').text()); const dislikes = Number($('.label-rating .dislike').text()); const siteElement = $('.niche-site-logo'); const siteUrl = `https://www.brazzers.com${siteElement.attr('href').slice(0, -1)}`; const siteName = siteElement.attr('title'); const rawTags = $('.tag-card-container a').map((tagIndex, tagElement) => $(tagElement).text()).toArray(); const poster = `https:${videoData.poster}`; const trailer = `https:${videoData.stream_info.http.paths.mp4_480_1500}`; const photos = $('.carousel-thumb a').map((photoIndex, photoElement) => `https:${$(photoElement).attr('href')}`).toArray(); const [tags, channelSite] = await Promise.all([ matchTags(rawTags), knex('sites') .where({ url: siteUrl }) .orWhere({ name: siteName }) .first(), ]); return { url, shootId, title, description, actors, date, poster, photos, trailer: { src: trailer, quality: 480, }, duration, rating: { likes, dislikes, }, tags, site: channelSite || site, }; } async function fetchLatest(site, page = 1) { const res = await bhttp.get(`${site.url}/page/${page}/`); return scrape(res.body.toString(), site, false); } async function fetchUpcoming(site) { const res = await bhttp.get(`${site.url}/`); return scrape(res.body.toString(), site, true); } async function fetchScene(url, site) { const res = await bhttp.get(url); return scrapeScene(res.body.toString(), url, site); } module.exports = { fetchLatest, fetchUpcoming, fetchScene, };