forked from DebaucheryLibrarian/traxxx
173 lines
3.9 KiB
JavaScript
Executable File
173 lines
3.9 KiB
JavaScript
Executable File
'use strict';
|
|
|
|
const unprint = require('unprint');
|
|
|
|
const slugify = require('../utils/slugify');
|
|
const { stripQuery } = require('../utils/url');
|
|
|
|
async function getTrailer(data) {
|
|
const mediaId = data.medias?.find((media) => media.type === 'free')?.media_id;
|
|
|
|
if (!mediaId) {
|
|
return null;
|
|
}
|
|
|
|
const res = await unprint.get(`https://pornbox.com/media/${mediaId}/stream`);
|
|
|
|
if (res.ok) {
|
|
return res.data.qualities?.map((video) => ({
|
|
src: video.src,
|
|
type: video.type,
|
|
quality: parseInt(video.size, 10),
|
|
}));
|
|
}
|
|
|
|
return null;
|
|
}
|
|
|
|
async function scrapeScene(data, channel, include) {
|
|
const release = {};
|
|
const entityUrl = new URL(channel.url).origin;
|
|
|
|
release.title = data.scene_name || data.custom_name;
|
|
|
|
release.entryId = data.id;
|
|
release.url = `${entityUrl}/watch/${data.id}/${slugify(release.title, '_')}`;
|
|
|
|
release.date = new Date(data.release_date || data.publish_date);
|
|
release.duration = unprint.extractDuration(data.runtime);
|
|
|
|
release.actors = [...data.models, ...(data.male_models || [])].map((model) => ({
|
|
name: model.model_name,
|
|
gender: model.sex,
|
|
entryId: model.model_id,
|
|
url: `${entityUrl}/model/${model.model_id}/${slugify(model.model_name, '_')}`,
|
|
}));
|
|
|
|
release.tags = data.niches.map((niche) => niche.niche);
|
|
|
|
release.poster = [
|
|
data.player_poster,
|
|
data.thumbnail.mosaic,
|
|
data.thumbnail.list,
|
|
data.thumbnail.large, // squared
|
|
data.thumbnail.small,
|
|
];
|
|
|
|
release.photos = data.gallery?.map((photo) => [
|
|
stripQuery(photo.large_thumbnail),
|
|
photo.large_thumbnail,
|
|
photo.small_thumbnail,
|
|
]);
|
|
|
|
release.caps = data.screenshots?.map((screenshot) => [
|
|
screenshot.xga_size,
|
|
screenshot.small_thumbnail,
|
|
]);
|
|
|
|
release.teaser = data.video_preview;
|
|
|
|
if (include?.includeTrailers) {
|
|
release.trailer = await getTrailer(data);
|
|
release.qualities = release.trailer?.map((src) => src.quality);
|
|
}
|
|
|
|
if (data.has_4k_full_video && !release.qualities) {
|
|
release.qualities = [2160];
|
|
}
|
|
|
|
release.studio = slugify(data.studio, '');
|
|
|
|
return release;
|
|
}
|
|
|
|
function scrapeAll(scenes, channel) {
|
|
return Promise.all(scenes.map(async (data) => scrapeScene(data, channel)));
|
|
}
|
|
|
|
async function fetchLatest(channel, page = 1) {
|
|
if (!channel.parameters?.studioId) {
|
|
return null;
|
|
}
|
|
|
|
const url = `https://pornbox.com/studio/${channel.parameters.studioId}/?sort=latest&skip=${page}`; // sort=recent is 'sold recently', not latest chronologically
|
|
const res = await unprint.get(url);
|
|
|
|
if (res.ok && res.data?.contents) {
|
|
return scrapeAll(res.data.contents, channel);
|
|
}
|
|
|
|
return res.status;
|
|
}
|
|
|
|
async function fetchScene(url, entity, baseRelease, include) {
|
|
const entryId = new URL(url).pathname.match(/\/watch(?:-page)?\/(\d+)/)[1];
|
|
const res = await unprint.get(`https://pornbox.com/contents/${entryId}`);
|
|
|
|
if (res.ok) {
|
|
return scrapeScene(res.data, entity, include);
|
|
}
|
|
|
|
return res.status;
|
|
}
|
|
|
|
function scrapeProfile(data) {
|
|
const profile = {};
|
|
|
|
profile.age = data.age;
|
|
profile.gender = data.sex;
|
|
|
|
profile.birthCountry = data.nationality?.[0]?.name;
|
|
profile.nationality = data.nationality?.[0]?.nationality;
|
|
|
|
profile.aliases = data.stage_name;
|
|
|
|
profile.avatar = [
|
|
stripQuery(data.headshot),
|
|
data.headshot,
|
|
];
|
|
|
|
return profile;
|
|
}
|
|
|
|
async function getActorUrl(actor, entity) {
|
|
if (actor.url) {
|
|
return actor.url;
|
|
}
|
|
|
|
const res = await unprint.get(`https://pornbox.com/autocomplete/${actor.name}`);
|
|
|
|
if (res.ok && Array.isArray(res.data)) {
|
|
const model = res.data.find((item) => item.type === 'model' && item.name === actor.name);
|
|
|
|
if (model) {
|
|
return `${entity.url}/model/${model.id}/${slugify(model.name, '_')}`;
|
|
}
|
|
}
|
|
|
|
return null;
|
|
}
|
|
|
|
async function fetchProfile(actor, entity) {
|
|
const url = await getActorUrl(actor, entity);
|
|
|
|
if (!url) {
|
|
return null;
|
|
}
|
|
|
|
const actorId = new URL(url).pathname.match(/\/model\/(\d+)/)[1];
|
|
const res = await unprint.get(`https://pornbox.com/model/info/${actorId}`);
|
|
|
|
if (res.ok) {
|
|
return scrapeProfile(res.data, entity);
|
|
}
|
|
|
|
return res.status;
|
|
}
|
|
|
|
module.exports = {
|
|
fetchLatest,
|
|
fetchProfile,
|
|
fetchScene,
|
|
};
|