diff --git a/assets/components/networks/network.vue b/assets/components/networks/network.vue index 3b54891d..3e5a91a0 100644 --- a/assets/components/networks/network.vue +++ b/assets/components/networks/network.vue @@ -219,6 +219,17 @@ export default { } } +.networks { + display: grid; + grid-gap: 0 1rem; + flex-grow: 1; + padding: 1rem; + grid-template-columns: 1fr; + grid-template-rows: min-content; + overflow-y: auto; + scrollbar-color: $highlight-weak $profile; +} + .logo { width: 100%; max-height: 8rem; diff --git a/assets/components/releases/banner.vue b/assets/components/releases/banner.vue index 65ff4601..b1b47ab4 100644 --- a/assets/components/releases/banner.vue +++ b/assets/components/releases/banner.vue @@ -26,6 +26,8 @@ :alt="release.title" class="item trailer-video" controls + @playing="playing = true" + @pause="playing = false" >Sorry, the tailer cannot be played in your browser + + !!sourceX.quality)) { @@ -124,7 +126,12 @@ async function fetchItem(source, index, existingItemsBySource, domain, role, att logger.verbose(`Fetching ${domain} ${role} from ${source.src || source}`); // const res = await bhttp.get(source.src || source); - const res = await get(source.src || source); + const res = await get(source.src || source, { + headers: { + ...(source.referer && { referer: source.referer }), + ...(source.host && { host: source.host }), + }, + }); if (res.statusCode === 200) { const { pathname } = new URL(source.src || source); diff --git a/src/scrapers/amateurallure.js b/src/scrapers/amateurallure.js new file mode 100644 index 00000000..e86830c5 --- /dev/null +++ b/src/scrapers/amateurallure.js @@ -0,0 +1,49 @@ +'use strict'; + +const { fetchLatest, fetchScene } = require('./julesjordan'); + +function extractActors(scene) { + const release = scene; + + if (!scene.actors || scene.actors.length === 0) { + const introActorMatches = scene.title.match(/(?:presents|introduces|features|welcomes) (\w+ \w+)/i); + const introTwoActorMatches = scene.title.match(/(?:presents|introduces|features|welcomes) (?:(\w+)|(\w+ \w+)) and (\w+ \w+)/i); + const returnActorMatches = scene.title.match(/(?:(^\w+)|(\w+ \w+))(?:,| (?:return|visit|pov|give|suck|lick|milk|love|enjoy|service|is))/i); + const returnTwoActorMatches = scene.title.match(/(\w+ \w+) and (?:(\w+)|(\w+ \w+)) (?:return|visit|give|suck|lick|milk|love|enjoy|service|are)/i); + + const rawActors = (introTwoActorMatches || introActorMatches || returnTwoActorMatches || returnActorMatches)?.slice(1); + const actors = rawActors?.filter((actor) => { + if (!actor) return false; + if (/swallow|\bcum|fuck|suck|give|giving|take|takes|taking|head|teen|babe|cute|beaut|naughty|teacher|nanny|adorable|brunette|blonde|bust|audition|from|\band\b|\bto\b/i.test(actor)) return false; + + return true; + }); + + if (actors) { + release.actors = actors; + } + } + + if (release.actors?.length > 1 || /threesome|threeway/.test(scene.title)) { + release.tags = scene.tags ? [...scene.tags, 'mff'] : ['mff']; + } + + return release; +} + +async function fetchLatestWrap(site, page = 1) { + const latest = await fetchLatest(site, page); + + return latest.map(scene => extractActors(scene)); +} + +async function fetchSceneWrap(url, site) { + const scene = await fetchScene(url, site); + + return extractActors(scene); +} + +module.exports = { + fetchLatest: fetchLatestWrap, + fetchScene: fetchSceneWrap, +}; diff --git a/src/scrapers/julesjordan.js b/src/scrapers/julesjordan.js index 73bd21e7..d81f8bc7 100644 --- a/src/scrapers/julesjordan.js +++ b/src/scrapers/julesjordan.js @@ -1,5 +1,6 @@ 'use strict'; +const util = require('util'); const Promise = require('bluebird'); const bhttp = require('bhttp'); const cheerio = require('cheerio'); @@ -78,7 +79,7 @@ async function getPhotosLegacy(entryId, site, type = 'highres', page = 1) { } async function getPhotos(entryId, site, type = 'highres', page = 1) { - const albumUrl = `${site.url}/trial/gallery.php?id=${entryId}&type=${type}&page=${page}`; + const albumUrl = `${site.parameters?.photos || `${site.url}/gallery.php`}?id=${entryId}&type=${type}&page=${page}`; const res = await bhttp.get(albumUrl); const html = res.body.toString(); @@ -86,7 +87,10 @@ async function getPhotos(entryId, site, type = 'highres', page = 1) { const sourceLines = html.split(/\n/).filter(line => line.match(/ptx\["\w+"\]/)); const sources = sourceLines.reduce((acc, sourceLine) => { const quality = sourceLine.match(/\["\w+"\]/)[0].slice(2, -2); - const source = sourceLine.slice(sourceLine.indexOf('/trial'), sourceLine.indexOf('.jpg') + 4); + const sourceStart = sourceLine.match(/\/trial|\/tour|\/content/); + + if (!sourceStart) return acc; + const source = sourceLine.slice(sourceStart.index, sourceLine.indexOf('.jpg') + 4); if (!source) return acc; if (!acc[quality]) acc[quality] = []; @@ -120,9 +124,9 @@ function scrapeLatest(html, site) { return scenesElements.map((element) => { const release = {}; - const sceneLinkElement = $(element).find('a[title*=" "]'); + const sceneLinkElement = $(element).find('a[title], .update_title a'); release.url = sceneLinkElement.attr('href'); - release.title = sceneLinkElement.text(); + release.title = sceneLinkElement.text()?.trim() || sceneLinkElement.attr('alt')?.trim(); release.entryId = $(element).attr('data-setid'); @@ -135,14 +139,16 @@ function scrapeLatest(html, site) { .toArray(); const photoElement = $(element).find('a img.thumbs'); - const photoCount = Number(photoElement.attr('cnt')); + const photoCount = Number(photoElement.attr('cnt')) || 1; [release.poster, ...release.photos] = Array.from({ length: photoCount }, (value, index) => { - const src = photoElement.attr(`src${index}_1x`) || photoElement.attr(`src${index}`); + const src = photoElement.attr(`src${index}_1x`) || photoElement.attr(`src${index}`) || photoElement.attr('src'); if (!src) return null; - if (src.match(/^http/)) return src; - return `${site.url}${src}`; + return { + src: /^http/.test(src) ? src : `${site.url}${src}`, + referer: site.url, + }; }).filter(photoUrl => photoUrl); const teaserScript = $(element).find('script').html(); @@ -249,21 +255,39 @@ async function scrapeScene(html, url, site) { .split('\n'); const posterPath = infoLines.find(line => line.match('useimage')).replace('useimage = "', '').slice(0, -2); - if (posterPath) release.poster = posterPath.match(/^http/) ? posterPath : `${site.url}${posterPath}`; - const trailerLine = infoLines.find(line => line.match('movie["Trailer_720"]')); + if (posterPath) { + const poster = /^http/.test(posterPath) ? posterPath : `${site.url}${posterPath}`; + + if (poster) { + release.poster = { + src: poster, + referer: site.url, + }; + } + } if (site.slug !== 'manuelferrara') { - release.trailer = { - src: trailerLine.slice(trailerLine.indexOf('path:"') + 6, trailerLine.indexOf('",movie')), - quality: 720, - }; + const trailerLines = infoLines.filter(line => /movie\["Trailer\w*"\]\[/.test(line)); + + if (trailerLines.length) { + release.trailer = trailerLines.map((trailerLine) => { + const src = trailerLine.match(/path:"([\w:/.&=?%]+)"/)?.[1]; + const quality = trailerLine.match(/movie_height:'(\d+)/)?.[1]; + + return src && { + src: /^http/.test(src) ? src : `${site.url}${src}`, + quality: quality && Number(quality), + }; + }).filter(Boolean); + } } release.photos = await getPhotos(release.entryId, site); - release.tags = $('.update_tags a').map((tagIndex, tagElement) => $(tagElement).text()).toArray(); - release.movie = $('.update_dvds a').attr('href'); + + const movie = $('.update_dvds a').attr('href'); + if (movie) release.movie = movie; release.stars = Number($('.avg_rating').text().trim().replace(/[\s|Avg Rating:]/g, '')); @@ -320,15 +344,27 @@ function scrapeProfile(html, url, actorName) { } async function fetchLatest(site, page = 1) { - const res = await bhttp.get(`${site.url}/trial/categories/movies_${page}_d.html`); + const url = site.parameters?.latest ? util.format(site.parameters.latest, page) : `${site.url}/trial/categories/movies_${page}_d.html`; + const res = await bhttp.get(url); - return scrapeLatest(res.body.toString(), site); + if (res.statusCode === 200) { + return scrapeLatest(res.body.toString(), site); + } + + return res.statusCode; } async function fetchUpcoming(site) { - const res = await bhttp.get(`${site.url}/trial/index.php`); + if (site.parameters?.upcoming === false) return null; - return scrapeUpcoming(res.body.toString(), site); + const url = site.parameters?.upcoming ? util.format(site.parameters.upcoming) : `${site.url}/trial/index.php`; + const res = await bhttp.get(url); + + if (res.statusCode === 200) { + return scrapeUpcoming(res.body.toString(), site); + } + + return res.statusCode; } async function fetchScene(url, site) { diff --git a/src/scrapers/scrapers.js b/src/scrapers/scrapers.js index 215d3207..36f4ec0d 100644 --- a/src/scrapers/scrapers.js +++ b/src/scrapers/scrapers.js @@ -2,6 +2,7 @@ const adulttime = require('./adulttime'); const assylum = require('./assylum'); +const amateurallure = require('./amateurallure'); const babes = require('./babes'); const bang = require('./bang'); const bangbros = require('./bangbros'); @@ -65,6 +66,7 @@ module.exports = { '21sextreme': sextreme, '21sextury': sextury, adulttime, + amateurallure, assylum, babes, bang, @@ -83,6 +85,7 @@ module.exports = { fantasymassage, fullpornnetwork, girlsway, + girlgirl: julesjordan, insex, jayrock, julesjordan, @@ -106,6 +109,7 @@ module.exports = { puretaboo, realitykings, score, + swallowsalon: julesjordan, teamskeet, twistys, vivid,