'use strict'; const unprint = require('unprint'); const { decode } = require('html-entities'); const slugify = require('../utils/slugify'); const { feetInchesToCm, femaleFeetUsToEu } = require('../utils/convert'); function scrapeScene(data, channel, parameters) { const release = {}; release.entryId = data.cms_set_id; release.url = `${parameters.scene || channel.url}/video/${data.cms_set_id}`; release.title = data.name; release.description = data.description; release.date = unprint.extractDate(data.added_nice, 'YYYY-MM-DD'); release.duration = Number(data.lengths.total); release.actors = data.data_types.find((dataType) => dataType.data_type === 'Models' || dataType.data_type === 'Talent')?.data_values.map((actor) => ({ name: actor.name, url: `${channel.url}/model/${actor.cms_data_value_id}?models=${encodeURI(actor.name)}`, // slug does not work unless it's also the ID })); release.directors = data.data_types.find((dataType) => dataType.data_type === 'Videographers')?.data_values.map((director) => ({ name: director.name, // url: `${channel.url}/model/${director.slug}?models=${director.name}`, })); release.tags = data.data_types .filter((dataType) => dataType.data_type === 'Tags' || dataType.data_type === 'Category') .flatMap((tags) => tags.data_values.map((tag) => tag.name)); const poster = data.preview_formatted.thumb; const teaser = data.preview_formatted.clip?.[0]; const trailer = data.preview_formatted.trailer?.formats?.[0]?.content?.[0]; if (poster) { release.poster = Object.keys(poster) .filter((key) => poster[key].length > 0) .toSorted((keyA, keyB) => keyB.split('-')[0] - keyA.split('-')[0]) .map((key) => unprint.prefixUrl(`${poster[key][0].fileuri}?${poster[key][0].signature}`, parameters.cdn)); } release.caps = data.content ?.filter((item) => item.content_type === 'image' && item.content?.[0]) .map((item) => [ item.content[0], ...(item.thumb ? Object.keys(item.thumb).toSorted((keyA, keyB) => keyB.split('-')[0] - keyA.split('-')[0]).map((key) => item.thumb[key][0]).filter(Boolean) : []), ]) .map((sources) => sources.map((source) => ({ src: unprint.prefixUrl(`${source.fileuri}?${source.signature}`, parameters.cdn), expectType: { 'application/octet-stream': 'image/jpeg', }, }))); if (teaser && teaser.fileuri !== trailer?.fileuri) { release.teaser = unprint.prefixUrl(`${teaser.fileuri}?${teaser.signature}`, parameters.cdn); } if (trailer) { release.trailer = unprint.prefixUrl(`${trailer.fileuri}?${trailer.signature}`, parameters.cdn); } release.channel = slugify(data.data_types.find((dataType) => dataType.data_type === 'Series')?.data_values[0]?.name, ''); return release; } async function fetchLatest(channel, page = 1, { parameters }) { const query = new URLSearchParams({ cms_area_id: parameters.areaId, cms_block_id: parameters.blockId, count: 100, start: (page - 1) * 100, orderby: 'published_desc', content_type: 'video', // unsure what this does status: 'enabled', cms_set_ids: undefined, data_types: 1, content_count: 1, data_type_search: parameters.seriesId && JSON.stringify({ 7: parameters.seriesId.toString() }), // doesn't seem relevant }).toString(); const url = `https://azianistudios.com/tour_api.php/content/sets?${query}`; const res = await unprint.get(url, { headers: { Referer: channel.url, 'x-nats-cms-area-id': parameters.areaId, }, }); if (res.ok && res.data.success) { return res.data.sets.map((data) => scrapeScene(data, channel, parameters)); } return res.status; } async function fetchScene(url, entity, _baseRelease, { parameters }) { const entryId = new URL(url).pathname.match(/\/video\/(\w+)/)[1]; const query = new URLSearchParams({ cms_set_ids: entryId, cms_area_id: parameters.areaId, cms_block_id: parameters.blockId, content: 1, orderby: 'published_desc', content_type: 'video', // unsure what this does data_types: 1, content_count: 1, }).toString(); const apiUrl = `https://azianistudios.com/tour_api.php/content/sets?${query}`; const res = await unprint.get(apiUrl, { headers: { Referer: entity.url, 'x-nats-cms-area-id': parameters.areaId, }, }); if (res.ok && res.data.success) { return scrapeScene(res.data.sets[0], entity, parameters); } return res.status; } function scrapeProfile(data, entity, parameters) { const profile = {}; const bio = Object.fromEntries(Object.values(data.data_detail_values).map((detail) => [ slugify(detail.name, '_'), decode(detail.value || detail.content_formatted || detail.content), ])); profile.url = `${entity.url}/model/${data.cms_data_value_id}`; profile.entryId = data.cms_data_value_id; profile.description = data.description; profile.gender = bio.gender?.toLowerCase(); profile.age = bio.age; profile.dateOfBirth = unprint.extractDate(`${bio.born} 0`, 'MMMM Do YYYY', { match: /\w+ \d+\w{2} \d{1,4}/ }); profile.measurements = bio.measurements; profile.height = feetInchesToCm(bio.height); profile.foot = femaleFeetUsToEu(bio.foot_size); profile.hairColor = bio.hair_color; profile.eyeColor = bio.eye_color; const avatar = bio.thumbnail?.image[0]; if (avatar) { profile.avatar = { src: `${parameters.cdn}${avatar.fileuri}?${avatar.signature}`, expectType: { 'application/octet-stream': 'image/jpeg', }, }; } return profile; } async function fetchProfile({ url }, { entity, parameters }) { if (!url) { // no easy search option return null; } const actorId = new URL(url).pathname.match(/model\/(\d+)/)[1]; const query = new URLSearchParams({ cms_data_value_ids: actorId, cms_block_id: entity.parameters.modelBlockId, cms_data_type_id: 4, }).toString(); const apiUrl = `https://azianistudios.com/tour_api.php/content/data-values?${query}`; const res = await unprint.get(apiUrl, { headers: { Referer: entity.url, 'x-nats-cms-area-id': entity.parameters.areaId, }, }); if (res.ok && res.data.success) { return scrapeProfile(res.data.data_values[0], entity, parameters); } return res.status; } module.exports = { fetchLatest, fetchProfile, fetchScene, };