diff --git a/assets/components/releases/banner.vue b/assets/components/releases/banner.vue
index e507def5..0a18bcb0 100644
--- a/assets/components/releases/banner.vue
+++ b/assets/components/releases/banner.vue
@@ -38,15 +38,30 @@
class="item trailer"
>
-
+
+
+
+
+
+
diff --git a/assets/img/icons/presentation.svg b/assets/img/icons/presentation.svg
new file mode 100644
index 00000000..4c13540a
--- /dev/null
+++ b/assets/img/icons/presentation.svg
@@ -0,0 +1,5 @@
+
+
diff --git a/public/img/logos/bradmontana/bradmontana.png b/public/img/logos/bradmontana/bradmontana.png
new file mode 100644
index 00000000..5759dab8
Binary files /dev/null and b/public/img/logos/bradmontana/bradmontana.png differ
diff --git a/public/img/logos/bradmontana/favicon.png b/public/img/logos/bradmontana/favicon.png
new file mode 100644
index 00000000..1ab3ea51
Binary files /dev/null and b/public/img/logos/bradmontana/favicon.png differ
diff --git a/public/img/logos/bradmontana/favicon_dark.png b/public/img/logos/bradmontana/favicon_dark.png
new file mode 100644
index 00000000..970ea14a
Binary files /dev/null and b/public/img/logos/bradmontana/favicon_dark.png differ
diff --git a/public/img/logos/bradmontana/favicon_light.png b/public/img/logos/bradmontana/favicon_light.png
new file mode 100644
index 00000000..113347a5
Binary files /dev/null and b/public/img/logos/bradmontana/favicon_light.png differ
diff --git a/public/img/logos/bradmontana/lazy/bradmontana.png b/public/img/logos/bradmontana/lazy/bradmontana.png
new file mode 100644
index 00000000..0ed67b9a
Binary files /dev/null and b/public/img/logos/bradmontana/lazy/bradmontana.png differ
diff --git a/public/img/logos/bradmontana/lazy/network.png b/public/img/logos/bradmontana/lazy/network.png
new file mode 100644
index 00000000..836e669f
Binary files /dev/null and b/public/img/logos/bradmontana/lazy/network.png differ
diff --git a/public/img/logos/bradmontana/network.png b/public/img/logos/bradmontana/network.png
new file mode 100644
index 00000000..84de07aa
Binary files /dev/null and b/public/img/logos/bradmontana/network.png differ
diff --git a/public/img/logos/bradmontana/thumbs/bradmontana.png b/public/img/logos/bradmontana/thumbs/bradmontana.png
new file mode 100644
index 00000000..dd57ea5c
Binary files /dev/null and b/public/img/logos/bradmontana/thumbs/bradmontana.png differ
diff --git a/public/img/logos/bradmontana/thumbs/network.png b/public/img/logos/bradmontana/thumbs/network.png
new file mode 100644
index 00000000..342ee3a7
Binary files /dev/null and b/public/img/logos/bradmontana/thumbs/network.png differ
diff --git a/public/img/tags/free-use/jeni_angel_brazzersexxtra.jpeg b/public/img/tags/free-use/jeni_angel_brazzersexxtra.jpeg
new file mode 100644
index 00000000..fcb427b1
Binary files /dev/null and b/public/img/tags/free-use/jeni_angel_brazzersexxtra.jpeg differ
diff --git a/public/img/tags/free-use/lazy/jeni_angel_brazzersexxtra.jpeg b/public/img/tags/free-use/lazy/jeni_angel_brazzersexxtra.jpeg
new file mode 100644
index 00000000..473a141a
Binary files /dev/null and b/public/img/tags/free-use/lazy/jeni_angel_brazzersexxtra.jpeg differ
diff --git a/public/img/tags/free-use/lazy/veruca_james_brazzersexxtra.jpeg b/public/img/tags/free-use/lazy/veruca_james_brazzersexxtra.jpeg
new file mode 100644
index 00000000..ed734a99
Binary files /dev/null and b/public/img/tags/free-use/lazy/veruca_james_brazzersexxtra.jpeg differ
diff --git a/public/img/tags/free-use/thumbs/jeni_angel_brazzersexxtra.jpeg b/public/img/tags/free-use/thumbs/jeni_angel_brazzersexxtra.jpeg
new file mode 100644
index 00000000..358f4eb7
Binary files /dev/null and b/public/img/tags/free-use/thumbs/jeni_angel_brazzersexxtra.jpeg differ
diff --git a/public/img/tags/free-use/thumbs/veruca_james_brazzersexxtra.jpeg b/public/img/tags/free-use/thumbs/veruca_james_brazzersexxtra.jpeg
new file mode 100644
index 00000000..31158795
Binary files /dev/null and b/public/img/tags/free-use/thumbs/veruca_james_brazzersexxtra.jpeg differ
diff --git a/public/img/tags/free-use/veruca_james_brazzersexxtra.jpeg b/public/img/tags/free-use/veruca_james_brazzersexxtra.jpeg
new file mode 100644
index 00000000..e32362bd
Binary files /dev/null and b/public/img/tags/free-use/veruca_james_brazzersexxtra.jpeg differ
diff --git a/seeds/00_tags.js b/seeds/00_tags.js
index f4bd5d59..0729e6d0 100644
--- a/seeds/00_tags.js
+++ b/seeds/00_tags.js
@@ -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',
diff --git a/seeds/02_sites.js b/seeds/02_sites.js
index 35244f2b..e67667bf 100644
--- a/seeds/02_sites.js
+++ b/seeds/02_sites.js
@@ -1524,6 +1524,12 @@ const sites = [
description: '',
parent: 'blowpass',
},
+ // BRAD MONTANA
+ {
+ slug: 'bradmontana',
+ name: 'Brad Montana',
+ url: 'https://www.bradmontana.com',
+ },
// BRAZZERS
{
slug: 'momsincontrol',
diff --git a/seeds/04_media.js b/seeds/04_media.js
index 643ff191..33ff097a 100644
--- a/seeds/04_media.js
+++ b/seeds/04_media.js
@@ -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'],
diff --git a/src/scrapers/bradmontana.js b/src/scrapers/bradmontana.js
new file mode 100644
index 00000000..77f01915
--- /dev/null
+++ b/src/scrapers/bradmontana.js
@@ -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,
+};
diff --git a/src/scrapers/scrapers.js b/src/scrapers/scrapers.js
index 49927899..f80afe28 100644
--- a/src/scrapers/scrapers.js
+++ b/src/scrapers/scrapers.js
@@ -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,