Added basic Pascals Subsluts scraper.
| After Width: | Height: | Size: 1.8 KiB | 
| After Width: | Height: | Size: 2.3 KiB | 
| After Width: | Height: | Size: 2.3 KiB | 
| After Width: | Height: | Size: 12 KiB | 
| After Width: | Height: | Size: 12 KiB | 
| After Width: | Height: | Size: 12 KiB | 
| After Width: | Height: | Size: 12 KiB | 
|  | @ -5399,6 +5399,13 @@ const sites = [ | |||
| 		tags: ['parody'], | ||||
| 		parent: 'nubiles', | ||||
| 	}, | ||||
| 	// PASCALS SUBSLUTS
 | ||||
| 	{ | ||||
| 		slug: 'pascalssubsluts', | ||||
| 		name: 'Pascal\'s Sub Sluts', | ||||
| 		url: 'https://www.pascalssubsluts.com', | ||||
| 		tags: ['rough', 'bdsm'], | ||||
| 	}, | ||||
| 	// PERFECT GONZO
 | ||||
| 	{ | ||||
| 		slug: 'allinternal', | ||||
|  |  | |||
|  | @ -0,0 +1,101 @@ | |||
| 'use strict'; | ||||
| 
 | ||||
| const qu = require('../utils/q'); | ||||
| const capitalize = require('../utils/capitalize'); | ||||
| 
 | ||||
| function scrapeAll(months, channel, year) { | ||||
| 	return months.map(({ query: queryMonth, el }) => { | ||||
| 		const month = queryMonth.cnt('h3'); | ||||
| 		const scenes = queryMonth.all(el.nextElementSibling, 'li:nth-child(2n)'); | ||||
| 
 | ||||
| 		return qu.initAll(scenes).map(({ query }) => { | ||||
| 			const release = {}; | ||||
| 
 | ||||
| 			release.url = query.url('a.video-pop-up', 'href', { origin: `${channel.url}/submissive` }); | ||||
| 			release.entryId = new URL(release.url).searchParams.get('id'); | ||||
| 
 | ||||
| 			release.title = query.cnt('.updates-item-title h4'); | ||||
| 
 | ||||
| 			release.date = qu.parseDate(`${month} ${year}`, 'MMMM/YYYY'); | ||||
| 			release.datePrecision = 'month'; | ||||
| 
 | ||||
| 			release.actors = [{ | ||||
| 				name: capitalize(query.q('a.video-pop-up', 'data-modelname'), { uncapitalize: true }), | ||||
| 				url: query.url('a.video-pop-up', 'data-modellink', { origin: `${channel.url}/submissive` }), | ||||
| 			}]; | ||||
| 
 | ||||
| 			release.poster = query.img('img'); | ||||
| 
 | ||||
| 			return release; | ||||
| 		}); | ||||
| 	}).flat(); | ||||
| } | ||||
| 
 | ||||
| function scrapeScene({ html }, url) { | ||||
| 	const release = {}; | ||||
| 
 | ||||
| 	release.entryId = new URL(url).searchParams.get('id'); | ||||
| 	release.trailer = html.match(/file: '(.*)'/)[1]; | ||||
| 
 | ||||
| 	return release; | ||||
| } | ||||
| 
 | ||||
| /* | ||||
| function scrapeProfile({ query, el }, actorName, entity, include) { | ||||
| 	const profile = {}; | ||||
| 
 | ||||
| 	profile.description = query.cnt('.bio-text'); | ||||
| 	profile.birthPlace = query.cnt('.birth-place span'); | ||||
| 
 | ||||
| 	profile.avatar = query.img('.actor-photo img'); | ||||
| 
 | ||||
| 	if (include.releases) { | ||||
| 		return scrapeAll(qu.initAll(el, '.scene')); | ||||
| 	} | ||||
| 
 | ||||
| 	console.log(profile); | ||||
| 	return profile; | ||||
| } | ||||
| */ | ||||
| 
 | ||||
| async function fetchLatest(channel, page = 1) { | ||||
| 	const year = new Date().getFullYear() - (page - 1); | ||||
| 
 | ||||
| 	const url = `${channel.url}/submissive/updates.php?y=${year}`; | ||||
| 	const res = await qu.getAll(url, '.month'); | ||||
| 
 | ||||
| 	if (res.ok) { | ||||
| 		return scrapeAll(res.items, channel, year); | ||||
| 	} | ||||
| 
 | ||||
| 	return res.status; | ||||
| } | ||||
| 
 | ||||
| async function fetchScene(url, channel) { | ||||
| 	const res = await qu.get(url); | ||||
| 
 | ||||
| 	if (res.ok) { | ||||
| 		return scrapeScene(res.item, url, channel); | ||||
| 	} | ||||
| 
 | ||||
| 	return res.status; | ||||
| } | ||||
| 
 | ||||
| /* | ||||
| async function fetchProfile({ name: actorName }, entity, include) { | ||||
| 	const url = `${entity.url}/actors/${slugify(actorName, '_')}`; | ||||
| 	const res = await qu.get(url); | ||||
| 
 | ||||
| 	if (res.ok) { | ||||
| 		return scrapeProfile(res.item, actorName, entity, include); | ||||
| 	} | ||||
| 
 | ||||
| 	return res.status; | ||||
| } | ||||
| */ | ||||
| 
 | ||||
| module.exports = { | ||||
| 	fetchLatest, | ||||
| 	fetchScene, | ||||
| 	fetchProfile, | ||||
| }; | ||||
|  | @ -53,6 +53,7 @@ const pervcity = require('./pervcity'); | |||
| const porncz = require('./porncz'); | ||||
| const pornhub = require('./pornhub'); | ||||
| const whalemember = require('./whalemember'); | ||||
| const pascalssubsluts = require('./pascalssubsluts'); // reserved keyword
 | ||||
| const privateNetwork = require('./private'); // reserved keyword
 | ||||
| const puretaboo = require('./puretaboo'); | ||||
| const realitykings = require('./realitykings'); | ||||
|  | @ -134,6 +135,7 @@ module.exports = { | |||
| 		naughtyamerica, | ||||
| 		newsensations, | ||||
| 		nubiles, | ||||
| 		pascalssubsluts, | ||||
| 		perfectgonzo, | ||||
| 		pervcity, | ||||
| 		pimpxxx: cherrypimps, | ||||
|  |  | |||
|  | @ -56,6 +56,10 @@ function prefixUrl(urlValue, origin, protocol = 'https') { | |||
| 		return `${origin}${urlValue}`; | ||||
| 	} | ||||
| 
 | ||||
| 	if (origin && /^\.\//.test(urlValue)) { | ||||
| 		return `${origin}${urlValue.slice(1)}`; | ||||
| 	} | ||||
| 
 | ||||
| 	if (origin) { | ||||
| 		return `${origin}/${urlValue}`; | ||||
| 	} | ||||
|  |  | |||