diff --git a/public/img/logos/firstanalquest/doubleviewcasting.png b/public/img/logos/firstanalquest/doubleviewcasting.png new file mode 100644 index 00000000..42f5999c Binary files /dev/null and b/public/img/logos/firstanalquest/doubleviewcasting.png differ diff --git a/public/img/logos/firstanalquest/favicon.png b/public/img/logos/firstanalquest/favicon.png new file mode 100644 index 00000000..97869ed3 Binary files /dev/null and b/public/img/logos/firstanalquest/favicon.png differ diff --git a/public/img/logos/firstanalquest/firstanalquest.png b/public/img/logos/firstanalquest/firstanalquest.png new file mode 100644 index 00000000..0709d2b3 Binary files /dev/null and b/public/img/logos/firstanalquest/firstanalquest.png differ diff --git a/public/img/logos/firstanalquest/fuckndrive.png b/public/img/logos/firstanalquest/fuckndrive.png new file mode 100644 index 00000000..2dd0eed7 Binary files /dev/null and b/public/img/logos/firstanalquest/fuckndrive.png differ diff --git a/public/img/logos/firstanalquest/jizzonteens.png b/public/img/logos/firstanalquest/jizzonteens.png new file mode 100644 index 00000000..589a8eb9 Binary files /dev/null and b/public/img/logos/firstanalquest/jizzonteens.png differ diff --git a/public/img/logos/firstanalquest/lazy/doubleviewcasting.png b/public/img/logos/firstanalquest/lazy/doubleviewcasting.png new file mode 100644 index 00000000..ad7b336a Binary files /dev/null and b/public/img/logos/firstanalquest/lazy/doubleviewcasting.png differ diff --git a/public/img/logos/firstanalquest/lazy/firstanalquest.png b/public/img/logos/firstanalquest/lazy/firstanalquest.png new file mode 100644 index 00000000..57079093 Binary files /dev/null and b/public/img/logos/firstanalquest/lazy/firstanalquest.png differ diff --git a/public/img/logos/firstanalquest/lazy/fuckndrive.png b/public/img/logos/firstanalquest/lazy/fuckndrive.png new file mode 100644 index 00000000..75eec304 Binary files /dev/null and b/public/img/logos/firstanalquest/lazy/fuckndrive.png differ diff --git a/public/img/logos/firstanalquest/lazy/jizzonteens.png b/public/img/logos/firstanalquest/lazy/jizzonteens.png new file mode 100644 index 00000000..e5857e3c Binary files /dev/null and b/public/img/logos/firstanalquest/lazy/jizzonteens.png differ diff --git a/public/img/logos/firstanalquest/lazy/network.png b/public/img/logos/firstanalquest/lazy/network.png new file mode 100644 index 00000000..fc192dbe Binary files /dev/null and b/public/img/logos/firstanalquest/lazy/network.png differ diff --git a/public/img/logos/firstanalquest/lazy/wantedgfs.png b/public/img/logos/firstanalquest/lazy/wantedgfs.png new file mode 100644 index 00000000..40ab347c Binary files /dev/null and b/public/img/logos/firstanalquest/lazy/wantedgfs.png differ diff --git a/public/img/logos/firstanalquest/misc/double-view-casting.png b/public/img/logos/firstanalquest/misc/double-view-casting.png new file mode 100644 index 00000000..42f5999c Binary files /dev/null and b/public/img/logos/firstanalquest/misc/double-view-casting.png differ diff --git a/public/img/logos/firstanalquest/misc/first-anal-quest_square.png b/public/img/logos/firstanalquest/misc/first-anal-quest_square.png new file mode 100644 index 00000000..3e6d6efc Binary files /dev/null and b/public/img/logos/firstanalquest/misc/first-anal-quest_square.png differ diff --git a/public/img/logos/firstanalquest/misc/first-anal-quest_square_clean.png b/public/img/logos/firstanalquest/misc/first-anal-quest_square_clean.png new file mode 100644 index 00000000..0709d2b3 Binary files /dev/null and b/public/img/logos/firstanalquest/misc/first-anal-quest_square_clean.png differ diff --git a/public/img/logos/firstanalquest/misc/fuck-n-drive.png b/public/img/logos/firstanalquest/misc/fuck-n-drive.png new file mode 100644 index 00000000..2dd0eed7 Binary files /dev/null and b/public/img/logos/firstanalquest/misc/fuck-n-drive.png differ diff --git a/public/img/logos/firstanalquest/misc/jizz-on-teens.png b/public/img/logos/firstanalquest/misc/jizz-on-teens.png new file mode 100644 index 00000000..589a8eb9 Binary files /dev/null and b/public/img/logos/firstanalquest/misc/jizz-on-teens.png differ diff --git a/public/img/logos/firstanalquest/misc/jizz-on-teens_slogan.png b/public/img/logos/firstanalquest/misc/jizz-on-teens_slogan.png new file mode 100644 index 00000000..3e580012 Binary files /dev/null and b/public/img/logos/firstanalquest/misc/jizz-on-teens_slogan.png differ diff --git a/public/img/logos/firstanalquest/misc/wanted-gfs.png b/public/img/logos/firstanalquest/misc/wanted-gfs.png new file mode 100644 index 00000000..ad40f907 Binary files /dev/null and b/public/img/logos/firstanalquest/misc/wanted-gfs.png differ diff --git a/public/img/logos/firstanalquest/network.png b/public/img/logos/firstanalquest/network.png new file mode 100644 index 00000000..0709d2b3 Binary files /dev/null and b/public/img/logos/firstanalquest/network.png differ diff --git a/public/img/logos/firstanalquest/thumbs/doubleviewcasting.png b/public/img/logos/firstanalquest/thumbs/doubleviewcasting.png new file mode 100644 index 00000000..d55f0be9 Binary files /dev/null and b/public/img/logos/firstanalquest/thumbs/doubleviewcasting.png differ diff --git a/public/img/logos/firstanalquest/thumbs/firstanalquest.png b/public/img/logos/firstanalquest/thumbs/firstanalquest.png new file mode 100644 index 00000000..7f0087de Binary files /dev/null and b/public/img/logos/firstanalquest/thumbs/firstanalquest.png differ diff --git a/public/img/logos/firstanalquest/thumbs/fuckndrive.png b/public/img/logos/firstanalquest/thumbs/fuckndrive.png new file mode 100644 index 00000000..81269fe0 Binary files /dev/null and b/public/img/logos/firstanalquest/thumbs/fuckndrive.png differ diff --git a/public/img/logos/firstanalquest/thumbs/jizzonteens.png b/public/img/logos/firstanalquest/thumbs/jizzonteens.png new file mode 100644 index 00000000..3421cd72 Binary files /dev/null and b/public/img/logos/firstanalquest/thumbs/jizzonteens.png differ diff --git a/public/img/logos/firstanalquest/thumbs/network.png b/public/img/logos/firstanalquest/thumbs/network.png new file mode 100644 index 00000000..9180aedd Binary files /dev/null and b/public/img/logos/firstanalquest/thumbs/network.png differ diff --git a/public/img/logos/firstanalquest/thumbs/wantedgfs.png b/public/img/logos/firstanalquest/thumbs/wantedgfs.png new file mode 100644 index 00000000..a44e9047 Binary files /dev/null and b/public/img/logos/firstanalquest/thumbs/wantedgfs.png differ diff --git a/public/img/logos/firstanalquest/wantedgfs.png b/public/img/logos/firstanalquest/wantedgfs.png new file mode 100644 index 00000000..ad40f907 Binary files /dev/null and b/public/img/logos/firstanalquest/wantedgfs.png differ diff --git a/seeds/01_networks.js b/seeds/01_networks.js index 23a9da16..1debbf11 100644 --- a/seeds/01_networks.js +++ b/seeds/01_networks.js @@ -224,6 +224,11 @@ const networks = [ description: 'Wherever they go, there is porn. Hospital, Taxis, Casting… Maybe fucking to a fake cop, fake agent or fake taxi driver. And we record it all.', parent: 'mindgeek', }, + { + slug: 'firstanalquest', + name: 'First Anal Quest', + url: 'http://www.firstanalquest.com', + }, { slug: 'forbondage', name: 'ForBondage', diff --git a/seeds/02_sites.js b/seeds/02_sites.js index 115aa108..3f510a4a 100644 --- a/seeds/02_sites.js +++ b/seeds/02_sites.js @@ -2757,6 +2757,55 @@ const sites = [ url: 'https://afterhoursexposed.com', parent: 'fcuk', }, + // FIRST ANAL QUEST + { + slug: 'firstanalquest', + name: 'First Anal Quest', + url: 'http://www.firstanalquest.com', + tags: ['anal'], + parent: 'firstanalquest', + parameters: { + layout: 'a', + latest: 'http://www.firstanalquest.com/latest-updates', + }, + }, + { + slug: 'doubleviewcasting', + name: 'Double View Casting', + url: 'http://www.doubleviewcasting.com', + parent: 'firstanalquest', + parameters: { + layout: 'a', + latest: 'http://www.doubleviewcasting.com/scenes/page', + }, + }, + { + slug: 'fuckndrive', + name: 'Fuck\'n\'Drive', + url: 'http://www.fuckndrive.com', + parent: 'firstanalquest', + parameters: { + layout: 'b', + }, + }, + { + slug: 'jizzonteens', + name: 'Jizz On Teens', + url: 'http://www.jizzonteens.com', + parent: 'firstanalquest', + parameters: { + layout: 'b', + }, + }, + { + slug: 'wantedgfs', + name: 'Wanted GFs', + url: 'http://www.wantedgfs.com', + parent: 'firstanalquest', + parameters: { + layout: 'c', + }, + }, // FOR BONDAGE { name: 'Crowd Bondage', diff --git a/src/deep.js b/src/deep.js index 23edfdd1..77ecfdda 100644 --- a/src/deep.js +++ b/src/deep.js @@ -41,7 +41,7 @@ async function findEntities(baseReleases) { .orderBy('entities.type', 'asc'); // channel entity will overwrite network entity - const entitiesBySlug = entities.reduce((accEntities, entity) => ({ ...accEntities, [entity.slug]: entity }), {}); + const entitiesBySlug = entities.reduce((accEntities, entity) => ({ ...accEntities, [entity.slug]: accEntities[entity.slug] || entity }), {}); return entitiesBySlug; } @@ -102,13 +102,14 @@ async function scrapeRelease(baseRelease, entities, type = 'scene') { } const scraper = scrapers.releases[entity.slug] || scrapers.releases[entity.parent?.slug]; + const layoutScraper = scraper[entity.parameters?.layout] || scraper; - if (!scraper) { + if (!layoutScraper) { logger.warn(`Could not find scraper for ${baseRelease.url}`); return baseRelease; } - if ((type === 'scene' && !scraper.fetchScene) || (type === 'movie' && !scraper.fetchMovie)) { + if ((type === 'scene' && !layoutScraper.fetchScene) || (type === 'movie' && !layoutScraper.fetchMovie)) { logger.warn(`The '${entity.name}'-scraper cannot fetch individual ${type}s`); return baseRelease; } @@ -117,8 +118,8 @@ async function scrapeRelease(baseRelease, entities, type = 'scene') { logger.verbose(`Fetching ${type} ${baseRelease.url}`); const scrapedRelease = type === 'scene' - ? await scraper.fetchScene(baseRelease.url, entity, baseRelease, include, null) - : await scraper.fetchMovie(baseRelease.url, entity, baseRelease, include, null); + ? await layoutScraper.fetchScene(baseRelease.url, entity, baseRelease, include, null) + : await layoutScraper.fetchMovie(baseRelease.url, entity, baseRelease, include, null); const mergedRelease = { ...baseRelease, diff --git a/src/scrapers/firstanalquest.js b/src/scrapers/firstanalquest.js new file mode 100644 index 00000000..bb2fb274 --- /dev/null +++ b/src/scrapers/firstanalquest.js @@ -0,0 +1,99 @@ +'use strict'; + +const qu = require('../utils/qu'); + +function scrapeAllA(scenes, channel) { + return scenes.map(({ query }) => { + const release = {}; + + release.url = query.url('a.thumb-img, a.thumb', 'href', { origin: channel.url }); + release.entryId = new URL(release.url).pathname.match(/(\d+)\/?$/)?.[1]; + + release.title = query.text('.thumb-title, .title'); + release.date = query.date('.thumb-added, .date', ['MMM D, YYYY', 'MMMM DD, YYYY'], /\w+ \d{1,2}, \d{4}/); + release.duration = query.dur('.thumb-duration'); + + release.actors = query.all('.thumb-models a, .models a').map(actorEl => ({ + name: query.cnt(actorEl), + url: query.url(actorEl, null, 'href', { origin: channel.url }), + })); + + const [, photoUrl, photoCount] = query.q('.thumb-img img', 'onmouseover')?.match(/'(.*)', (\d+)\)/) || []; + + if (photoUrl && photoCount) { + [release.poster, ...release.photos] = Array.from({ length: 5 }, (value, index) => `${photoUrl}${index + 1}.jpg`); + } else { + release.poster = query.img('.thumb-img img, .thumb img', 'src', { origin: channel.url }); + } + + release.tags = query.cnts('.tags a'); + release.rating = query.number('.thumb-rating'); + + console.log(release); + return release; + }); +} + +function scrapeSceneA({ query }, url, channel) { + const release = {}; + + release.entryId = new URL(url).pathname.match(/(\d+)\/?$/)?.[1]; + + release.title = query.cnt('.title, .scene-title h3').replace(/:$/, ''); + release.description = query.cnt('.text-desc p, .info-description p'); + + release.duration = query.dur('.media-body li span, .duration'); + + release.actors = query.all('.media-body a[href*="models/"], .models a').map(actorEl => ({ + name: query.cnt(actorEl), + url: query.url(actorEl, null, 'href', { origin: channel.url }), + })); + + release.tags = query.cnts('.media-body a[href*="tags/"], .tags a'); + + release.poster = [ + query.img('.player-preview'), + qu.prefixUrl(`/contents/videos_screenshots/0/${release.entryId}/preview_trailer.mp4.jpg`, channel.url), + qu.prefixUrl(query.q('param[name="flashvars"]', 'value')?.match(/poster=(.*\.jpg)/)?.[1], channel.url), + qu.prefixUrl(`/contents/scenes/${release.entyId}/thumbnails/920x518.jpg`, channel.url), + ]; + + release.photos = query.urls('.thumb-album a:not([href="#"]), .thumbs-photo a:not([href*="signup"])', 'href', { origin: channel.url }) + .concat(query.imgs('.thumb-album a[href="#"] img, .thumbs-photo a[href*="signup"] img', 'src', { origin: channel.url })); + + release.trailer = query.url('a[href*="get_file/"], .download a'); + + console.log(release); + return release; +} + +async function fetchLatestA(channel, page) { + const url = channel.parameters?.latest + ? `${channel.parameters.latest}/${page}` + : `${channel.url}/latest-updates/${page}/`; + + const res = await qu.getAll(url, '.list-thumbs ul > li, .main-thumbs > li'); + + if (res.ok) { + return scrapeAllA(res.items, channel); + } + + return res.status; +} + +async function fetchSceneA(url, channel) { + const res = await qu.get(url, '.main, .main-content'); + + if (res.ok) { + return scrapeSceneA(res.item, url, channel); + } + + return res.status; +} + +module.exports = { + a: { + fetchLatest: fetchLatestA, + fetchScene: fetchSceneA, + }, +}; diff --git a/src/scrapers/scrapers.js b/src/scrapers/scrapers.js index edb4bc96..b6ef5d83 100644 --- a/src/scrapers/scrapers.js +++ b/src/scrapers/scrapers.js @@ -22,6 +22,7 @@ const evilangel = require('./evilangel'); const fakehub = require('./fakehub'); const famedigital = require('./famedigital'); const fantasymassage = require('./fantasymassage'); +const firstanalquest = require('./firstanalquest'); const fcuk = require('./fcuk'); const fullpornnetwork = require('./fullpornnetwork'); const girlsway = require('./girlsway'); @@ -110,6 +111,7 @@ const scrapers = { famedigital, fantasymassage, fcuk, + firstanalquest, forbondage: porndoe, fullpornnetwork, girlsway, diff --git a/src/updates.js b/src/updates.js index 2a9f5bb5..07553829 100644 --- a/src/updates.js +++ b/src/updates.js @@ -209,7 +209,9 @@ async function scrapeChannel(channelEntity, accNetworkReleases) { || scrapers.releases[channelEntity.parent?.slug] || scrapers.releases[channelEntity.parent?.parent?.slug]; - if (!scraper) { + const layoutScraper = scraper?.[channelEntity.parameters?.layout] || scraper; + + if (!layoutScraper) { logger.warn(`No scraper found for '${channelEntity.name}' (${channelEntity.parent?.name})`); return emptyReleases; } @@ -217,7 +219,7 @@ async function scrapeChannel(channelEntity, accNetworkReleases) { try { const beforeFetchLatest = await scraper.beforeFetchLatest?.(channelEntity); - return await scrapeChannelReleases(scraper, channelEntity, { + return await scrapeChannelReleases(layoutScraper, channelEntity, { ...accNetworkReleases, beforeFetchLatest, }); diff --git a/src/utils/qu.js b/src/utils/qu.js index 121bb877..97a52733 100644 --- a/src/utils/qu.js +++ b/src/utils/qu.js @@ -161,7 +161,7 @@ function styles(context, selector, styleAttr) { return elStyles; } -function number(context, selector, match = /\d+/, attr = 'textContent') { +function number(context, selector, match = /\d+(\.\d*)?/, attr = 'textContent') { const value = q(context, selector, attr); if (value && match) {