diff --git a/config/default.js b/config/default.js
index 94f527e1..da913c15 100644
--- a/config/default.js
+++ b/config/default.js
@@ -171,6 +171,9 @@ module.exports = {
'pervertgallery',
'povperverts',
],
+ 'wankzvr',
+ 'milfvr',
+ 'tranzvr',
'topwebmodels',
'pascalssubsluts',
'kellymadison',
@@ -252,7 +255,7 @@ module.exports = {
thumbnailQuality: 100,
lazySize: 90,
lazyQuality: 90,
- trailerQuality: [480, 720, 360, 1080, 320, 540, 2160, 270, 240, 180],
+ trailerQuality: [480, 540, 360, 720, 1080, 320, 1440, 1600, 1920, 2160, 270, 240, 180],
limit: 25, // max number of photos per release
streamConcurrency: 2, // max number of video streams (m3u8 etc.) to fetch and process at once
},
diff --git a/migrations/20190325001339_releases.js b/migrations/20190325001339_releases.js
index e03d367a..55eb57ae 100644
--- a/migrations/20190325001339_releases.js
+++ b/migrations/20190325001339_releases.js
@@ -34,6 +34,7 @@ exports.up = knex => Promise.resolve()
table.integer('quality', 6);
table.integer('width', 6);
table.integer('height', 6);
+ table.boolean('vr');
table.float('entropy');
table.float('sharpness');
diff --git a/public/img/logos/wankzvr/favicon.png b/public/img/logos/wankzvr/favicon.png
new file mode 100644
index 00000000..4516ea47
Binary files /dev/null and b/public/img/logos/wankzvr/favicon.png differ
diff --git a/public/img/logos/wankzvr/favicon_dark.png b/public/img/logos/wankzvr/favicon_dark.png
new file mode 100644
index 00000000..93b58d0b
Binary files /dev/null and b/public/img/logos/wankzvr/favicon_dark.png differ
diff --git a/public/img/logos/wankzvr/favicon_light.png b/public/img/logos/wankzvr/favicon_light.png
new file mode 100644
index 00000000..bd1a599a
Binary files /dev/null and b/public/img/logos/wankzvr/favicon_light.png differ
diff --git a/public/img/logos/wankzvr/lazy/favicon.png b/public/img/logos/wankzvr/lazy/favicon.png
new file mode 100644
index 00000000..3289c969
Binary files /dev/null and b/public/img/logos/wankzvr/lazy/favicon.png differ
diff --git a/public/img/logos/wankzvr/lazy/favicon_dark.png b/public/img/logos/wankzvr/lazy/favicon_dark.png
new file mode 100644
index 00000000..2221caae
Binary files /dev/null and b/public/img/logos/wankzvr/lazy/favicon_dark.png differ
diff --git a/public/img/logos/wankzvr/lazy/favicon_light.png b/public/img/logos/wankzvr/lazy/favicon_light.png
new file mode 100644
index 00000000..409a1577
Binary files /dev/null and b/public/img/logos/wankzvr/lazy/favicon_light.png differ
diff --git a/public/img/logos/wankzvr/lazy/milfvr.png b/public/img/logos/wankzvr/lazy/milfvr.png
new file mode 100644
index 00000000..691f1fd5
Binary files /dev/null and b/public/img/logos/wankzvr/lazy/milfvr.png differ
diff --git a/public/img/logos/wankzvr/lazy/network.png b/public/img/logos/wankzvr/lazy/network.png
new file mode 100644
index 00000000..ade9b4ff
Binary files /dev/null and b/public/img/logos/wankzvr/lazy/network.png differ
diff --git a/public/img/logos/wankzvr/lazy/transvr.png b/public/img/logos/wankzvr/lazy/transvr.png
new file mode 100644
index 00000000..d3747aef
Binary files /dev/null and b/public/img/logos/wankzvr/lazy/transvr.png differ
diff --git a/public/img/logos/wankzvr/lazy/tranzvr.png b/public/img/logos/wankzvr/lazy/tranzvr.png
new file mode 100644
index 00000000..c2664670
Binary files /dev/null and b/public/img/logos/wankzvr/lazy/tranzvr.png differ
diff --git a/public/img/logos/wankzvr/lazy/wankzvr.png b/public/img/logos/wankzvr/lazy/wankzvr.png
new file mode 100644
index 00000000..d1f701bc
Binary files /dev/null and b/public/img/logos/wankzvr/lazy/wankzvr.png differ
diff --git a/public/img/logos/wankzvr/milfvr.png b/public/img/logos/wankzvr/milfvr.png
new file mode 100644
index 00000000..6739b230
Binary files /dev/null and b/public/img/logos/wankzvr/milfvr.png differ
diff --git a/public/img/logos/wankzvr/misc/milf-vr.svg b/public/img/logos/wankzvr/misc/milf-vr.svg
new file mode 100644
index 00000000..95ded5c1
--- /dev/null
+++ b/public/img/logos/wankzvr/misc/milf-vr.svg
@@ -0,0 +1 @@
+
diff --git a/public/img/logos/wankzvr/misc/milf-vr_dark.png b/public/img/logos/wankzvr/misc/milf-vr_dark.png
new file mode 100644
index 00000000..15adac96
Binary files /dev/null and b/public/img/logos/wankzvr/misc/milf-vr_dark.png differ
diff --git a/public/img/logos/wankzvr/misc/milf-vr_light.png b/public/img/logos/wankzvr/misc/milf-vr_light.png
new file mode 100644
index 00000000..75f499d2
Binary files /dev/null and b/public/img/logos/wankzvr/misc/milf-vr_light.png differ
diff --git a/public/img/logos/wankzvr/misc/tranz-vr.svg b/public/img/logos/wankzvr/misc/tranz-vr.svg
new file mode 100644
index 00000000..cdfc547f
--- /dev/null
+++ b/public/img/logos/wankzvr/misc/tranz-vr.svg
@@ -0,0 +1 @@
+
diff --git a/public/img/logos/wankzvr/misc/wankz-vr.svg b/public/img/logos/wankzvr/misc/wankz-vr.svg
new file mode 100644
index 00000000..2cd9a9ef
--- /dev/null
+++ b/public/img/logos/wankzvr/misc/wankz-vr.svg
@@ -0,0 +1 @@
+
diff --git a/public/img/logos/wankzvr/network.png b/public/img/logos/wankzvr/network.png
new file mode 100644
index 00000000..f49489a8
Binary files /dev/null and b/public/img/logos/wankzvr/network.png differ
diff --git a/public/img/logos/wankzvr/thumbs/favicon.png b/public/img/logos/wankzvr/thumbs/favicon.png
new file mode 100644
index 00000000..3289c969
Binary files /dev/null and b/public/img/logos/wankzvr/thumbs/favicon.png differ
diff --git a/public/img/logos/wankzvr/thumbs/favicon_dark.png b/public/img/logos/wankzvr/thumbs/favicon_dark.png
new file mode 100644
index 00000000..2221caae
Binary files /dev/null and b/public/img/logos/wankzvr/thumbs/favicon_dark.png differ
diff --git a/public/img/logos/wankzvr/thumbs/favicon_light.png b/public/img/logos/wankzvr/thumbs/favicon_light.png
new file mode 100644
index 00000000..409a1577
Binary files /dev/null and b/public/img/logos/wankzvr/thumbs/favicon_light.png differ
diff --git a/public/img/logos/wankzvr/thumbs/milfvr.png b/public/img/logos/wankzvr/thumbs/milfvr.png
new file mode 100644
index 00000000..f4258595
Binary files /dev/null and b/public/img/logos/wankzvr/thumbs/milfvr.png differ
diff --git a/public/img/logos/wankzvr/thumbs/network.png b/public/img/logos/wankzvr/thumbs/network.png
new file mode 100644
index 00000000..dae50b90
Binary files /dev/null and b/public/img/logos/wankzvr/thumbs/network.png differ
diff --git a/public/img/logos/wankzvr/thumbs/transvr.png b/public/img/logos/wankzvr/thumbs/transvr.png
new file mode 100644
index 00000000..bdd661c4
Binary files /dev/null and b/public/img/logos/wankzvr/thumbs/transvr.png differ
diff --git a/public/img/logos/wankzvr/thumbs/tranzvr.png b/public/img/logos/wankzvr/thumbs/tranzvr.png
new file mode 100644
index 00000000..31e4fa20
Binary files /dev/null and b/public/img/logos/wankzvr/thumbs/tranzvr.png differ
diff --git a/public/img/logos/wankzvr/thumbs/wankzvr.png b/public/img/logos/wankzvr/thumbs/wankzvr.png
new file mode 100644
index 00000000..9a79d1dd
Binary files /dev/null and b/public/img/logos/wankzvr/thumbs/wankzvr.png differ
diff --git a/public/img/logos/wankzvr/tranzvr.png b/public/img/logos/wankzvr/tranzvr.png
new file mode 100644
index 00000000..c481ea36
Binary files /dev/null and b/public/img/logos/wankzvr/tranzvr.png differ
diff --git a/public/img/logos/wankzvr/wankzvr.png b/public/img/logos/wankzvr/wankzvr.png
new file mode 100644
index 00000000..76b3b6f4
Binary files /dev/null and b/public/img/logos/wankzvr/wankzvr.png differ
diff --git a/seeds/00_tags.js b/seeds/00_tags.js
index 9649362a..8dad2d8f 100644
--- a/seeds/00_tags.js
+++ b/seeds/00_tags.js
@@ -57,6 +57,14 @@ const groups = [
];
const tags = [
+ {
+ name: '180°',
+ slug: '180',
+ },
+ {
+ name: '60 FPS',
+ slug: '60fps',
+ },
{
name: '3D',
slug: '3d',
@@ -72,6 +80,16 @@ const tags = [
slug: '5k',
description: 'Available in very high quality 5K resolution.',
},
+ {
+ name: '7K',
+ slug: '7k',
+ description: 'Available in super high quality 7K resolution.',
+ },
+ {
+ name: '8K',
+ slug: '8k',
+ description: 'Available in extremely high quality 8K resolution.',
+ },
{
name: '69',
slug: '69',
diff --git a/seeds/01_networks.js b/seeds/01_networks.js
index 02bcd42a..07ae1015 100644
--- a/seeds/01_networks.js
+++ b/seeds/01_networks.js
@@ -543,6 +543,11 @@ const networks = [
url: 'https://www.vixen.com',
description: 'Vixen.com features the world’s finest cinematic adult films with 4K quality and high-end erotic photography.',
},
+ {
+ slug: 'wankzvr',
+ name: 'WankzVR',
+ url: 'https://www.wankzvr.com',
+ },
{
slug: 'pierrewoodman',
name: 'Pierre Woodman',
diff --git a/seeds/02_sites.js b/seeds/02_sites.js
index 0e7f719b..81031a78 100644
--- a/seeds/02_sites.js
+++ b/seeds/02_sites.js
@@ -9365,6 +9365,28 @@ const sites = [
url: 'https://www.vogov.com',
description: 'Top rated models. Graceful locations. Best gonzo scenes. 4K UHD 60 FPS. So, in general Vogov is a website that is worth visiting and exploring carefully. It gives a chance to spend a fantastic night with gorgeous girls ready to experiment and to full around with their lovers.',
},
+ // WANKZ VR
+ {
+ name: 'WankzVR',
+ slug: 'wankzvr',
+ url: 'https://www.wankzvr.com',
+ tags: ['vr'],
+ parent: 'wankzvr',
+ },
+ {
+ name: 'MilfVR',
+ slug: 'milfvr',
+ url: 'https://www.milfvr.com',
+ tags: ['vr', 'milf'],
+ parent: 'wankzvr',
+ },
+ {
+ name: 'TranzVR',
+ slug: 'tranzvr',
+ url: 'https://www.tranzvr.com',
+ tags: ['vr', 'transsexual'],
+ parent: 'wankzvr',
+ },
// WHALE MEMBER
{
name: 'Cum 4K',
diff --git a/src/deep.js b/src/deep.js
index 30ec19bc..bdfca6d1 100644
--- a/src/deep.js
+++ b/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;
diff --git a/src/media.js b/src/media.js
index 36ff092e..ca122211 100644
--- a/src/media.js
+++ b/src/media.js
@@ -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,
diff --git a/src/scrapers/scrapers.js b/src/scrapers/scrapers.js
index 41f708ce..4cd518b1 100644
--- a/src/scrapers/scrapers.js
+++ b/src/scrapers/scrapers.js
@@ -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,
diff --git a/src/scrapers/wankzvr.js b/src/scrapers/wankzvr.js
new file mode 100644
index 00000000..6f541dcf
--- /dev/null
+++ b/src/scrapers/wankzvr.js
@@ -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,
+};