Added Brad Montana. Added teaser link to trailer video.
|
@ -38,6 +38,20 @@
|
|||
class="item trailer"
|
||||
>
|
||||
|
||||
<span
|
||||
v-if="release.poster || release.teaser"
|
||||
class="poster-links"
|
||||
>
|
||||
<a
|
||||
v-if="release.teaser"
|
||||
v-tooltip="'View teaser'"
|
||||
:href="getPath(release.teaser)"
|
||||
:class="{ playing }"
|
||||
target="_blank"
|
||||
rel="noopener noreferrer"
|
||||
class="poster-link"
|
||||
><Icon icon="film4" /></a>
|
||||
|
||||
<a
|
||||
v-if="release.poster"
|
||||
v-tooltip="'View poster'"
|
||||
|
@ -47,6 +61,7 @@
|
|||
rel="noopener noreferrer"
|
||||
class="poster-link"
|
||||
><Icon icon="image" /></a>
|
||||
</span>
|
||||
|
||||
<span
|
||||
v-if="sfw && !playing"
|
||||
|
@ -217,11 +232,16 @@ export default {
|
|||
margin: 0 auto;
|
||||
}
|
||||
|
||||
.poster-link {
|
||||
.poster-links {
|
||||
display: flex;
|
||||
position: absolute;
|
||||
top: .5rem;
|
||||
right: .5rem;
|
||||
top: 0;
|
||||
right: 0;
|
||||
}
|
||||
|
||||
.poster-link {
|
||||
transition: opacity .1s ease;
|
||||
padding: .5rem;
|
||||
|
||||
.icon {
|
||||
width: 1.5rem;
|
||||
|
@ -234,6 +254,14 @@ export default {
|
|||
opacity: 0;
|
||||
}
|
||||
|
||||
&:first-child {
|
||||
padding-left: .75rem;
|
||||
}
|
||||
|
||||
&:last-child {
|
||||
padding-right: .75rem;
|
||||
}
|
||||
|
||||
&:hover {
|
||||
cursor: pointer;
|
||||
opacity: 1;
|
||||
|
|
|
@ -121,6 +121,7 @@ const tagSlugsByCategory = {
|
|||
'bdsm',
|
||||
'femdom',
|
||||
'bondage',
|
||||
'free-use',
|
||||
'latex',
|
||||
'blindfold',
|
||||
],
|
||||
|
|
|
@ -0,0 +1,5 @@
|
|||
<!-- Generated by IcoMoon.io -->
|
||||
<svg version="1.1" xmlns="http://www.w3.org/2000/svg" width="16" height="16" viewBox="0 0 16 16">
|
||||
<title>film4</title>
|
||||
<path d="M0 2v12h16v-12h-16zM3 13h-2v-2h2v2zM3 9h-2v-2h2v2zM3 5h-2v-2h2v2zM12 13h-8v-10h8v10zM15 13h-2v-2h2v2zM15 9h-2v-2h2v2zM15 5h-2v-2h2v2zM6 5v6l4-3z"></path>
|
||||
</svg>
|
After Width: | Height: | Size: 322 B |
|
@ -0,0 +1,5 @@
|
|||
<!-- Generated by IcoMoon.io -->
|
||||
<svg version="1.1" xmlns="http://www.w3.org/2000/svg" width="16" height="16" viewBox="0 0 16 16">
|
||||
<title>presentation</title>
|
||||
<path d="M14.25 0h-13.5c-0.412 0-0.75 0.338-0.75 0.75v11.5c0 0.412 0.338 0.75 0.75 0.75h4.455l-2.040 2.040c-0.22 0.22-0.22 0.576 0 0.795 0.11 0.11 0.254 0.165 0.398 0.165s0.288-0.055 0.398-0.165l2.835-2.835h0.205v2.5c0 0.276 0.224 0.5 0.5 0.5s0.5-0.224 0.5-0.5v-2.5h0.205l2.835 2.835c0.11 0.11 0.254 0.165 0.398 0.165s0.288-0.055 0.398-0.165c0.22-0.22 0.22-0.576 0-0.795l-2.040-2.040h4.455c0.412 0 0.75-0.338 0.75-0.75v-11.5c0-0.412-0.338-0.75-0.75-0.75zM6 3l4 2.5-4 2.5v-5zM12.5 11h-10c-0.276 0-0.5-0.224-0.5-0.5s0.224-0.5 0.5-0.5h10c0.276 0 0.5 0.224 0.5 0.5s-0.224 0.5-0.5 0.5z"></path>
|
||||
</svg>
|
After Width: | Height: | Size: 756 B |
After Width: | Height: | Size: 8.8 KiB |
After Width: | Height: | Size: 1.1 KiB |
After Width: | Height: | Size: 1.1 KiB |
After Width: | Height: | Size: 1.1 KiB |
After Width: | Height: | Size: 2.6 KiB |
After Width: | Height: | Size: 2.6 KiB |
After Width: | Height: | Size: 8.8 KiB |
After Width: | Height: | Size: 5.9 KiB |
After Width: | Height: | Size: 5.9 KiB |
After Width: | Height: | Size: 825 KiB |
After Width: | Height: | Size: 10 KiB |
After Width: | Height: | Size: 7.7 KiB |
After Width: | Height: | Size: 49 KiB |
After Width: | Height: | Size: 34 KiB |
After Width: | Height: | Size: 846 KiB |
|
@ -511,6 +511,11 @@ const tags = [
|
|||
name: 'flexible',
|
||||
slug: 'flexible',
|
||||
},
|
||||
{
|
||||
name: 'free use',
|
||||
slug: 'free-use',
|
||||
description: 'The fantasy of giving universal consent, and making yourself available for any sexual activity, anywhere, anytime. As long as you are accommodating, you may continue what you were doing and pay no attention to how you\'re being used, and generally no one around you thinks considers it out of the ordinary.',
|
||||
},
|
||||
{
|
||||
name: 'MFF threesome',
|
||||
slug: 'mff',
|
||||
|
@ -1628,6 +1633,10 @@ const aliases = [
|
|||
name: 'foot fetish',
|
||||
for: 'feet',
|
||||
},
|
||||
{
|
||||
name: 'freeuse',
|
||||
for: 'free-use',
|
||||
},
|
||||
{
|
||||
name: 'french kissing',
|
||||
for: 'kissing',
|
||||
|
|
|
@ -1524,6 +1524,12 @@ const sites = [
|
|||
description: '',
|
||||
parent: 'blowpass',
|
||||
},
|
||||
// BRAD MONTANA
|
||||
{
|
||||
slug: 'bradmontana',
|
||||
name: 'Brad Montana',
|
||||
url: 'https://www.bradmontana.com',
|
||||
},
|
||||
// BRAZZERS
|
||||
{
|
||||
slug: 'momsincontrol',
|
||||
|
|
|
@ -809,26 +809,6 @@ const tagMedia = [
|
|||
['dv-tp', 'veronica_avluv_brazzers', 'Veronica Avluv in "The Secret Soiree: Six-Man Gang Bang"', 'brazzers'],
|
||||
['dv-tp', 1, 'Adriana Chechik in "Adriana\'s Triple Anal Penetration!"'],
|
||||
['dv-tp', 0, 'Luna Rival in SZ1490'],
|
||||
['facefucking', 5, 'Mia Moore B', 'throated'],
|
||||
['facefucking', 'paige_owens_julesjordan', 'Paige Owens in "Butt Slut In Anal Training"', 'julesjordan'],
|
||||
['facefucking', 'adria_rae_throated', 'Adria Rae in "Adria Rae Sucks Cock All Day"', 'throated'],
|
||||
['facefucking', 6, 'Halle Hayes in "Towering Temptress"', '5kporn'],
|
||||
['facefucking', 'cathy_heaven_roccosiffredi', 'Cathy Heaven', 'roccosiffredi'],
|
||||
['facefucking', 2, 'Jynx Maze', 'throated'],
|
||||
['facefucking', 7, 'Anya Olsen and Audrey Snow in "Babysitter Busted Giving A BJ"', 'mommyblowsbest'],
|
||||
['facefucking', 0, 'Ashly Anderson in "Rough Love"', 'hookuphotshot'],
|
||||
['facefucking', 4, 'Brooklyn Gray in "Throats Fucks 6"', 'evilangel'],
|
||||
['facefucking', 3, 'Adriana Chechik in "Performing Magic Butt Tricks With Jules Jordan. What Will Disappear In Her Ass?"', 'julesjordan'],
|
||||
['facial', 0, 'Brooklyn Gray in "All About Ass 4"', 'evilangel'],
|
||||
['facial', 'amy_anderssen_julesjordan_1', 'Amy Anderssen in "Lex The Impaler 8"', 'julesjordan'],
|
||||
['facial', 3, 'Paige Owens in "Oral Restraint"', 'babes'],
|
||||
['facial', 'mia_malkova_manojob_2', 'Mia Malkova in "Covered!"', 'manojob'],
|
||||
['facial', 'alicia_williams_holed', 'Alicia Wiliams in "Bath and Anal"', 'holed'],
|
||||
['facial', 'poster', 'Jynx Maze in "Gag Reflex 3"', 'evilangel'],
|
||||
['facial', 'hope_howell_manojob', 'Hope Howell in "Super Slutty Step-Daugher"', 'manojob'],
|
||||
['facial', 2, 'Ashly Anderson', 'hookuphotshot'],
|
||||
['facial', 4, 'Kendra Heart', 'facialsforever'],
|
||||
['flexible', 'lara_frost_legalporno', 'Lara Frost in NRX059', 'legalporno'],
|
||||
['electric-shock', 'tia_ling_electrosluts', 'Tia Ling', 'electrosluts'],
|
||||
['enhanced-boobs', 7, 'Charley Atwell', 'icandigirls'],
|
||||
['enhanced-boobs', 14, 'Rikki Six', 'dreamdolls'],
|
||||
|
@ -877,6 +857,25 @@ const tagMedia = [
|
|||
['enhanced-boobs', 19, 'Kerrie Lee in "Bricked"', 'studio66tv'],
|
||||
['enhanced-boobs', 4, 'Capri Cavanni', 'bigtitsinsports'],
|
||||
['enhanced-butt', '0a', 'Aletta Ocean in "Jerk Off Instructions"', 'alettaoceanlive'],
|
||||
['facefucking', 5, 'Mia Moore B', 'throated'],
|
||||
['facefucking', 'paige_owens_julesjordan', 'Paige Owens in "Butt Slut In Anal Training"', 'julesjordan'],
|
||||
['facefucking', 'adria_rae_throated', 'Adria Rae in "Adria Rae Sucks Cock All Day"', 'throated'],
|
||||
['facefucking', 6, 'Halle Hayes in "Towering Temptress"', '5kporn'],
|
||||
['facefucking', 'cathy_heaven_roccosiffredi', 'Cathy Heaven', 'roccosiffredi'],
|
||||
['facefucking', 2, 'Jynx Maze', 'throated'],
|
||||
['facefucking', 7, 'Anya Olsen and Audrey Snow in "Babysitter Busted Giving A BJ"', 'mommyblowsbest'],
|
||||
['facefucking', 0, 'Ashly Anderson in "Rough Love"', 'hookuphotshot'],
|
||||
['facefucking', 4, 'Brooklyn Gray in "Throats Fucks 6"', 'evilangel'],
|
||||
['facefucking', 3, 'Adriana Chechik in "Performing Magic Butt Tricks With Jules Jordan. What Will Disappear In Her Ass?"', 'julesjordan'],
|
||||
['facial', 0, 'Brooklyn Gray in "All About Ass 4"', 'evilangel'],
|
||||
['facial', 'amy_anderssen_julesjordan_1', 'Amy Anderssen in "Lex The Impaler 8"', 'julesjordan'],
|
||||
['facial', 3, 'Paige Owens in "Oral Restraint"', 'babes'],
|
||||
['facial', 'mia_malkova_manojob_2', 'Mia Malkova in "Covered!"', 'manojob'],
|
||||
['facial', 'alicia_williams_holed', 'Alicia Wiliams in "Bath and Anal"', 'holed'],
|
||||
['facial', 'poster', 'Jynx Maze in "Gag Reflex 3"', 'evilangel'],
|
||||
['facial', 'hope_howell_manojob', 'Hope Howell in "Super Slutty Step-Daugher"', 'manojob'],
|
||||
['facial', 2, 'Ashly Anderson', 'hookuphotshot'],
|
||||
['facial', 4, 'Kendra Heart', 'facialsforever'],
|
||||
['fake-cum', 2, 'Mimi Allen', 'fuckedupfacials'],
|
||||
['fake-cum', 3, 'Alexia Anders in "Thanksgiving Creampies"', 'cum4k'],
|
||||
['fake-cum', 0, 'Jynx Maze in "Showering Slut Gets Sludged"', 'cumshotsurprise'],
|
||||
|
@ -892,6 +891,9 @@ const tagMedia = [
|
|||
['fisting', '1a', 'Aletta Ocean in "Solo Fisting"', '21sextury'],
|
||||
['fisting', 0, 'Abella Danger and Karma Rx in "Neon Dreaming"', 'brazzers'],
|
||||
['fisting-dp', 0, 'Janice Griffith and Veronica Avluv in "The Nymphomaniac\'s Apprentice', 'theupperfloor'],
|
||||
['flexible', 'lara_frost_legalporno', 'Lara Frost in NRX059', 'legalporno'],
|
||||
['free-use', 'jeni_angel_brazzersexxtra', 'Jeni Angel in "Gamer Girl Threesome Action"', 'brazzersexxtra'],
|
||||
['free-use', 'veruca_james_brazzersexxtra', 'Veruca James in "The Perfect Maid"', 'brazzersexxtra'],
|
||||
['gangbang', 5, 'Carter Cruise\'s first gangbang in "Slut Puppies 9"', 'julesjordan'],
|
||||
['gangbang', 'kristen_scott_julesjordan', 'Kristen Scott in "Interracial Gangbang!"', 'julesjordan'],
|
||||
['gangbang', 'monika_fox_legalporno', 'Monika Fox in GL479', 'legalporno'],
|
||||
|
|
|
@ -0,0 +1,149 @@
|
|||
'use strict';
|
||||
|
||||
const qu = require('../utils/q');
|
||||
const slugify = require('../utils/slugify');
|
||||
|
||||
function genderFromUrl(url) {
|
||||
const { pathname } = new URL(url);
|
||||
|
||||
if (/atores/.test(pathname)) {
|
||||
return 'male';
|
||||
}
|
||||
|
||||
if (/atrizes/.test(pathname)) {
|
||||
return 'female';
|
||||
}
|
||||
|
||||
return null;
|
||||
}
|
||||
|
||||
function scrapeAll(scenes) {
|
||||
return scenes.map(({ query }) => {
|
||||
const release = {};
|
||||
const subtitle = query.cnt('.subtitle');
|
||||
|
||||
release.url = query.url('a');
|
||||
release.entryId = new URL(release.url).pathname.match(/\/videos\/([\w-]+)/)[1];
|
||||
|
||||
release.title = query.cnt('.title') || query.q('img', 'title');
|
||||
release.actors = subtitle.slice(subtitle.indexOf(':') + 1).split(',').map(actor => actor.trim()).filter(Boolean);
|
||||
|
||||
release.poster = query.img('.thumb img');
|
||||
|
||||
if (release.poster) {
|
||||
const match = release.poster.match(/\/uploads\/(\d{4})\/(\d{2})/);
|
||||
|
||||
if (match) {
|
||||
release.date = new Date(match[1], match[2] - 1, 1);
|
||||
release.datePrecision = 'month';
|
||||
}
|
||||
}
|
||||
|
||||
return release;
|
||||
});
|
||||
}
|
||||
|
||||
function scrapeScene({ query, html }, url, channel) {
|
||||
const release = {};
|
||||
|
||||
const dataString = query.html('.yoast-schema-graph');
|
||||
const data = dataString && JSON.parse(dataString)['@graph'];
|
||||
const pageData = data.find(item => item['@type'] === 'WebPage');
|
||||
const imageData = data.find(item => item['@type'] === 'ImageObject');
|
||||
|
||||
release.entryId = new URL(url).pathname.match(/\/videos\/([\w-]+)/)[1];
|
||||
|
||||
release.title = query.cnt('.video .title h1')
|
||||
|| data.find(item => item['@type'] === 'BreadcrumbList')?.itemListElement.slice(-1)[0].item.name
|
||||
|| pageData?.name.slice(0, pageData.name.lastIndexOf('-')).trim();
|
||||
|
||||
release.description = query.cnt('.video .descript');
|
||||
|
||||
release.date = pageData.datePublished && new Date(pageData.datePublished);
|
||||
|
||||
release.actors = query.all('.video .elenco a').map((el) => {
|
||||
const actorUrl = query.url(el, null);
|
||||
|
||||
return {
|
||||
name: query.cnt(el),
|
||||
url: actorUrl,
|
||||
gender: genderFromUrl(actorUrl),
|
||||
};
|
||||
});
|
||||
|
||||
release.poster = imageData?.url
|
||||
|| query.meta('property="og:image"')
|
||||
|| html.match(/poster: '(http.*\.jpg)'/)?.[1];
|
||||
|
||||
release.photos = query.imgs('.listPostSm a', 'href');
|
||||
release.trailer = query.video('source', 'src', { origin: channel.url });
|
||||
|
||||
release.likes = query.number('.vortex-p-like-counter');
|
||||
release.dislikes = query.number('.vortex-p-dislike-counter');
|
||||
|
||||
if (!release.date && release.poster) {
|
||||
const match = release.poster.match(/\/uploads\/(\d{4})\/(\d{2})/);
|
||||
|
||||
if (match) {
|
||||
release.date = new Date(match[1], match[2] - 1, 1);
|
||||
release.datePrecision = 'month';
|
||||
}
|
||||
}
|
||||
|
||||
return release;
|
||||
}
|
||||
|
||||
function scrapeProfile({ query, el }, entity, url) {
|
||||
const profile = { url };
|
||||
|
||||
profile.gender = genderFromUrl(url);
|
||||
|
||||
profile.description = query.cnt('.about')?.replace(/sobre a atriz:/i, '').trim();
|
||||
profile.avatar = query.img('.left .thumb img');
|
||||
|
||||
profile.scenes = scrapeAll(qu.initAll(el, '.listPostLg .post'));
|
||||
|
||||
return profile;
|
||||
}
|
||||
|
||||
async function fetchLatest(channel, page = 1) {
|
||||
const url = `${channel.url}/videos/page/${page}`;
|
||||
const res = await qu.getAll(url, '.listPostLg .post');
|
||||
|
||||
if (res.ok) {
|
||||
return scrapeAll(res.items, channel);
|
||||
}
|
||||
|
||||
return res.status;
|
||||
}
|
||||
|
||||
async function fetchProfilePage({ name, gender }, entity, secondAttempt) {
|
||||
const url = `${entity.url}/${gender === 'male' || secondAttempt ? 'atores' : 'atrizes'}/${slugify(name, '-')}`;
|
||||
const res = await qu.get(url);
|
||||
|
||||
if (res.ok) {
|
||||
return { res, url };
|
||||
}
|
||||
|
||||
if (secondAttempt) {
|
||||
return res.status;
|
||||
}
|
||||
|
||||
return fetchProfilePage({ name, gender }, entity, true);
|
||||
}
|
||||
|
||||
async function fetchProfile(baseActor, entity, options) {
|
||||
const { res, url } = await fetchProfilePage(baseActor, entity, false);
|
||||
|
||||
if (res.ok) {
|
||||
return scrapeProfile(res.item, entity, url, options);
|
||||
}
|
||||
|
||||
return res.status;
|
||||
}
|
||||
|
||||
module.exports = {
|
||||
fetchLatest,
|
||||
fetchProfile,
|
||||
scrapeScene,
|
||||
};
|
|
@ -11,6 +11,7 @@ const bamvisions = require('./bamvisions');
|
|||
const bang = require('./bang');
|
||||
const bangbros = require('./bangbros');
|
||||
const blowpass = require('./blowpass');
|
||||
const bradmontana = require('./bradmontana');
|
||||
const cherrypimps = require('./cherrypimps');
|
||||
const cumlouder = require('./cumlouder');
|
||||
const czechav = require('./czechav');
|
||||
|
@ -82,6 +83,7 @@ const scrapers = {
|
|||
bang,
|
||||
bangbros,
|
||||
blowpass,
|
||||
bradmontana,
|
||||
brazzers: mindgeek,
|
||||
cherrypimps,
|
||||
cumlouder,
|
||||
|
@ -178,6 +180,7 @@ const scrapers = {
|
|||
blackambush: elevatedx,
|
||||
blowpass,
|
||||
boobpedia,
|
||||
bradmontana,
|
||||
brattysis: nubiles,
|
||||
brazzers: mindgeek,
|
||||
burningangel: gamma,
|
||||
|
|