diff --git a/src/extractor/FileMoon.test.ts b/src/extractor/FileMoon.test.ts new file mode 100644 index 0000000..c348db6 --- /dev/null +++ b/src/extractor/FileMoon.test.ts @@ -0,0 +1,20 @@ +import winston from 'winston'; +import { createTestContext } from '../test'; +import { FetcherMock } from '../utils'; +import { ExtractorRegistry } from './ExtractorRegistry'; +import { FileMoon } from './FileMoon'; + +const logger = winston.createLogger({ transports: [new winston.transports.Console({ level: 'nope' })] }); +const extractorRegistry = new ExtractorRegistry(logger, [new FileMoon(new FetcherMock(`${__dirname}/__fixtures__/FileMoon`))]); + +const ctx = createTestContext({ mediaFlowProxyUrl: 'https://mediaflow.test.org', mediaFlowProxyPassword: 'test' }); + +describe('FileMoon', () => { + test('z1ekv717 d', async () => { + expect(await extractorRegistry.handle(ctx, new URL('https://z1ekv717.fun/d/wkhcbggdxf1d'))).toMatchSnapshot(); + }); + + test('page not found', async () => { + expect(await extractorRegistry.handle(ctx, new URL('https://filemoon.sx/e/n7i8zodwjqr9'))).toMatchSnapshot(); + }); +}); diff --git a/src/extractor/FileMoon.ts b/src/extractor/FileMoon.ts new file mode 100644 index 0000000..e72bce1 --- /dev/null +++ b/src/extractor/FileMoon.ts @@ -0,0 +1,73 @@ +import * as cheerio from 'cheerio'; +import { NotFoundError } from '../error'; +import { Context, Format, Meta, UrlResult } from '../types'; +import { buildMediaFlowProxyExtractorStreamUrl, guessHeightFromPlaylist, supportsMediaFlowProxy } from '../utils'; +import { Extractor } from './Extractor'; + +/** @see https://github.com/Gujal00/ResolveURL/blob/master/script.module.resolveurl/lib/resolveurl/plugins/filemoon.py */ +export class FileMoon extends Extractor { + public readonly id = 'filemoon'; + + public readonly label = 'FileMoon (via MediaFlow Proxy)'; + + public override viaMediaFlowProxy = true; + + public supports(ctx: Context, url: URL): boolean { + const supportedDomain = null !== url.host.match(/filemoon/) + || [ + '1azayf9w.xyz', + '222i8x.lol', + '81u6xl9d.xyz', + '8mhlloqo.fun', + '96ar.com', + 'bf0skv.org', + 'boosteradx.online', + 'c1z39.com', + 'cinegrab.com', + 'f51rm.com', + 'furher.in', + 'kerapoxy.cc', + 'l1afav.net', + 'moonmov.pro', + 'smdfs40r.skin', + 'xcoic.com', + 'z1ekv717.fun', + ].includes(url.host); + + return supportedDomain && supportsMediaFlowProxy(ctx); + } + + public override normalize(url: URL): URL { + return new URL(url.href.replace('/e/', '/d/')); + } + + protected async extractInternal(ctx: Context, url: URL, meta: Meta): Promise { + const headers = { Referer: meta.referer ?? url.href }; + + const html = await this.fetcher.text(ctx, url, { headers }); + + if (/Page not found/.test(html)) { + throw new NotFoundError(); + } + + const playlistUrl = await buildMediaFlowProxyExtractorStreamUrl(ctx, this.fetcher, 'FileMoon', url, headers); + + const $ = cheerio.load(html); + const title = $('h3').text().trim(); + + return [ + { + url: playlistUrl, + format: Format.hls, + label: this.label, + sourceId: `${this.id}_${meta.countryCodes?.join('_')}`, + ttl: this.ttl, + meta: { + ...meta, + height: await guessHeightFromPlaylist(ctx, this.fetcher, playlistUrl, { queueLimit: 4 }), + title, + }, + }, + ]; + }; +} diff --git a/src/extractor/LuluStream.test.ts b/src/extractor/LuluStream.test.ts new file mode 100644 index 0000000..dd4abdc --- /dev/null +++ b/src/extractor/LuluStream.test.ts @@ -0,0 +1,20 @@ +import winston from 'winston'; +import { createTestContext } from '../test'; +import { FetcherMock } from '../utils'; +import { ExtractorRegistry } from './ExtractorRegistry'; +import { LuluStream } from './LuluStream'; + +const logger = winston.createLogger({ transports: [new winston.transports.Console({ level: 'nope' })] }); +const extractorRegistry = new ExtractorRegistry(logger, [new LuluStream(new FetcherMock(`${__dirname}/__fixtures__/LuluStream`))]); + +const ctx = createTestContext({ mediaFlowProxyUrl: 'https://mediaflow.test.org', mediaFlowProxyPassword: 'test' }); + +describe('LuluStream', () => { + test('streamhihi d', async () => { + expect(await extractorRegistry.handle(ctx, new URL('https://streamhihi.com/d/mk9m58lz8ts6'))).toMatchSnapshot(); + }); + + test('no such file', async () => { + expect(await extractorRegistry.handle(ctx, new URL('https://lulustream.com/e/uthq0o0sljnx'))).toMatchSnapshot(); + }); +}); diff --git a/src/extractor/LuluStream.ts b/src/extractor/LuluStream.ts new file mode 100644 index 0000000..65c4057 --- /dev/null +++ b/src/extractor/LuluStream.ts @@ -0,0 +1,65 @@ +import bytes from 'bytes'; +import * as cheerio from 'cheerio'; +import { NotFoundError } from '../error'; +import { Context, Format, Meta, UrlResult } from '../types'; +import { buildMediaFlowProxyExtractorStreamUrl, guessHeightFromPlaylist, supportsMediaFlowProxy } from '../utils'; +import { Extractor } from './Extractor'; + +/** @see https://github.com/Gujal00/ResolveURL/blob/master/script.module.resolveurl/lib/resolveurl/plugins/lulustream.py */ +export class LuluStream extends Extractor { + public readonly id = 'lulustream'; + + public readonly label = 'LuluStream (via MediaFlow Proxy)'; + + public override viaMediaFlowProxy = true; + + public supports(ctx: Context, url: URL): boolean { + const supportedDomain = null !== url.host.match(/lulu/) + || [ + '732eg54de642sa.sbs', + 'cdn1.site', + 'd00ds.site', + 'streamhihi.com', + ].includes(url.host); + + return supportedDomain && supportsMediaFlowProxy(ctx); + } + + public override normalize(url: URL): URL { + return new URL(url.href.replace('/d/', '/e/')); + } + + protected async extractInternal(ctx: Context, url: URL, meta: Meta): Promise { + const headers = { Referer: meta.referer ?? url.href }; + + const fileUrl = new URL(url.href.replace('/e/', '/d/')); + const html = await this.fetcher.text(ctx, fileUrl, { headers }); + + if (/No such file/.test(html)) { + throw new NotFoundError(); + } + + const $ = cheerio.load(html); + const title = $('h1').text().trim(); + + const sizeMatch = html.match(/([\d.]+ ?[GM]B)/) as string[]; + + const playlistUrl = await buildMediaFlowProxyExtractorStreamUrl(ctx, this.fetcher, 'LuluStream', url, headers); + + return [ + { + url: playlistUrl, + format: Format.hls, + label: this.label, + sourceId: `${this.id}_${meta.countryCodes?.join('_')}`, + ttl: this.ttl, + meta: { + ...meta, + bytes: bytes.parse(sizeMatch[1] as string) as number, + height: await guessHeightFromPlaylist(ctx, this.fetcher, playlistUrl, { queueLimit: 4 }), + title, + }, + }, + ]; + }; +} diff --git a/src/extractor/Voe.test.ts b/src/extractor/Voe.test.ts new file mode 100644 index 0000000..bf268ba --- /dev/null +++ b/src/extractor/Voe.test.ts @@ -0,0 +1,20 @@ +import winston from 'winston'; +import { createTestContext } from '../test'; +import { FetcherMock } from '../utils'; +import { ExtractorRegistry } from './ExtractorRegistry'; +import { Voe } from './Voe'; + +const logger = winston.createLogger({ transports: [new winston.transports.Console({ level: 'nope' })] }); +const extractorRegistry = new ExtractorRegistry(logger, [new Voe(new FetcherMock(`${__dirname}/__fixtures__/Voe`))]); + +const ctx = createTestContext({ mediaFlowProxyUrl: 'https://mediaflow.test.org', mediaFlowProxyPassword: 'test' }); + +describe('Voe', () => { + test('jilliandescribecompany', async () => { + expect(await extractorRegistry.handle(ctx, new URL('https://jilliandescribecompany.com/e/ea21l02gcygw'))).toMatchSnapshot(); + }); + + test('encoding error', async () => { + expect(await extractorRegistry.handle(ctx, new URL('https://voe.sx/e/c2yxvit4f6bz'))).toMatchSnapshot(); + }); +}); diff --git a/src/extractor/Voe.ts b/src/extractor/Voe.ts new file mode 100644 index 0000000..012cd6b --- /dev/null +++ b/src/extractor/Voe.ts @@ -0,0 +1,151 @@ +import * as cheerio from 'cheerio'; +import { NotFoundError } from '../error'; +import { Context, Format, Meta, UrlResult } from '../types'; +import { buildMediaFlowProxyExtractorStreamUrl, guessHeightFromPlaylist, supportsMediaFlowProxy } from '../utils'; +import { Extractor } from './Extractor'; + +/** @see https://github.com/Gujal00/ResolveURL/blob/master/script.module.resolveurl/lib/resolveurl/plugins/voesx.py */ +export class Voe extends Extractor { + public readonly id = 'voe'; + + public readonly label = 'VOE (via MediaFlow Proxy)'; + + public override viaMediaFlowProxy = true; + + public supports(ctx: Context, url: URL): boolean { + const supportedDomain = null !== url.host.match(/voe/) + || [ + '19turanosephantasia.com', + '20demidistance9elongations.com', + '30sensualizeexpression.com', + '321naturelikefurfuroid.com', + '35volitantplimsoles5.com', + '449unceremoniousnasoseptal.com', + '745mingiestblissfully.com', + 'adrianmissionminute.com', + 'alleneconomicmatter.com', + 'antecoxalbobbing1010.com', + 'apinchcaseation.com', + 'audaciousdefaulthouse.com', + 'availedsmallest.com', + 'bigclatterhomesguideservice.com', + 'boonlessbestselling244.com', + 'bradleyviewdoctor.com', + 'brittneystandardwestern.com', + 'brucevotewithin.com', + 'chromotypic.com', + 'chuckle-tube.com', + 'cindyeyefinal.com', + 'counterclockwisejacky.com', + 'crownmakermacaronicism.com', + 'cyamidpulverulence530.com', + 'diananatureforeign.com', + 'donaldlineelse.com', + 'edwardarriveoften.com', + 'erikcoldperson.com', + 'figeterpiazine.com', + 'fittingcentermondaysunday.com', + 'fraudclatterflyingcar.com', + 'gamoneinterrupted.com', + 'generatesnitrosate.com', + 'graceaddresscommunity.com', + 'greaseball6eventual20.com', + 'guidon40hyporadius9.com', + 'heatherdiscussionwhen.com', + 'housecardsummerbutton.com', + 'jamessoundcost.com', + 'jamiesamewalk.com', + 'jasminetesttry.com', + 'jayservicestuff.com', + 'jennifercertaindevelopment.com', + 'jilliandescribecompany.com', + 'johnalwayssame.com', + 'jonathansociallike.com', + 'josephseveralconcern.com', + 'kathleenmemberhistory.com', + 'kellywhatcould.com', + 'kennethofficialitem.com', + 'kristiesoundsimply.com', + 'launchreliantcleaverriver.com', + 'lisatrialidea.com', + 'loriwithinfamily.com', + 'lukecomparetwo.com', + 'mariatheserepublican.com', + 'matriculant401merited.com', + 'maxfinishseveral.com', + 'metagnathtuggers.com', + 'michaelapplysome.com', + 'nathanfromsubject.com', + 'nectareousoverelate.com', + 'nonesnanking.com', + 'paulkitchendark.com', + 'realfinanceblogcenter.com', + 'rebeccaneverbase.com', + 'reputationsheriffkennethsand.com', + 'richardsignfish.com', + 'roberteachfinal.com', + 'robertordercharacter.com', + 'robertplacespace.com', + 'sandratableother.com', + 'sandrataxeight.com', + 'scatch176duplicities.com', + 'sethniceletter.com', + 'shannonpersonalcost.com', + 'simpulumlamerop.com', + 'stevenimaginelittle.com', + 'strawberriesporail.com', + 'telyn610zoanthropy.com', + 'timberwoodanotia.com', + 'toddpartneranimal.com', + 'toxitabellaeatrebates306.com', + 'uptodatefinishconferenceroom.com', + 'v-o-e-unblock.com', + 'valeronevijao.com', + 'wolfdyslectic.com', + 'yodelswartlike.com', + ].includes(url.host); + + return supportedDomain && supportsMediaFlowProxy(ctx); + } + + public override normalize(url: URL): URL { + const videoId = url.pathname.split('/').slice(-1)[0] as string; + + return new URL(`/e/${videoId}`, url); + } + + protected async extractInternal(ctx: Context, url: URL, meta: Meta): Promise { + const headers = { Referer: meta.referer ?? url.href }; + + const html = await this.fetcher.text(ctx, url, { headers }); + + const redirectMatch = html.match(/window\.location\.href\s*=\s*'([^']+)/); + if (redirectMatch && redirectMatch[1]) { + return await this.extractInternal(ctx, new URL(redirectMatch[1]), meta); + } + + if (/An error occurred during encoding/.test(html)) { + throw new NotFoundError(); + } + + const $ = cheerio.load(html); + const title = $('meta[name="description"]').attr('content')?.trim().replace(/^Watch /, '').replace(/ at VOE$/, '').trim(); + + const playlistUrl = await buildMediaFlowProxyExtractorStreamUrl(ctx, this.fetcher, 'Voe', url, headers); + + return [ + { + url: playlistUrl, + format: Format.hls, + label: this.label, + sourceId: `${this.id}_${meta.countryCodes?.join('_')}`, + ttl: this.ttl, + meta: { + ...meta, + height: await guessHeightFromPlaylist(ctx, this.fetcher, playlistUrl, { queueLimit: 4 }), + title, + }, + }, + ]; + }; +} diff --git a/src/extractor/__fixtures__/FileMoon/https:filemoon.sxdn7i8zodwjqr9 b/src/extractor/__fixtures__/FileMoon/https:filemoon.sxdn7i8zodwjqr9 new file mode 100644 index 0000000..1ffa0cc --- /dev/null +++ b/src/extractor/__fixtures__/FileMoon/https:filemoon.sxdn7i8zodwjqr9 @@ -0,0 +1,57 @@ + + + + + + + Not Found + + + + + + + + + + + + + +
ad
+ + +
+
+ +
+
+ + diff --git a/src/extractor/__fixtures__/FileMoon/https:mediaflow.test.org-2df9a69a7a01fb3f2f7e847df89895d0 b/src/extractor/__fixtures__/FileMoon/https:mediaflow.test.org-2df9a69a7a01fb3f2f7e847df89895d0 new file mode 100644 index 0000000..b646af4 --- /dev/null +++ b/src/extractor/__fixtures__/FileMoon/https:mediaflow.test.org-2df9a69a7a01fb3f2f7e847df89895d0 @@ -0,0 +1,4 @@ +#EXTM3U +#EXT-X-STREAM-INF:PROGRAM-ID=1,BANDWIDTH=853331,RESOLUTION=1280x720,FRAME-RATE=24.000,CODECS="avc1.64001f,mp4a.40.2",VIDEO-RANGE=SDR +https://mediaflow.test.org/proxy/hls/manifest.m3u8?api_password=test&h_user-agent=Mozilla%2F5.0+%28Windows+NT+10.0%3B+Win64%3B+x64%29+AppleWebKit%2F537.36+%28KHTML%2C+like+Gecko%29+Chrome%2F136.0.0.0+Safari%2F537.36&h_referer=https%3A%2F%2Fz1ekv717.fun%2Fd%2Fwkhcbggdxf1d&d=https%3A%2F%2Fbe7713.rcr82.waw05.i8yz83pn.com%2Fhls2%2F01%2F09665%2Fwkhcbggdxf1d_h%2Findex-v1-a1.m3u8%3Ft%3D359izbQ_L-sOHaIjj275YKdBDyiPzUi3ETfbNoN9bzU%26s%3D1759754698%26e%3D10800%26f%3D48329866%26srv%3D1075%26asn%3D13335%26sp%3D4000%26p%3D +#EXT-X-I-FRAME-STREAM-INF:BANDWIDTH=49442,RESOLUTION=1280x720,CODECS="avc1.64001f",URI="https://mediaflow.test.org/proxy/hls/manifest.m3u8?api_password=test&h_user-agent=Mozilla%2F5.0+%28Windows+NT+10.0%3B+Win64%3B+x64%29+AppleWebKit%2F537.36+%28KHTML%2C+like+Gecko%29+Chrome%2F136.0.0.0+Safari%2F537.36&h_referer=https%3A%2F%2Fz1ekv717.fun%2Fd%2Fwkhcbggdxf1d&d=https%3A%2F%2Fbe7713.rcr82.waw05.i8yz83pn.com%2Fhls2%2F01%2F09665%2Fwkhcbggdxf1d_h%2Fiframes-v1-a1.m3u8%3Ft%3D359izbQ_L-sOHaIjj275YKdBDyiPzUi3ETfbNoN9bzU%26s%3D1759754698%26e%3D10800%26f%3D48329866%26srv%3D1075%26asn%3D13335%26sp%3D4000%26p%3D",VIDEO-RANGE=SDR diff --git a/src/extractor/__fixtures__/FileMoon/https:mediaflow.test.orgextractorvideohostFileMoonandapi_passwordtestanddhttpspercent3Apercent2Fpercent2Fz1ekv717.funpercent2Fdpercent2Fwkhcbggdxf1dandh_refererhttpspercent3Apercent2Fpercent2Fz1ekv717.funpercent2Fdpercent2Fwkhcbggdxf1d b/src/extractor/__fixtures__/FileMoon/https:mediaflow.test.orgextractorvideohostFileMoonandapi_passwordtestanddhttpspercent3Apercent2Fpercent2Fz1ekv717.funpercent2Fdpercent2Fwkhcbggdxf1dandh_refererhttpspercent3Apercent2Fpercent2Fz1ekv717.funpercent2Fdpercent2Fwkhcbggdxf1d new file mode 100644 index 0000000..31e8eec --- /dev/null +++ b/src/extractor/__fixtures__/FileMoon/https:mediaflow.test.orgextractorvideohostFileMoonandapi_passwordtestanddhttpspercent3Apercent2Fpercent2Fz1ekv717.funpercent2Fdpercent2Fwkhcbggdxf1dandh_refererhttpspercent3Apercent2Fpercent2Fz1ekv717.funpercent2Fdpercent2Fwkhcbggdxf1d @@ -0,0 +1 @@ +{"destination_url":"https://be7713.rcr82.waw05.i8yz83pn.com/hls2/01/09665/wkhcbggdxf1d_h/master.m3u8?t=359izbQ_L-sOHaIjj275YKdBDyiPzUi3ETfbNoN9bzU&s=1759754698&e=10800&f=48329866&srv=1075&asn=13335&sp=4000&p=","request_headers":{"user-agent":"Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/136.0.0.0 Safari/537.36","referer":"https://z1ekv717.fun/d/wkhcbggdxf1d"},"mediaflow_proxy_url":"https://mediaflow.test.org/proxy/hls/manifest.m3u8","query_params":{"api_password":"test"}} diff --git a/src/extractor/__fixtures__/FileMoon/https:z1ekv717.fundwkhcbggdxf1d b/src/extractor/__fixtures__/FileMoon/https:z1ekv717.fundwkhcbggdxf1d new file mode 100644 index 0000000..9ca6a83 --- /dev/null +++ b/src/extractor/__fixtures__/FileMoon/https:z1ekv717.fundwkhcbggdxf1d @@ -0,0 +1,226 @@ + + + + + + + Watch alien earth s01e01 1080p web h264 successfulcrab + + + + + + + + + + + + + + + + + + + + + +
+
+
+
+ +
+
+ +
+
+ +
+
+
+ + Log In + Sign Up + +
+
+ +
+
+
+
+
+ + + + + + +
+
+
+
+
+

alien earth s01e01 1080p web h264-successfulcrab

+
+
Uploaded: 2025-08-13 00:08:29 +
+
+
+
+ +
+
+ + + +
+
+ + + +
+
+ +
+ + + +
+ +
+
+ + + +
+
+ + + +
+
+ +
+
+ + +
+ Download +
+ + +
+
+
+ + + + + + +
+
+ + Sign in + Sign up + +
+ + + + + + + diff --git a/src/extractor/__fixtures__/LuluStream/https:lulustream.comduthq0o0sljnx b/src/extractor/__fixtures__/LuluStream/https:lulustream.comduthq0o0sljnx new file mode 100644 index 0000000..661cc1e --- /dev/null +++ b/src/extractor/__fixtures__/LuluStream/https:lulustream.comduthq0o0sljnx @@ -0,0 +1,147 @@ + + + + + + LuluStream + + + + + + + + + + + + + + + + + + + + + + + +
+
+
+
+
+ +
+ +
+ +
+
+ + +
+ + Register +
+
+ +
+ + + +
+
+
+ + +
+ +
+
+ +
+ No such file=uthq0o0sljnx +
+ + +
+
+
+ + + + \ No newline at end of file diff --git a/src/extractor/__fixtures__/LuluStream/https:mediaflow.test.org-a2f2340c4a16e932bc5ea0c234dda69f b/src/extractor/__fixtures__/LuluStream/https:mediaflow.test.org-a2f2340c4a16e932bc5ea0c234dda69f new file mode 100644 index 0000000..16e8603 --- /dev/null +++ b/src/extractor/__fixtures__/LuluStream/https:mediaflow.test.org-a2f2340c4a16e932bc5ea0c234dda69f @@ -0,0 +1,4 @@ +#EXTM3U +#EXT-X-STREAM-INF:PROGRAM-ID=1,BANDWIDTH=1498884,RESOLUTION=1280x720,FRAME-RATE=24.000,CODECS="avc1.4d401f,mp4a.40.2" +https://mediaflow.test.org/proxy/hls/manifest.m3u8?api_password=test&h_user-agent=Mozilla%2F5.0+%28Windows+NT+10.0%3B+Win64%3B+x64%29+AppleWebKit%2F537.36+%28KHTML%2C+like+Gecko%29+Chrome%2F136.0.0.0+Safari%2F537.36&h_referer=https%3A%2F%2Fstreamhihi.com%2Fe%2Fmk9m58lz8ts6&d=https%3A%2F%2Fh1gdnnp1dr11.tnmr.org%2Fhls2%2F02%2F02416%2Fqx1ysro2ny1o_h%2Findex-v1-a1.m3u8%3Ft%3DC1RS64a-9j6bSDO9TmHU9jIZpVb59jsWah7j-KgJkRg%26s%3D1759753708%26e%3D28800%26f%3D12081096%26i%3D0.3%26sp%3D0 +#EXT-X-I-FRAME-STREAM-INF:BANDWIDTH=41327,RESOLUTION=1280x720,CODECS="avc1.4d401f",URI="https://mediaflow.test.org/proxy/hls/manifest.m3u8?api_password=test&h_user-agent=Mozilla%2F5.0+%28Windows+NT+10.0%3B+Win64%3B+x64%29+AppleWebKit%2F537.36+%28KHTML%2C+like+Gecko%29+Chrome%2F136.0.0.0+Safari%2F537.36&h_referer=https%3A%2F%2Fstreamhihi.com%2Fe%2Fmk9m58lz8ts6&d=https%3A%2F%2Fh1gdnnp1dr11.tnmr.org%2Fhls2%2F02%2F02416%2Fqx1ysro2ny1o_h%2Fiframes-v1-a1.m3u8%3Ft%3DC1RS64a-9j6bSDO9TmHU9jIZpVb59jsWah7j-KgJkRg%26s%3D1759753708%26e%3D28800%26f%3D12081096%26i%3D0.3%26sp%3D0" diff --git a/src/extractor/__fixtures__/LuluStream/https:mediaflow.test.orgextractorvideohostLuluStreamandapi_passwordtestanddhttpspercent3Apercent2Fpercent2Fstreamhihi.compercent2Fepercent2Fmk9m58lz8ts6andh_refererhttpspercent3Apercent2Fpercent2Fstreamhihi.compercent2Fepercent2Fmk9m58lz8ts6 b/src/extractor/__fixtures__/LuluStream/https:mediaflow.test.orgextractorvideohostLuluStreamandapi_passwordtestanddhttpspercent3Apercent2Fpercent2Fstreamhihi.compercent2Fepercent2Fmk9m58lz8ts6andh_refererhttpspercent3Apercent2Fpercent2Fstreamhihi.compercent2Fepercent2Fmk9m58lz8ts6 new file mode 100644 index 0000000..dc69182 --- /dev/null +++ b/src/extractor/__fixtures__/LuluStream/https:mediaflow.test.orgextractorvideohostLuluStreamandapi_passwordtestanddhttpspercent3Apercent2Fpercent2Fstreamhihi.compercent2Fepercent2Fmk9m58lz8ts6andh_refererhttpspercent3Apercent2Fpercent2Fstreamhihi.compercent2Fepercent2Fmk9m58lz8ts6 @@ -0,0 +1 @@ +{"destination_url":"https://h1gdnnp1dr11.tnmr.org/hls2/02/02416/qx1ysro2ny1o_h/master.m3u8?t=C1RS64a-9j6bSDO9TmHU9jIZpVb59jsWah7j-KgJkRg&s=1759753708&e=28800&f=12081096&i=0.3&sp=0","request_headers":{"user-agent":"Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/136.0.0.0 Safari/537.36","referer":"https://streamhihi.com/e/mk9m58lz8ts6"},"mediaflow_proxy_url":"https://mediaflow.test.org/proxy/hls/manifest.m3u8","query_params":{"api_password":"test"}} diff --git a/src/extractor/__fixtures__/LuluStream/https:streamhihi.comdmk9m58lz8ts6 b/src/extractor/__fixtures__/LuluStream/https:streamhihi.comdmk9m58lz8ts6 new file mode 100644 index 0000000..1fd364f --- /dev/null +++ b/src/extractor/__fixtures__/LuluStream/https:streamhihi.comdmk9m58lz8ts6 @@ -0,0 +1,529 @@ + + + + + + The.Thursday.Murder.Club.2025.1080p.NF.WEB-DL.DDP5.1.Atmos.H.264-playWEB - Lulustream.mp4 + + + + + + + + + + + + + + + + + + + + + + + + + +
+
+
+
+
+ +
+ +
+ +
+
+ + +
+ + Register +
+
+ +
+ + + +
+
+
+ + +
+ +
+
+
+ + + + + +
+ +
+
+
+
+ +
+

The Thursday Murder Club 2025 1080p NF WEB-DL DDP5 1 Atmos H 264-playWEB

+
+ on Aug 28, 2025 + + 1.2 GB +
+
+ +
+
+ +
+ + + +
+ +
+ + + +
+ + + + +
+
+ + +
+ +
+ +
+
+ +
+
+
Embed size: x
+ +
+
+ +
+ + + + + + + + + + + + + + + + +
+
+
+
+ + + diff --git a/src/extractor/__fixtures__/Voe/https:jilliandescribecompany.comec2yxvit4f6bz b/src/extractor/__fixtures__/Voe/https:jilliandescribecompany.comec2yxvit4f6bz new file mode 100644 index 0000000..dd8af9e --- /dev/null +++ b/src/extractor/__fixtures__/Voe/https:jilliandescribecompany.comec2yxvit4f6bz @@ -0,0 +1,71 @@ + + + + + Watch Une bataille après l'autre (2025).mp4 - VOE | Content Delivery Network (CDN) & Video Cloud + + + + + + + + + + + + + + + + + + + +
+ + + + An error occurred during encoding. +
+ + + + + + + + + + + + + + + + + diff --git a/src/extractor/__fixtures__/Voe/https:jilliandescribecompany.comeea21l02gcygw b/src/extractor/__fixtures__/Voe/https:jilliandescribecompany.comeea21l02gcygw new file mode 100644 index 0000000..1a08ec1 --- /dev/null +++ b/src/extractor/__fixtures__/Voe/https:jilliandescribecompany.comeea21l02gcygw @@ -0,0 +1,204 @@ + + + + + Watch Superman.2025.2160p.WEB-DL.DV.HDR10Plus.X265.DDP5.1.Atmos-YIN.mp4 - VOE | Content Delivery Network (CDN) & Video Cloud + + + + + + + + + + + + + + + + + + + +
+ + + + + + + + +
+
+
+
+
+
+ +
+ + + + + +
+ + + + + + + + + + + + + + + + + diff --git a/src/extractor/__fixtures__/Voe/https:mediaflow.test.org-69b2d6ce0f425db5b27748c3e67b81eb b/src/extractor/__fixtures__/Voe/https:mediaflow.test.org-69b2d6ce0f425db5b27748c3e67b81eb new file mode 100644 index 0000000..6e34ff7 --- /dev/null +++ b/src/extractor/__fixtures__/Voe/https:mediaflow.test.org-69b2d6ce0f425db5b27748c3e67b81eb @@ -0,0 +1 @@ +{"destination_url":"https://cdn-kuc3ehpz4wnczfyz.orbitcache.com/engine/hls2-c/01/15242/ea21l02gcygw_,n,.urlset/master.m3u8?t=3iMAKoJqij6nC4HDamYxtDB75a_-AlG_wD1demRBo0I&s=1759754183&e=14400&f=76213694&node=FPYruvgfgORaUYuYfpByMgjFbC8X/HWKW1utbUQQRyQ=&i=104.28&sp=2500&asn=13335&q=n&rq=zKNpONzQJHzTeXTzr0V2M9V4DUnzwX9C8hTNxrUW","request_headers":{"user-agent":"Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/136.0.0.0 Safari/537.36","referer":"https://jilliandescribecompany.com/e/ea21l02gcygw"},"mediaflow_proxy_url":"https://mediaflow.test.org/proxy/hls/manifest.m3u8","query_params":{"api_password":"test"}} diff --git a/src/extractor/__fixtures__/Voe/https:mediaflow.test.org-f60f1c6427ad36dfca849557f64c724f b/src/extractor/__fixtures__/Voe/https:mediaflow.test.org-f60f1c6427ad36dfca849557f64c724f new file mode 100644 index 0000000..b129838 --- /dev/null +++ b/src/extractor/__fixtures__/Voe/https:mediaflow.test.org-f60f1c6427ad36dfca849557f64c724f @@ -0,0 +1,4 @@ +#EXTM3U +#EXT-X-STREAM-INF:PROGRAM-ID=1,BANDWIDTH=1186371,RESOLUTION=1368x720,FRAME-RATE=24.000,CODECS="avc1.640020,mp4a.40.2",VIDEO-RANGE=PQ +https://mediaflow.test.org/proxy/hls/manifest.m3u8?api_password=test&h_user-agent=Mozilla%2F5.0+%28Windows+NT+10.0%3B+Win64%3B+x64%29+AppleWebKit%2F537.36+%28KHTML%2C+like+Gecko%29+Chrome%2F136.0.0.0+Safari%2F537.36&h_referer=https%3A%2F%2Fjilliandescribecompany.com%2Fe%2Fea21l02gcygw&d=https%3A%2F%2Fcdn-kuc3ehpz4wnczfyz.orbitcache.com%2Fengine%2Fhls2-c%2F01%2F15242%2Fea21l02gcygw_%2Cn%2C.urlset%2Findex-v1-a1.m3u8%3Ft%3D3iMAKoJqij6nC4HDamYxtDB75a_-AlG_wD1demRBo0I%26s%3D1759754183%26e%3D14400%26f%3D76213694%26node%3DFPYruvgfgORaUYuYfpByMgjFbC8X%2FHWKW1utbUQQRyQ%3D%26i%3D104.28%26sp%3D2500%26asn%3D13335%26q%3Dn%26rq%3DzKNpONzQJHzTeXTzr0V2M9V4DUnzwX9C8hTNxrUW +#EXT-X-I-FRAME-STREAM-INF:BANDWIDTH=25403,RESOLUTION=1368x720,CODECS="avc1.640020",URI="https://mediaflow.test.org/proxy/hls/manifest.m3u8?api_password=test&h_user-agent=Mozilla%2F5.0+%28Windows+NT+10.0%3B+Win64%3B+x64%29+AppleWebKit%2F537.36+%28KHTML%2C+like+Gecko%29+Chrome%2F136.0.0.0+Safari%2F537.36&h_referer=https%3A%2F%2Fjilliandescribecompany.com%2Fe%2Fea21l02gcygw&d=https%3A%2F%2Fcdn-kuc3ehpz4wnczfyz.orbitcache.com%2Fengine%2Fhls2-c%2F01%2F15242%2Fea21l02gcygw_%2Cn%2C.urlset%2Fiframes-v1-a1.m3u8%3Ft%3D3iMAKoJqij6nC4HDamYxtDB75a_-AlG_wD1demRBo0I%26s%3D1759754183%26e%3D14400%26f%3D76213694%26node%3DFPYruvgfgORaUYuYfpByMgjFbC8X%2FHWKW1utbUQQRyQ%3D%26i%3D104.28%26sp%3D2500%26asn%3D13335%26q%3Dn%26rq%3DzKNpONzQJHzTeXTzr0V2M9V4DUnzwX9C8hTNxrUW",VIDEO-RANGE=PQ diff --git a/src/extractor/__fixtures__/Voe/https:voe.sxec2yxvit4f6bz b/src/extractor/__fixtures__/Voe/https:voe.sxec2yxvit4f6bz new file mode 100644 index 0000000..ef365f5 --- /dev/null +++ b/src/extractor/__fixtures__/Voe/https:voe.sxec2yxvit4f6bz @@ -0,0 +1,23 @@ + + + + + Redirecting... + + + + + \ No newline at end of file diff --git a/src/extractor/__snapshots__/FileMoon.test.ts.snap b/src/extractor/__snapshots__/FileMoon.test.ts.snap new file mode 100644 index 0000000..9a25799 --- /dev/null +++ b/src/extractor/__snapshots__/FileMoon.test.ts.snap @@ -0,0 +1,20 @@ +// Jest Snapshot v1, https://jestjs.io/docs/snapshot-testing + +exports[`FileMoon page not found 1`] = `[]`; + +exports[`FileMoon z1ekv717 d 1`] = ` +[ + { + "format": "hls", + "label": "FileMoon (via MediaFlow Proxy)", + "meta": { + "countryCodes": [], + "height": 720, + "title": "alien earth s01e01 1080p web h264-successfulcrab", + }, + "sourceId": "filemoon_", + "ttl": 900000, + "url": "https://mediaflow.test.org/proxy/hls/manifest.m3u8?api_password=test&h_user-agent=Mozilla%2F5.0+%28Windows+NT+10.0%3B+Win64%3B+x64%29+AppleWebKit%2F537.36+%28KHTML%2C+like+Gecko%29+Chrome%2F136.0.0.0+Safari%2F537.36&h_referer=https%3A%2F%2Fz1ekv717.fun%2Fd%2Fwkhcbggdxf1d&d=https%3A%2F%2Fbe7713.rcr82.waw05.i8yz83pn.com%2Fhls2%2F01%2F09665%2Fwkhcbggdxf1d_h%2Fmaster.m3u8%3Ft%3D359izbQ_L-sOHaIjj275YKdBDyiPzUi3ETfbNoN9bzU%26s%3D1759754698%26e%3D10800%26f%3D48329866%26srv%3D1075%26asn%3D13335%26sp%3D4000%26p%3D", + }, +] +`; diff --git a/src/extractor/__snapshots__/LuluStream.test.ts.snap b/src/extractor/__snapshots__/LuluStream.test.ts.snap new file mode 100644 index 0000000..f2d5c98 --- /dev/null +++ b/src/extractor/__snapshots__/LuluStream.test.ts.snap @@ -0,0 +1,21 @@ +// Jest Snapshot v1, https://jestjs.io/docs/snapshot-testing + +exports[`LuluStream no such file 1`] = `[]`; + +exports[`LuluStream streamhihi d 1`] = ` +[ + { + "format": "hls", + "label": "LuluStream (via MediaFlow Proxy)", + "meta": { + "bytes": 1288490188, + "countryCodes": [], + "height": 720, + "title": "The Thursday Murder Club 2025 1080p NF WEB-DL DDP5 1 Atmos H 264-playWEB", + }, + "sourceId": "lulustream_", + "ttl": 900000, + "url": "https://mediaflow.test.org/proxy/hls/manifest.m3u8?api_password=test&h_user-agent=Mozilla%2F5.0+%28Windows+NT+10.0%3B+Win64%3B+x64%29+AppleWebKit%2F537.36+%28KHTML%2C+like+Gecko%29+Chrome%2F136.0.0.0+Safari%2F537.36&h_referer=https%3A%2F%2Fstreamhihi.com%2Fe%2Fmk9m58lz8ts6&d=https%3A%2F%2Fh1gdnnp1dr11.tnmr.org%2Fhls2%2F02%2F02416%2Fqx1ysro2ny1o_h%2Fmaster.m3u8%3Ft%3DC1RS64a-9j6bSDO9TmHU9jIZpVb59jsWah7j-KgJkRg%26s%3D1759753708%26e%3D28800%26f%3D12081096%26i%3D0.3%26sp%3D0", + }, +] +`; diff --git a/src/extractor/__snapshots__/Voe.test.ts.snap b/src/extractor/__snapshots__/Voe.test.ts.snap new file mode 100644 index 0000000..56c54c8 --- /dev/null +++ b/src/extractor/__snapshots__/Voe.test.ts.snap @@ -0,0 +1,20 @@ +// Jest Snapshot v1, https://jestjs.io/docs/snapshot-testing + +exports[`Voe encoding error 1`] = `[]`; + +exports[`Voe jilliandescribecompany 1`] = ` +[ + { + "format": "hls", + "label": "VOE (via MediaFlow Proxy)", + "meta": { + "countryCodes": [], + "height": 720, + "title": "Superman.2025.2160p.WEB-DL.DV.HDR10Plus.X265.DDP5.1.Atmos-YIN.mp4", + }, + "sourceId": "voe_", + "ttl": 900000, + "url": "https://mediaflow.test.org/proxy/hls/manifest.m3u8?api_password=test&h_user-agent=Mozilla%2F5.0+%28Windows+NT+10.0%3B+Win64%3B+x64%29+AppleWebKit%2F537.36+%28KHTML%2C+like+Gecko%29+Chrome%2F136.0.0.0+Safari%2F537.36&h_referer=https%3A%2F%2Fjilliandescribecompany.com%2Fe%2Fea21l02gcygw&d=https%3A%2F%2Fcdn-kuc3ehpz4wnczfyz.orbitcache.com%2Fengine%2Fhls2-c%2F01%2F15242%2Fea21l02gcygw_%2Cn%2C.urlset%2Fmaster.m3u8%3Ft%3D3iMAKoJqij6nC4HDamYxtDB75a_-AlG_wD1demRBo0I%26s%3D1759754183%26e%3D14400%26f%3D76213694%26node%3DFPYruvgfgORaUYuYfpByMgjFbC8X%2FHWKW1utbUQQRyQ%3D%26i%3D104.28%26sp%3D2500%26asn%3D13335%26q%3Dn%26rq%3DzKNpONzQJHzTeXTzr0V2M9V4DUnzwX9C8hTNxrUW", + }, +] +`; diff --git a/src/extractor/index.ts b/src/extractor/index.ts index a0b048f..d4a6329 100644 --- a/src/extractor/index.ts +++ b/src/extractor/index.ts @@ -5,8 +5,10 @@ import { ExternalUrl } from './ExternalUrl'; import { Extractor } from './Extractor'; import { Fastream } from './Fastream'; import { FileLions } from './FileLions'; +import { FileMoon } from './FileMoon'; import { HubCloud } from './HubCloud'; import { KinoGer } from './KinoGer'; +import { LuluStream } from './LuluStream'; import { Mixdrop } from './Mixdrop'; import { SaveFiles } from './SaveFiles'; import { Soaper } from './Soaper'; @@ -16,6 +18,7 @@ import { SuperVideo } from './SuperVideo'; import { Uqload } from './Uqload'; import { VidSrc } from './VidSrc'; import { VixSrc } from './VixSrc'; +import { Voe } from './Voe'; import { YouTube } from './YouTube'; export * from './Extractor'; @@ -29,8 +32,10 @@ export const createExtractors = (fetcher: Fetcher): Extractor[] => { new Dropload(fetcher), new Fastream(fetcher), new FileLions(fetcher), + new FileMoon(fetcher), new HubCloud(fetcher), new KinoGer(fetcher), + new LuluStream(fetcher), new Mixdrop(fetcher), new SaveFiles(fetcher), new Soaper(fetcher), @@ -52,6 +57,7 @@ export const createExtractors = (fetcher: Fetcher): Extractor[] => { 'xyz', ]), new VixSrc(fetcher), + new Voe(fetcher), new YouTube(fetcher), new ExternalUrl(fetcher), // fallback extractor which must come last ].filter(extractor => !disabledExtractors.includes(extractor.id));