Added WankzVR update, scene and profile scraper.
This commit is contained in:
11
src/deep.js
11
src/deep.js
@@ -56,10 +56,17 @@ async function fetchScene(scraper, url, entity, baseRelease, options) {
|
||||
}
|
||||
|
||||
if (scraper.scrapeScene) {
|
||||
const res = await qu.get(url);
|
||||
const session = qu.session();
|
||||
const res = await qu.get(url, null, null, { session });
|
||||
const cookie = await session._sessionOptions.cookieJar.get(url);
|
||||
|
||||
if (res.ok) {
|
||||
return scraper.scrapeScene(res.item, url, entity, baseRelease, options);
|
||||
return scraper.scrapeScene(res.item, url, entity, baseRelease, options, {
|
||||
session,
|
||||
headers: res.headers,
|
||||
cookieJar: session._sessionOptions.cookieJar,
|
||||
cookie,
|
||||
});
|
||||
}
|
||||
|
||||
return res.status;
|
||||
|
||||
@@ -108,6 +108,8 @@ function toBaseSource(rawSource) {
|
||||
if (rawSource.interval) baseSource.interval = rawSource.interval;
|
||||
if (rawSource.concurrency) baseSource.concurrency = rawSource.concurrency;
|
||||
|
||||
if (rawSource.vr) baseSource.vr = rawSource.vr;
|
||||
|
||||
if (rawSource.credit !== undefined) baseSource.credit = rawSource.credit;
|
||||
if (rawSource.comment) baseSource.comment = rawSource.comment;
|
||||
if (rawSource.group) baseSource.group = rawSource.group;
|
||||
@@ -155,17 +157,19 @@ function baseSourceToBaseMedia(baseSource, role, metadata) {
|
||||
function sortBaseTrailersByQuality(sources, role) {
|
||||
if (role === 'trailers') {
|
||||
const sortedSources = sources.sort((sourceA, sourceB) => {
|
||||
if (config.media.trailerQuality.indexOf(sourceA.quality) > config.media.trailerQuality.indexOf(sourceB.quality)) {
|
||||
if (config.media.trailerQuality.includes(sourceB.quality) && config.media.trailerQuality.indexOf(sourceA.quality) > config.media.trailerQuality.indexOf(sourceB.quality)) {
|
||||
return 1;
|
||||
}
|
||||
|
||||
if (config.media.trailerQuality.indexOf(sourceA.quality) < config.media.trailerQuality.indexOf(sourceB.quality)) {
|
||||
if (config.media.trailerQuality.includes(sourceA.quality) && config.media.trailerQuality.indexOf(sourceA.quality) < config.media.trailerQuality.indexOf(sourceB.quality)) {
|
||||
return -1;
|
||||
}
|
||||
|
||||
return 0;
|
||||
});
|
||||
|
||||
console.log(sortedSources);
|
||||
|
||||
return sortedSources;
|
||||
}
|
||||
|
||||
@@ -632,6 +636,7 @@ function curateMediaEntry(media, index) {
|
||||
size: media.meta.size,
|
||||
width: media.meta.width,
|
||||
height: media.meta.height,
|
||||
vr: media.vr,
|
||||
entropy: media.meta.entropy,
|
||||
sharpness: media.meta.sharpness,
|
||||
source: media.src,
|
||||
|
||||
@@ -57,6 +57,7 @@ const traxxx = require('./traxxx');
|
||||
const vivid = require('./vivid');
|
||||
const vixen = require('./vixen');
|
||||
const vogov = require('./vogov');
|
||||
const wankzvr = require('./wankzvr');
|
||||
const whalemember = require('./whalemember');
|
||||
const xempire = require('./xempire');
|
||||
|
||||
@@ -138,6 +139,7 @@ const scrapers = {
|
||||
vivid,
|
||||
vixen,
|
||||
vogov,
|
||||
wankzvr,
|
||||
whalemember,
|
||||
xempire,
|
||||
},
|
||||
@@ -212,6 +214,7 @@ const scrapers = {
|
||||
men: mindgeek,
|
||||
metrohd: mindgeek,
|
||||
milehighmedia: mindgeek,
|
||||
milfvr: wankzvr,
|
||||
mofos: mindgeek,
|
||||
mugfucked: fullpornnetwork,
|
||||
naughtyamerica,
|
||||
@@ -248,6 +251,7 @@ const scrapers = {
|
||||
topwebmodels,
|
||||
transangels: mindgeek,
|
||||
transbella: porndoe,
|
||||
tranzvr: wankzvr,
|
||||
trueanal: mikeadriano,
|
||||
tushy: vixen,
|
||||
tushyraw: vixen,
|
||||
@@ -255,6 +259,7 @@ const scrapers = {
|
||||
vipsexvault: porndoe,
|
||||
vixen,
|
||||
vrcosplayx: badoink,
|
||||
wankzvr,
|
||||
wicked: gamma,
|
||||
wildoncam: cherrypimps,
|
||||
xempire,
|
||||
|
||||
177
src/scrapers/wankzvr.js
Normal file
177
src/scrapers/wankzvr.js
Normal file
@@ -0,0 +1,177 @@
|
||||
'use strict';
|
||||
|
||||
const qu = require('../utils/qu');
|
||||
const http = require('../utils/http');
|
||||
const slugify = require('../utils/slugify');
|
||||
|
||||
async function getTrailerUrl(release, channel, request) {
|
||||
const csrfToken = request.cookie.match('csrfst=(.*?);')?.[1];
|
||||
|
||||
if (!csrfToken) {
|
||||
return null;
|
||||
}
|
||||
|
||||
const res = await http.post(`${channel.url}/ajax/player-config.json`, {
|
||||
item_id: release.entryId,
|
||||
}, {
|
||||
headers: {
|
||||
'X-CSRF-Token': csrfToken,
|
||||
},
|
||||
session: request.session,
|
||||
encodeJSON: false,
|
||||
});
|
||||
|
||||
if (res.ok) {
|
||||
const trailers = res.body.streams.map(trailer => ({
|
||||
src: trailer.url,
|
||||
quality: Number(trailer.id?.match(/\d+/)?.[0] || trailer?.name.match(/\d+/)?.[0]),
|
||||
vr: true,
|
||||
}));
|
||||
|
||||
return {
|
||||
trailers,
|
||||
poster: qu.prefixUrl(res.body.poster, res.body.thumbCDN),
|
||||
};
|
||||
}
|
||||
|
||||
return null;
|
||||
}
|
||||
|
||||
function scrapeAll(scenes, channel) {
|
||||
return scenes.map(({ query }) => {
|
||||
const release = {};
|
||||
|
||||
release.url = query.url('a', 'href', { origin: channel.url });
|
||||
release.entryId = new URL(release.url).pathname.match(/(\d+)\/?$/)?.[1];
|
||||
|
||||
release.title = query.cnt('.card__h');
|
||||
release.date = query.date('.card__date', 'D MMMM, YYYY');
|
||||
|
||||
release.actors = query.all('.card__links a').map(el => ({
|
||||
name: qu.query.cnt(el),
|
||||
url: qu.query.url(el, null, 'href', { origin: channel.url }),
|
||||
}));
|
||||
|
||||
const poster = query.srcset('picture source[type="image/jpeg"]', 'data-srcset')
|
||||
|| query.srcset('picture source[type="image/jpeg"]', 'srcset')
|
||||
|| query.srcset('.video__cover', 'srcset');
|
||||
|
||||
if (poster?.[0]) {
|
||||
release.poster = [
|
||||
poster[0].replace(/small|tiny/, 'large'),
|
||||
...poster,
|
||||
];
|
||||
|
||||
release.teaser = poster[0].replace(/\b(cover|hero|\d+)\/[a-z0-9_]+\.[a-z]+$/i, 'roll.webm'); // actually how site generates teaser URL
|
||||
}
|
||||
|
||||
release.channel = channel.slug; // avoid being assigned to WankzVR network
|
||||
|
||||
return release;
|
||||
});
|
||||
}
|
||||
|
||||
async function scrapeScene({ query }, url, channel, baseRelease, options, request) {
|
||||
const release = {};
|
||||
|
||||
release.entryId = new URL(url).pathname.match(/(\d+)\/?$/)?.[1];
|
||||
|
||||
release.title = query.cnt('.detail__title');
|
||||
release.description = query.cnt('.detail__txt');
|
||||
|
||||
release.date = query.date('.detail__date', 'D MMMM, YYYY');
|
||||
release.duration = query.number('.time') * 60;
|
||||
|
||||
release.actors = (query.all('.detail__header-lg .detail__models a') || query.all('.detail__header-sm .detail__models a')).map(el => ({
|
||||
name: qu.query.cnt(el),
|
||||
url: qu.query.url(el, null, 'href', { origin: channel.url }),
|
||||
}));
|
||||
|
||||
release.tags = query.cnts('.tag-list .tag').concat(query.cnts('.detail__specs-list .detail__specs-item'));
|
||||
|
||||
release.photos = query.all('.photo-strip__slide').map(el => ([
|
||||
qu.query.img(el, null, 'data-src'),
|
||||
qu.query.img(el, 'img', 'src'),
|
||||
]));
|
||||
|
||||
if (options.includePosters || options.includeTrailers) {
|
||||
const { trailers, poster } = await getTrailerUrl(release, channel, request);
|
||||
|
||||
release.trailer = trailers;
|
||||
release.poster = poster;
|
||||
}
|
||||
|
||||
return release;
|
||||
}
|
||||
|
||||
async function fetchActorScenes({ query }, url, entity, page = 1, accScenes = []) {
|
||||
const scenes = scrapeAll(qu.initAll(query.all('.cards-list .card')), entity);
|
||||
const hasNextPage = !query.exists('.pagenav__link.inactive');
|
||||
|
||||
if (hasNextPage) {
|
||||
const { origin, pathname, searchParams } = new URL(url);
|
||||
searchParams.set('p', page + 1);
|
||||
|
||||
const res = await qu.get(`${origin}${pathname}?${searchParams}`);
|
||||
|
||||
if (res.ok) {
|
||||
return fetchActorScenes(res.item, url, entity, page + 1, accScenes.concat(scenes));
|
||||
}
|
||||
}
|
||||
|
||||
return accScenes.concat(scenes);
|
||||
}
|
||||
|
||||
async function scrapeProfile({ query }, url, entity, options) {
|
||||
const profile = {};
|
||||
|
||||
const bio = query.all('.person__meta__item').reduce((acc, el) => ({
|
||||
...acc,
|
||||
[slugify(qu.query.cnt(el, '.person__meta__label'))]: qu.query.text(el),
|
||||
}), {});
|
||||
|
||||
profile.description = query.cnt('.person__content');
|
||||
|
||||
profile.gender = entity.slug === 'tranzvr' ? 'transsexual' : 'female';
|
||||
profile.age = bio.age;
|
||||
|
||||
profile.birthPlace = bio.birthplace;
|
||||
|
||||
profile.height = parseInt(bio.height, 10);
|
||||
profile.measurements = bio.measurements;
|
||||
|
||||
profile.avatar = query.srcset('.person__avatar img');
|
||||
|
||||
if (options.includeActorScenes) {
|
||||
profile.scenes = await fetchActorScenes({ query }, url, entity);
|
||||
}
|
||||
|
||||
return profile;
|
||||
}
|
||||
|
||||
async function fetchLatest(channel, page) {
|
||||
const res = await qu.getAll(`${channel.url}/videos?o=d&p=${page}`, '.cards-list .card');
|
||||
|
||||
if (res.ok) {
|
||||
return scrapeAll(res.items, channel);
|
||||
}
|
||||
|
||||
return res.status;
|
||||
}
|
||||
|
||||
async function fetchProfile(baseActor, { entity }, options) {
|
||||
const url = `${entity.url}/${baseActor.slug}`;
|
||||
const res = await qu.get(url);
|
||||
|
||||
if (res.ok) {
|
||||
return scrapeProfile(res.item, url, entity, options);
|
||||
}
|
||||
|
||||
return res.status;
|
||||
}
|
||||
|
||||
module.exports = {
|
||||
fetchLatest,
|
||||
scrapeScene,
|
||||
fetchProfile,
|
||||
};
|
||||
Reference in New Issue
Block a user