diff --git a/src/extractor/DoodStream.ts b/src/extractor/DoodStream.ts index 8b5e1d1..94601c9 100644 --- a/src/extractor/DoodStream.ts +++ b/src/extractor/DoodStream.ts @@ -2,7 +2,6 @@ import * as cheerio from 'cheerio'; import randomstring from 'randomstring'; import { NotFoundError } from '../error'; import { Context, CountryCode, Format, UrlResult } from '../types'; -import { Fetcher } from '../utils'; import { Extractor } from './Extractor'; export class DoodStream extends Extractor { @@ -10,14 +9,6 @@ export class DoodStream extends Extractor { public readonly label = 'DoodStream'; - private readonly fetcher: Fetcher; - - public constructor(fetcher: Fetcher) { - super(); - - this.fetcher = fetcher; - } - /** @see https://github.com/Gujal00/ResolveURL/blob/master/script.module.resolveurl/lib/resolveurl/plugins/doodstream.py */ public supports(_ctx: Context, url: URL): boolean { return null !== url.host.match(/dood|do[0-9]go|doood|dooood|ds2play|ds2video|d0o0d|do0od|d0000d|d000d|vidply|all3do|doply|vide0|vvide0|d-s/); diff --git a/src/extractor/Dropload.ts b/src/extractor/Dropload.ts index 3db503c..0a072fb 100644 --- a/src/extractor/Dropload.ts +++ b/src/extractor/Dropload.ts @@ -2,7 +2,7 @@ import bytes from 'bytes'; import * as cheerio from 'cheerio'; import { NotFoundError } from '../error'; import { Context, CountryCode, Format, UrlResult } from '../types'; -import { extractUrlFromPacked, Fetcher } from '../utils'; +import { extractUrlFromPacked } from '../utils'; import { Extractor } from './Extractor'; export class Dropload extends Extractor { @@ -10,14 +10,6 @@ export class Dropload extends Extractor { public readonly label = 'Dropload'; - private readonly fetcher: Fetcher; - - public constructor(fetcher: Fetcher) { - super(); - - this.fetcher = fetcher; - } - public supports(_ctx: Context, url: URL): boolean { return null !== url.host.match(/dropload/); } diff --git a/src/extractor/ExternalUrl.ts b/src/extractor/ExternalUrl.ts index 012c894..943eee6 100644 --- a/src/extractor/ExternalUrl.ts +++ b/src/extractor/ExternalUrl.ts @@ -1,6 +1,6 @@ import { BlockedError } from '../error'; import { Context, CountryCode, Format, UrlResult } from '../types'; -import { Fetcher, showExternalUrls } from '../utils'; +import { showExternalUrls } from '../utils'; import { Extractor } from './Extractor'; export class ExternalUrl extends Extractor { @@ -10,14 +10,6 @@ export class ExternalUrl extends Extractor { public override readonly ttl = 3600000; // 1h - private readonly fetcher: Fetcher; - - public constructor(fetcher: Fetcher) { - super(); - - this.fetcher = fetcher; - } - public supports(ctx: Context, url: URL): boolean { return showExternalUrls(ctx.config) && null !== url.host.match(/.*/); } diff --git a/src/extractor/Extractor.ts b/src/extractor/Extractor.ts index 76861e5..d19bf6d 100644 --- a/src/extractor/Extractor.ts +++ b/src/extractor/Extractor.ts @@ -1,5 +1,6 @@ import { NotFoundError } from '../error'; import { Context, CountryCode, Format, UrlResult } from '../types'; +import { Fetcher } from '../utils'; export abstract class Extractor { public abstract readonly id: string; @@ -10,6 +11,12 @@ export abstract class Extractor { public readonly viaMediaFlowProxy: boolean = false; + protected readonly fetcher: Fetcher; + + public constructor(fetcher: Fetcher) { + this.fetcher = fetcher; + } + public abstract supports(ctx: Context, url: URL): boolean; public normalize(url: URL): URL { diff --git a/src/extractor/Fastream.ts b/src/extractor/Fastream.ts index 544251a..71dfc0d 100644 --- a/src/extractor/Fastream.ts +++ b/src/extractor/Fastream.ts @@ -1,6 +1,6 @@ import bytes from 'bytes'; import { Context, CountryCode, Format, UrlResult } from '../types'; -import { buildMediaFlowProxyExtractorStreamUrl, Fetcher, supportsMediaFlowProxy } from '../utils'; +import { buildMediaFlowProxyExtractorStreamUrl, supportsMediaFlowProxy } from '../utils'; import { Extractor } from './Extractor'; export class Fastream extends Extractor { @@ -12,14 +12,6 @@ export class Fastream extends Extractor { public override viaMediaFlowProxy = true; - private readonly fetcher: Fetcher; - - public constructor(fetcher: Fetcher) { - super(); - - this.fetcher = fetcher; - } - public supports(ctx: Context, url: URL): boolean { return null !== url.host.match(/fastream/) && supportsMediaFlowProxy(ctx); } diff --git a/src/extractor/Fsst.ts b/src/extractor/Fsst.ts index c34aae1..55ae12a 100644 --- a/src/extractor/Fsst.ts +++ b/src/extractor/Fsst.ts @@ -1,6 +1,5 @@ import * as cheerio from 'cheerio'; import { Context, CountryCode, Format, UrlResult } from '../types'; -import { Fetcher } from '../utils'; import { Extractor } from './Extractor'; export class Fsst extends Extractor { @@ -10,14 +9,6 @@ export class Fsst extends Extractor { public override readonly ttl = 0; - private readonly fetcher: Fetcher; - - public constructor(fetcher: Fetcher) { - super(); - - this.fetcher = fetcher; - } - public supports(_ctx: Context, url: URL): boolean { return null !== url.host.match(/fsst/); }; diff --git a/src/extractor/KinoGer.ts b/src/extractor/KinoGer.ts index 0b80d2c..b76996f 100644 --- a/src/extractor/KinoGer.ts +++ b/src/extractor/KinoGer.ts @@ -1,6 +1,6 @@ import crypto from 'crypto'; import { Context, CountryCode, Format, UrlResult } from '../types'; -import { Fetcher, guessHeightFromPlaylist } from '../utils'; +import { guessHeightFromPlaylist } from '../utils'; import { Extractor } from './Extractor'; /** @see https://github.com/Gujal00/ResolveURL/blob/master/script.module.resolveurl/lib/resolveurl/plugins/kinoger.py */ @@ -9,14 +9,6 @@ export class KinoGer extends Extractor { public readonly label = 'KinoGer'; - private readonly fetcher: Fetcher; - - public constructor(fetcher: Fetcher) { - super(); - - this.fetcher = fetcher; - } - public supports(_ctx: Context, url: URL): boolean { return [ 'asianembed.cam', diff --git a/src/extractor/Mixdrop.ts b/src/extractor/Mixdrop.ts index 093d65a..fba3df7 100644 --- a/src/extractor/Mixdrop.ts +++ b/src/extractor/Mixdrop.ts @@ -2,7 +2,7 @@ import bytes from 'bytes'; import * as cheerio from 'cheerio'; import { NotFoundError } from '../error'; import { Context, CountryCode, Format, UrlResult } from '../types'; -import { buildMediaFlowProxyExtractorRedirectUrl, Fetcher, supportsMediaFlowProxy } from '../utils'; +import { buildMediaFlowProxyExtractorRedirectUrl, supportsMediaFlowProxy } from '../utils'; import { Extractor } from './Extractor'; export class Mixdrop extends Extractor { @@ -14,14 +14,6 @@ export class Mixdrop extends Extractor { public override viaMediaFlowProxy = true; - private readonly fetcher: Fetcher; - - public constructor(fetcher: Fetcher) { - super(); - - this.fetcher = fetcher; - } - public supports(ctx: Context, url: URL): boolean { return null !== url.host.match(/mixdrop/) && supportsMediaFlowProxy(ctx); } diff --git a/src/extractor/SaveFiles.ts b/src/extractor/SaveFiles.ts index 32584f2..f4cb4cb 100644 --- a/src/extractor/SaveFiles.ts +++ b/src/extractor/SaveFiles.ts @@ -1,7 +1,6 @@ import * as cheerio from 'cheerio'; import { NotFoundError } from '../error'; import { Context, CountryCode, Format, UrlResult } from '../types'; -import { Fetcher } from '../utils'; import { Extractor } from './Extractor'; export class SaveFiles extends Extractor { @@ -9,14 +8,6 @@ export class SaveFiles extends Extractor { public readonly label = 'SaveFiles'; - private readonly fetcher: Fetcher; - - public constructor(fetcher: Fetcher) { - super(); - - this.fetcher = fetcher; - } - public supports(_ctx: Context, url: URL): boolean { return null !== url.host.match(/savefiles|streamhls/); } diff --git a/src/extractor/Soaper.ts b/src/extractor/Soaper.ts index 0042d1e..f8e6697 100644 --- a/src/extractor/Soaper.ts +++ b/src/extractor/Soaper.ts @@ -1,5 +1,5 @@ import { Context, CountryCode, Format, UrlResult } from '../types'; -import { Fetcher, guessHeightFromPlaylist } from '../utils'; +import { guessHeightFromPlaylist } from '../utils'; import { Extractor } from './Extractor'; interface SoaperInfoResponsePartial { @@ -12,14 +12,6 @@ export class Soaper extends Extractor { public readonly label = 'Soaper'; - private readonly fetcher: Fetcher; - - public constructor(fetcher: Fetcher) { - super(); - - this.fetcher = fetcher; - } - public supports(_ctx: Context, url: URL): boolean { return null !== url.host.match(/soaper/) && null !== url.pathname.match(/^\/(episode|movie)_/); } diff --git a/src/extractor/StreamEmbed.ts b/src/extractor/StreamEmbed.ts index 90a7dcd..84fb133 100644 --- a/src/extractor/StreamEmbed.ts +++ b/src/extractor/StreamEmbed.ts @@ -1,5 +1,4 @@ import { Context, CountryCode, Format, UrlResult } from '../types'; -import { Fetcher } from '../utils'; import { Extractor } from './Extractor'; export class StreamEmbed extends Extractor { @@ -7,14 +6,6 @@ export class StreamEmbed extends Extractor { public readonly label = 'StreamEmbed'; - private readonly fetcher: Fetcher; - - public constructor(fetcher: Fetcher) { - super(); - - this.fetcher = fetcher; - } - public supports(_ctx: Context, url: URL): boolean { return null !== url.host.match(/bullstream|mp4player|watch\.gxplayer/); } diff --git a/src/extractor/Streamtape.ts b/src/extractor/Streamtape.ts index 95b4a20..6813301 100644 --- a/src/extractor/Streamtape.ts +++ b/src/extractor/Streamtape.ts @@ -2,7 +2,6 @@ import * as cheerio from 'cheerio'; import { Context, CountryCode, Format, UrlResult } from '../types'; import { buildMediaFlowProxyExtractorRedirectUrl, - Fetcher, supportsMediaFlowProxy, } from '../utils'; import { Extractor } from './Extractor'; @@ -14,14 +13,6 @@ export class Streamtape extends Extractor { public override readonly ttl = 0; - private readonly fetcher: Fetcher; - - public constructor(fetcher: Fetcher) { - super(); - - this.fetcher = fetcher; - } - public supports(ctx: Context, url: URL): boolean { return null !== url.host.match(/streamtape/) && supportsMediaFlowProxy(ctx); } diff --git a/src/extractor/SuperVideo.ts b/src/extractor/SuperVideo.ts index 0856d70..4bb92fe 100644 --- a/src/extractor/SuperVideo.ts +++ b/src/extractor/SuperVideo.ts @@ -2,7 +2,7 @@ import bytes from 'bytes'; import * as cheerio from 'cheerio'; import { NotFoundError } from '../error'; import { Context, CountryCode, Format, UrlResult } from '../types'; -import { extractUrlFromPacked, Fetcher } from '../utils'; +import { extractUrlFromPacked, guessHeightFromPlaylist } from '../utils'; import { Extractor } from './Extractor'; export class SuperVideo extends Extractor { @@ -10,14 +10,6 @@ export class SuperVideo extends Extractor { public readonly label = 'SuperVideo'; - private readonly fetcher: Fetcher; - - public constructor(fetcher: Fetcher) { - super(); - - this.fetcher = fetcher; - } - public supports(_ctx: Context, url: URL): boolean { return null !== url.host.match(/supervideo/); } @@ -37,14 +29,20 @@ export class SuperVideo extends Extractor { throw new NotFoundError(); } + const m3u8Url = extractUrlFromPacked(html, [/sources:\[{file:"(.*?)"/]); + const heightAndSizeMatch = html.match(/\d{3,}x(\d{3,}), ([\d.]+ ?[GM]B)/); + const size = heightAndSizeMatch ? bytes.parse(heightAndSizeMatch[2] as string) as number : undefined; + const height = heightAndSizeMatch + ? parseInt(heightAndSizeMatch[1] as string) + : await guessHeightFromPlaylist(ctx, this.fetcher, m3u8Url); const $ = cheerio.load(html); const title = $('.download__title').text().trim(); return [ { - url: extractUrlFromPacked(html, [/sources:\[{file:"(.*?)"/]), + url: m3u8Url, format: Format.hls, label: this.label, sourceId: `${this.id}_${countryCode}`, @@ -52,10 +50,8 @@ export class SuperVideo extends Extractor { meta: { countryCodes: [countryCode], title, - ...(heightAndSizeMatch && { - bytes: bytes.parse(heightAndSizeMatch[2] as string) as number, - height: parseInt(heightAndSizeMatch[1] as string), - }), + ...(size && { bytes: size }), + ...(height && { height }), }, }, ]; diff --git a/src/extractor/Uqload.ts b/src/extractor/Uqload.ts index 058da6a..fa63938 100644 --- a/src/extractor/Uqload.ts +++ b/src/extractor/Uqload.ts @@ -1,6 +1,6 @@ import * as cheerio from 'cheerio'; import { Context, CountryCode, Format, UrlResult } from '../types'; -import { buildMediaFlowProxyExtractorRedirectUrl, Fetcher, supportsMediaFlowProxy } from '../utils'; +import { buildMediaFlowProxyExtractorRedirectUrl, supportsMediaFlowProxy } from '../utils'; import { Extractor } from './Extractor'; export class Uqload extends Extractor { @@ -12,14 +12,6 @@ export class Uqload extends Extractor { public override viaMediaFlowProxy = true; - private readonly fetcher: Fetcher; - - public constructor(fetcher: Fetcher) { - super(); - - this.fetcher = fetcher; - } - public supports(ctx: Context, url: URL): boolean { return null !== url.host.match(/uqload/) && supportsMediaFlowProxy(ctx); } diff --git a/src/extractor/VidSrc.ts b/src/extractor/VidSrc.ts index 9616d5e..3c60d34 100644 --- a/src/extractor/VidSrc.ts +++ b/src/extractor/VidSrc.ts @@ -10,13 +10,11 @@ export class VidSrc extends Extractor { public readonly label = 'VidSrc'; - private readonly fetcher: Fetcher; private readonly tlds: NonEmptyArray; public constructor(fetcher: Fetcher, tlds: NonEmptyArray) { - super(); + super(fetcher); - this.fetcher = fetcher; this.tlds = tlds; } diff --git a/src/extractor/VixSrc.ts b/src/extractor/VixSrc.ts index c74b744..be844c2 100644 --- a/src/extractor/VixSrc.ts +++ b/src/extractor/VixSrc.ts @@ -2,7 +2,6 @@ import bytes from 'bytes'; import { Context, CountryCode, Format, UrlResult } from '../types'; import { buildMediaFlowProxyExtractorStreamUrl, - Fetcher, hasMultiEnabled, iso639FromCountryCode, supportsMediaFlowProxy, @@ -18,14 +17,6 @@ export class VixSrc extends Extractor { public override viaMediaFlowProxy = true; - private readonly fetcher: Fetcher; - - public constructor(fetcher: Fetcher) { - super(); - - this.fetcher = fetcher; - } - public supports(ctx: Context, url: URL): boolean { return null !== url.host.match(/vixsrc/) && supportsMediaFlowProxy(ctx); } diff --git a/src/extractor/XPrime.ts b/src/extractor/XPrime.ts index e4bffdf..44dd233 100644 --- a/src/extractor/XPrime.ts +++ b/src/extractor/XPrime.ts @@ -1,5 +1,4 @@ import { Context, CountryCode, Format, UrlResult } from '../types'; -import { Fetcher } from '../utils'; import { Extractor } from './Extractor'; interface XPrimePrimeboxResponsePartial { @@ -18,14 +17,6 @@ export class XPrime extends Extractor { public readonly label = 'XPrime'; - private readonly fetcher: Fetcher; - - public constructor(fetcher: Fetcher) { - super(); - - this.fetcher = fetcher; - } - public supports(_ctx: Context, url: URL): boolean { return null !== url.host.match(/xprime/); } diff --git a/src/extractor/YouTube.ts b/src/extractor/YouTube.ts index 48e0cb0..a8bed36 100644 --- a/src/extractor/YouTube.ts +++ b/src/extractor/YouTube.ts @@ -1,5 +1,4 @@ import { Context, CountryCode, Format, UrlResult } from '../types'; -import { Fetcher } from '../utils'; import { Extractor } from './Extractor'; export class YouTube extends Extractor { @@ -7,14 +6,6 @@ export class YouTube extends Extractor { public readonly label = 'YouTube'; - private readonly fetcher: Fetcher; - - public constructor(fetcher: Fetcher) { - super(); - - this.fetcher = fetcher; - } - public supports(_ctx: Context, url: URL): boolean { return null !== url.host.match(/youtube/) && url.searchParams.has('v'); } diff --git a/src/extractor/__fixtures__/SuperVideo/https:hfs308.serversicuro.cchlsdnzpe7rf5xg4a3gyva3h5orlyw23xosfzwunl5xbmjpz2l6t3doh5zbwynna.urlsetmaster.m3u8 b/src/extractor/__fixtures__/SuperVideo/https:hfs308.serversicuro.cchlsdnzpe7rf5xg4a3gyva3h5orlyw23xosfzwunl5xbmjpz2l6t3doh5zbwynna.urlsetmaster.m3u8 new file mode 100644 index 0000000..5c5be2c --- /dev/null +++ b/src/extractor/__fixtures__/SuperVideo/https:hfs308.serversicuro.cchlsdnzpe7rf5xg4a3gyva3h5orlyw23xosfzwunl5xbmjpz2l6t3doh5zbwynna.urlsetmaster.m3u8 @@ -0,0 +1,5 @@ +#EXTM3U +#EXT-X-STREAM-INF:PROGRAM-ID=1,BANDWIDTH=3056778,RESOLUTION=1920x1080,FRAME-RATE=25.000,CODECS="avc1.640828,mp4a.40.2" +https://hfs308.serversicuro.cc/hls/dnzpe7rf5xg4a3gyva3h5orlyw23xosfzwunl5xbmjpz2l6t3doh5zbwynna/index-v1-a1.m3u8 + +#EXT-X-I-FRAME-STREAM-INF:BANDWIDTH=215307,RESOLUTION=1920x1080,CODECS="avc1.640828",URI="https://hfs308.serversicuro.cc/hls/dnzpe7rf5xg4a3gyva3h5orlyw23xosfzwunl5xbmjpz2l6t3doh5zbwynna/iframes-v1-a1.m3u8" diff --git a/src/extractor/__fixtures__/SuperVideo/https:supervideo.ccbj6szat1pval b/src/extractor/__fixtures__/SuperVideo/https:supervideo.ccbj6szat1pval index 2d987fe..0261fd0 100644 --- a/src/extractor/__fixtures__/SuperVideo/https:supervideo.ccbj6szat1pval +++ b/src/extractor/__fixtures__/SuperVideo/https:supervideo.ccbj6szat1pval @@ -15,9 +15,9 @@ - - - + + + @@ -65,7 +65,7 @@ - @@ -99,30 +99,26 @@
  • Terms of service
  • - +
  • Make Money
  • -
  • +
  • Contact Us
  • -
    - + \ No newline at end of file diff --git a/src/extractor/__fixtures__/SuperVideo/https:supervideo.ccebj6szat1pval b/src/extractor/__fixtures__/SuperVideo/https:supervideo.ccebj6szat1pval index 56266d2..e9d3456 100644 --- a/src/extractor/__fixtures__/SuperVideo/https:supervideo.ccebj6szat1pval +++ b/src/extractor/__fixtures__/SuperVideo/https:supervideo.ccebj6szat1pval @@ -3,10 +3,10 @@ - - - - + + + - + + @@ -39,10 +39,10 @@ $.cookie('aff', '21776', { expires: 10 });
    Upgrade you account to watch videos with no limits!
    - - - - + + + +
    - - - + diff --git a/src/extractor/__snapshots__/SuperVideo.test.ts.snap b/src/extractor/__snapshots__/SuperVideo.test.ts.snap index cb1bf25..9e9bee3 100644 --- a/src/extractor/__snapshots__/SuperVideo.test.ts.snap +++ b/src/extractor/__snapshots__/SuperVideo.test.ts.snap @@ -11,11 +11,12 @@ exports[`SuperVideo embed only 1`] = ` "countryCodes": [ "it", ], + "height": 1080, "title": "", }, "sourceId": "supervideo_it", "ttl": 900000, - "url": "https://hfs308.serversicuro.cc/hls/,dnzpe7rf5xg4a3gyva3h5orlyw23xosfzwunl5xbmjpz2hqr27aodtfrseia,.urlset/master.m3u8", + "url": "https://hfs308.serversicuro.cc/hls/,dnzpe7rf5xg4a3gyva3h5orlyw23xosfzwunl5xbmjpz2l6t3doh5zbwynna,.urlset/master.m3u8", }, ] `; diff --git a/src/utils/StreamResolver.test.ts b/src/utils/StreamResolver.test.ts index 09052cc..54bea4c 100644 --- a/src/utils/StreamResolver.test.ts +++ b/src/utils/StreamResolver.test.ts @@ -152,7 +152,7 @@ describe('resolve', () => { }, { url: new URL('https://working2.com'), - format: Format.hls, + format: Format.unknown, label: 'working1', sourceId: 'hostercom', meta: { @@ -183,7 +183,7 @@ describe('resolve', () => { }, { url: new URL('https://working1.com'), - format: Format.hls, + format: Format.unknown, label: 'working2', sourceId: 'hostercom', meta: { @@ -248,7 +248,7 @@ describe('resolve', () => { ]; } - const streamResolver = new StreamResolver(logger, new ExtractorRegistry(logger, [new MockExtractor()])); + const streamResolver = new StreamResolver(logger, new ExtractorRegistry(logger, [new MockExtractor(fetcher)])); const streams = await streamResolver.resolve(ctx, [new MockSource()], 'movie', new ImdbId('tt11655566', undefined, undefined)); expect(streams).toMatchSnapshot();