| const { Source, RunnerScraper, Hoster } = require("source-scraper-core"); |
| const { PuppeteerRunner } = require("source-scraper-puppeteer-runner"); |
| const cheerio = require("cheerio"); |
| const u = require("url"); |
|
|
| class NinexbuddySource extends Source { |
| constructor(source) { |
| super(source); |
| this.quality = source.quality; |
| } |
| } |
|
|
| function parseSourceQuality(raw) { |
| const ar1 = /^([a-zA-Z\d]+)\s*-\s*(\d+)([a-zA-Z]+)?$/i.exec(raw); |
| if (ar1 !== null && ar1.length >= 4) |
| return { |
| raw, |
| description: ar1[1], |
| value: Number(ar1[2]), |
| unit: ar1[3] |
| }; |
| const ar2 = /^(\d+)([a-zA-Z]+)\s*\(?([a-zA-Z\s]+)\)?$/i.exec(raw); |
| if (ar2 !== null && ar2.length >= 3) |
| return { |
| raw, |
| description: ar2[3], |
| value: Number(ar2[1]), |
| unit: ar2[2] |
| }; |
| } |
|
|
| function parseHosterName(raw) { |
| const ar = /^(?:embed\s*-)?\s*([a-zA-Z\d.]+)$/i.exec(raw.trim()); |
| if (ar === null || ar.length < 2) |
| return; |
| return ar[ar.length - 1]; |
| } |
|
|
| function isDefined(value) { |
| return typeof value !== 'undefined'; |
| } |
|
|
| class NinexbuddyScraper extends RunnerScraper { |
| constructor() { |
| super(); |
| this.name = 'ninexbuddy'; |
| this.domains = []; |
| this.urlPattern = /.*/i; |
| this.runner = new PuppeteerRunner(); |
| this.defaultOptions = { |
| runnerOptions: { |
| navigationOptions: { |
| waitUntil: 'networkidle0' |
| } |
| } |
| }; |
| } |
|
|
| transformUrl(url) { |
| return `https://9xbuddy.com/process?url=${url}`; |
| } |
|
|
| async execWithArgs({ page, url: ninexbuddyUrl }) { |
| const isHoster = !!(await page.$('.playlist_el').catch(() => false)); |
| if (isHoster) { |
| const items = await page.$$('.playlist_el .text-blue'); |
| const hosters = (await Promise.all(items.map(async (item) => { |
| const urlPromise = item.getProperty('href').then(async (e) => e.jsonValue()).catch(() => undefined); |
| const namePromise = item.getProperty('textContent').then(async (e) => e.jsonValue()).catch(() => undefined); |
| const [url, name] = await Promise.all([urlPromise, namePromise]); |
| const hosterUrl = u.parse(url, true).query.url; |
| if (!hosterUrl) |
| return; |
| const parsed = name ? parseHosterName(name) : undefined; |
| if (!parsed) |
| return; |
| return new Hoster({ |
| url: hosterUrl, |
| name: parsed, |
| }); |
| }))).filter(isDefined); |
| return { |
| ninexbuddyUrl, |
| hosters |
| }; |
| } else { |
| const selector = '.tracking-wide.items-center.night-white'; |
| const items = await page.$$(selector); |
| const sources = (await Promise.all(items.map(async (item) => { |
| const formatPromise = item.$eval('.w-24.text-blue', e => e.textContent).catch(() => undefined); |
| const qualityPromise = item.$eval('.w-1\\/2', e => e.textContent).catch(() => undefined); |
| const urlPromise = item.$eval('.leading-normal.sm\\:leading-none', e => e.getAttribute('href')).catch(() => undefined); |
| const [format, quality, url] = await Promise.all([formatPromise, qualityPromise, urlPromise]); |
| if (!url) |
| return; |
| return new NinexbuddySource({ |
| url, |
| quality: quality ? parseSourceQuality(quality) : undefined, |
| type: format || undefined, |
| codec: undefined |
| }); |
| }))).filter(isDefined); |
| const poster = await page.$eval('img.shadow.border-2.border-grey-lighter.h-48', e => e.src).catch(() => undefined); |
| return { |
| ninexbuddyUrl, |
| title: await page.title(), |
| poster: poster && !poster.startsWith('data:image') ? poster : undefined, |
| sources |
| }; |
| } |
| } |
| } |
|
|
| module.exports = { |
| NinexbuddySource, |
| NinexbuddyScraper |
| } |