traxxx/src/scrapers/bellesa.js

118 lines
2.8 KiB
JavaScript

'use strict';
const unprint = require('unprint');
const slugify = require('../utils/slugify');
const channelMap = {
bellesa_house_party: 'House Party',
bellesa_blind_date: 'Blind Date',
};
function scrapeScene(data, entity, parameters) {
const release = {};
release.entryId = data.id;
release.url = `${new URL(entity.url).origin}/videos/${data.id}/${slugify(data.title)}`;
release.title = data.title;
release.description = data.description;
release.date = new Date(data.posted_on * 1000);
release.duration = data.duration;
release.actors = data.performers?.map((actor) => ({
name: actor.name,
url: `https://www.bellesa.co/pornstar/${actor.handle}`, // no actor page on Bellesa Plus, presumably shared database
entryId: actor.uid,
gender: actor.gender,
avatar: actor.image,
}));
release.tags = [
...(data.tags?.split(',') || []),
...(data.categories?.map((category) => category.name) || []),
];
release.qualities = data.resolutions?.split(',').map(Number);
release.poster = data.image;
const trailerId = data.source || data.trailer;
if (trailerId) {
// the regular site has full videos as 'trailers'
if (parameters.source === 'plus') {
release.trailer = [1080, 720, 480].map((quality) => ({
src: `https://s.bellesa.co/v/${trailerId}/${quality}.mp4`,
quality,
}));
}
release.teaser = `https://s.bellesa.co/v/${trailerId}/preview_62.mp4`;
}
const channel = data.content_provider?.[0]?.name;
if (channel) {
release.channel = `${channelMap[slugify(channel, '_')] || channel}${data.access.plus ? ' Plus' : ''}`;
}
return release;
}
async function fetchLatest(channel, page = 1, { parameters }) {
const provider = new URL(channel.url).searchParams.get('providers');
const res = await unprint.get(`${parameters.api}/videos?filter[provider]=${provider}&limit=24&sources=${parameters.source}&page=${page}`, {
interface: 'request',
headers: {
// currently only required for Bellesa Plus
Referer: `${new URL(channel.url).origin}/videos`,
Cookie: 'bellesa_agegate=true',
},
});
if (res.ok) {
return res.data.map((scene) => scrapeScene(scene, channel, parameters));
}
return res.status;
}
async function fetchScene(url, entity, baseRelease, { parameters }) {
if (baseRelease?.entryId) {
// identical data
return baseRelease;
}
const res = await unprint.get(url, {
interface: 'request',
headers: {
// currently only required for Bellesa Plus
Referer: `${new URL(entity.url).origin}/videos`,
Cookie: 'bellesa_agegate=true',
},
parser: {
runScripts: 'dangerously',
},
});
if (res.ok) {
const data = res.context.window.__INITIAL_DATA__.video || res.context.window.__INITIAL_DATA__.data.video;
if (data) {
return scrapeScene(data, entity, parameters);
}
return null;
}
return res.status;
}
module.exports = {
fetchLatest,
fetchScene,
};