feat(extractor): implement Mixdrop via MediaFlow Proxy

This commit is contained in:
WebStreamr 2025-06-19 20:30:33 +00:00
parent 0f415b7521
commit 7c600427e6
No known key found for this signature in database
11 changed files with 582 additions and 2 deletions

View file

@ -31,7 +31,7 @@ export class ExtractorRegistry {
urlResults = await extractor.extract(ctx, normalizedUrl, countryCode, title);
if (!urlResults.some(urlResult => urlResult.error)) {
if (!urlResults.some(urlResult => urlResult.error) && extractor.ttl) {
this.urlResultCache.set(normalizedUrl.href, urlResults, { ttl: extractor.ttl });
}

View file

@ -0,0 +1,21 @@
import winston from 'winston';
import { FetcherMock } from '../utils';
import { CountryCode } from '../types';
import { ExtractorRegistry } from './ExtractorRegistry';
import { Mixdrop } from './Mixdrop';
import { createTestContext } from '../test';
const logger = winston.createLogger({ transports: [new winston.transports.Console({ level: 'nope' })] });
const extractorRegistry = new ExtractorRegistry(logger, [new Mixdrop(new FetcherMock(`${__dirname}/__fixtures__/Mixdrop`))]);
const ctx = createTestContext({ mediaFlowProxyUrl: 'https://mediaflow-proxy.test', mediaFlowProxyPassword: 'asdfg' });
describe('Mixdrop', () => {
test('mixdrop.my /e/', async () => {
expect(await extractorRegistry.handle(ctx, new URL('https://mixdrop.my/e/knq0kj8waq44l8'), CountryCode.de)).toMatchSnapshot();
});
test('deleted or expired file', async () => {
expect(await extractorRegistry.handle(ctx, new URL('https://mixdrop.ag/e/123456789'), CountryCode.de)).toMatchSnapshot();
});
});

56
src/extractor/Mixdrop.ts Normal file
View file

@ -0,0 +1,56 @@
import bytes from 'bytes';
import * as cheerio from 'cheerio';
import { Extractor } from './Extractor';
import { buildMediaFlowProxyUrl, Fetcher, hasMediaFlowProxy } from '../utils';
import { Context, CountryCode, UrlResult } from '../types';
import { NotFoundError } from '../error';
export class Mixdrop extends Extractor {
public readonly id = 'mixdrop';
public readonly label = 'Mixdrop';
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(/mixdrop/) && hasMediaFlowProxy(ctx.config);
}
protected async extractInternal(ctx: Context, url: URL, countryCode: CountryCode): Promise<UrlResult[]> {
const fileUrl = new URL(url.href.replace('/e/', '/f/'));
const html = await this.fetcher.text(ctx, fileUrl);
if (/can't find the (file|video)/.test(html)) {
throw new NotFoundError();
}
const sizeMatch = html.match(/([\d.,]+ ?[GM]B)/);
const $ = cheerio.load(html);
const title = $('.title b').text().trim();
return [
{
url: buildMediaFlowProxyUrl(ctx.config, 'Mixdrop', url),
label: this.label,
sourceId: `${this.id}_${countryCode}`,
ttl: this.ttl,
meta: {
countryCode,
title,
...(sizeMatch && {
bytes: bytes.parse((sizeMatch[1] as string).replace(',', '')) as number,
}),
},
},
];
};
}

View file

@ -0,0 +1,192 @@
<!DOCTYPE html>
<html lang="en">
<head>
<meta http-equiv="Content-Type" content="text/html; charset=utf-8" />
<meta http-equiv="X-UA-Compatible" content="IE=edge,chrome=1" />
<meta name="viewport" content="width=device-width; initial-scale=1.0">
<title>MixDrop - File not found</title>
<meta name="description" content="" />
<meta name="keywords" content="mixdrop,share file,share video,upload file,upload video" />
<meta property="og:title" content="MixDrop - File not found" />
<meta property="og:description" content="" />
<meta name="verified-code" content="035b8906-2381-4a3a-9d4c-3b2ae07293e4">
<!--<meta name="robots" content="nosnippet">-->
<meta name="a.validate.02" content="ctm1Vhh9zx0o7ew5xlkxmA8MjHBDjK2gY_5x" />
<link rel="icon" type="image/png" href="/imgs/v2/favicon-32x32.png" sizes="32x32" />
<link rel="icon" type="image/png" href="/imgs/v2/favicon-16x16.png" sizes="16x16" />
<meta name="csrf" content="9e0a3388f70e9e3704f7ffb9f1cd84dc">
<meta name="clckd" content="ebd626d580ab61986c788e761c305e41" />
<meta name="monetag" content="d1dda856d50c7dd239c4daa5c545e3d3">
<meta name="41e891e66eaaca8fc8294c24cc35a2b1eee3aa09" content="41e891e66eaaca8fc8294c24cc35a2b1eee3aa09" />
<link rel="stylesheet" href="/js/slidebars/slidebars.css?v=0.1" />
<link rel="stylesheet" href="/css/style.v2.0.2.min.css" />
<script src="https://code.jquery.com/jquery-3.6.4.min.js" integrity="sha256-oP6HI9z1XaZNBrJURtCoUT5SUnxFr8s3BzRl+cbzUq8=" crossorigin="anonymous"></script>
</head>
<body>
<div class="container" canvas="container">
<div class="panel header">
<div class="wrapper">
<a href="/"><img src="/imgs/v2/logo.png" class="logo" alt="mixdrop" /></a>
<div class="menu">
<a href="javascript:void(0)" class="btn btn1 openModal" data-modal="signup">SIGNUP</a>
<a href="javascript:void(0)" class="btn btn2 openModal" data-modal="login">LOGIN</a>
</div> <div class="menu-mobile"><img src="/imgs/v2/menu.png" alt="menu"></div>
</div>
</div>
<div class="panel download error txt-c">
<div class="wrapper">
<img src="/imgs/illustration-notfound.png" style="width: 250px;max-width: 80%;" />
<h2>WE ARE SORRY</h2>
<h3>We can't find the file you are looking for.</h3>
<script data-cfasync="false" async type="text/javascript" src="//el.sokajecorin.com/si7MCVE6lXyG8/117018"></script> <div style="padding: 30px 0">
</div>
</div>
</div>
<footer class="panel">
<div class="wrapper">
<div class="col-3">
<a href="/"><img src="/imgs/v2/logo.png" class="logo" alt="mixdrop" /></a>
<a href="javascript:void(0)" class="openModal" data-modal="contact">Contact</a>
<a href="/news/">News</a>
<a href="/faq/">FAQ</a>
</div>
<div class="col-3">
<div class="hdr">POLICY</div>
<a href="/terms/">Terms And Conditions</a>
<a href="/privacy/">Privacy Policy</a>
<a href="/copyright/">Copyright Policy</a>
<a href="javascript:void(0)" class="openModal" data-modal="abuse">Report Abuse</a>
</div>
<div class="col-3">
<div class="hdr">SERVICES</div>
<a href="/panel/">User Panel</a>
<a href="/api/">API</a>
</div>
<!--
<div class="col-lang">
<div class="langSwitch">
<a href="javascript:void(0)" title="English"><img src="/imgs/flag_en.png" alt="english"> EN</a>
<div class="langOptions" style="display: none;">
</div>
</div>
</div>-->
</div>
</footer>
</div>
<div class="uploadbox">
<div class="header">Uploads ( <span>0 / 0</span> ) <i class="toggle"></i></div>
<div class="scroll">
<div class="tbl">
</div>
</div>
</div>
<div id="goUp" class="scrollTo floating" data-scrollto='.container'></div>
<div class="modal" id="modal-login">
<div class="modal-wrapper">
<form action="/actions/global.php">
<input type="text" name="email" placeholder="E-Mail" class="ic ic-in-mail" />
<input type="password" name="password" placeholder="Password" class="ic ic-in-pass" />
<div class="2fa-content" style="display:none">
<label class="hdr">2FA Confirmation Code</label>
<p>A confirmation code was sent to your e-mail address, please confirm it below</p>
<input type="text" name="code" placeholder="" style="text-transform: uppercase;font-size: 2rem;letter-spacing: .5rem;" />
</div>
<button type="button" class="submit btn2">LOGIN</button>
<a href="javascript:void(0)" class="forgot">Forgot your password?</a>
<div class="mbError">&nbsp;</div>
<input type="hidden" name="step" value="0" />
<input type="hidden" name="a" value="login" />
</form>
</div>
</div>
<div class="modal" id="modal-recover">
<div class="modal-wrapper">
<form action="/actions/global.php">
<input type="text" name="email" placeholder="E-Mail" class="ic ic-in-mail" />
<button type="button" class="submit btn2">RECOVER</button>
<div class="mbError">&nbsp;</div>
<input type="hidden" name="a" value="recover" />
</form>
</div>
</div>
<div class="modal" id="modal-signup">
<div class="modal-wrapper">
<form action="/actions/global.php">
<input type="text" name="email" placeholder="E-Mail" class="ic ic-in-mail" />
<input type="password" name="password" placeholder="Password" class="ic ic-in-pass" />
<input type="password" name="passwordconfirm" placeholder="Repeat Password" class="ic ic-in-pass" />
<button type="button" class="submit btn2">SIGNUP</button>
<a href="javascript:void(0)" class="mlogin">Already have an account?</a>
<div class="mbError">&nbsp;</div>
<input type="hidden" name="a" value="signup" />
</form>
</div>
</div>
<div class="modal" id="modal-contact">
<div class="modal-wrapper">
<form action="/actions/global.php">
<input type="text" name="name" placeholder="Your name" class="ic ic-in-user" />
<input type="text" name="email" placeholder="Your E-Mail" class="ic ic-in-mail" />
<textarea name="message" placeholder="Your message" class="ic ic-in-compose" rows="6"></textarea>
<button type="button" class="submit btn2">SEND MESSAGE</button>
<div class="mbError">&nbsp;</div>
<input type="hidden" name="a" value="contact" />
</form>
</div>
</div>
<div class="modal" id="modal-abuse">
<div class="modal-wrapper">
<form action="/actions/global.php">
<select name="reason" class="ic ic-in-list">
<option>Reason</option>
<option value="copyright">Copyright infringement</option>
<option value="cp">Child Pornography</option>
<option value="terrorism">Terrorism Content</option>
</select>
<input type="text" name="name" placeholder="Your name" class="ic ic-in-user" />
<input type="text" name="email" placeholder="Your E-Mail" class="ic ic-in-mail" />
<textarea name="message" placeholder="Your message" class="ic ic-in-compose" rows="6"></textarea>
<button type="button" class="submit btn2">SEND MESSAGE</button>
<div class="mbError">&nbsp;</div>
<input type="hidden" name="a" value="abuse" />
</form>
</div>
</div>
<div off-canvas="menu right push" class="toggleMenu">
<a href="javascript:void(0)" class="openModal" data-modal="login">LOGIN</a>
<a href="javascript:void(0)" class="openModal" data-modal="signup">SIGNUP</a>
<a href="javascript:void(0)" class="scrollTo" data-scrollto=".landing">HOME</a>
<a href="/panel/">USER PANEL</a>
<a href="javascript:void(0)" class="scrollTo" data-scrollto=".share">SHARE</a>
<a href="javascript:void(0)" class="scrollTo" data-scrollto=".embed">EMBED</a>
<a href="" class="scrollTo" data-scrollto=".affiliate">AFFILIATE</a>
<a href="/faq/">FAQ</a>
<a href="/news/">NEWS</a>
<a href="javascript:void(0)" class="openModal" data-modal="contact">CONTACT</a>
</div>
<script src="https://code.jquery.com/ui/1.13.2/jquery-ui.min.js" integrity="sha256-lSjKY0/srUM9BE3dPm+c4fBo1dky2v27Gdjm2uoZaL0=" crossorigin="anonymous"></script>
<script src="/js/modal/modal.js?v=2.0.1"></script>
<script src="/js/slidebars/slidebars.min.js?v=2.0.1"></script>
<script src="/js/circular-progress/circle-progress.min.js?v=2.0.1"></script>
<script src="/js/jquery-upload/js/jquery.iframe-transport.js?v=2.0.1"></script>
<script src="/js/jquery-upload/js/jquery.fileupload.js?v=2.0.1"></script>
<script src="/js/jquery-upload/js/main.js?v=2.0.1"></script>
<script src="/panel/js/scroll/perfect-scrollbar.min.js?v=2.0.1"></script>
<link rel="stylesheet" href="/panel/js/scroll/perfect-scrollbar.css?v=2.0.1" />
<script src="/js/script.v2.min.js?v=2.0.1"></script>
<script src="/js/ads.js"></script>
<script defer data-domain="mixdrop.ag/f" src="https://mdstats.info/js/script.js"></script>
</body>
</html>

View file

@ -0,0 +1,213 @@
<!DOCTYPE html>
<html lang="en">
<head>
<meta http-equiv="Content-Type" content="text/html; charset=utf-8" />
<meta http-equiv="X-UA-Compatible" content="IE=edge,chrome=1" />
<meta name="viewport" content="width=device-width; initial-scale=1.0">
<title>MixDrop - Watch 28_giorni_dopo_2002_HD_-_Altadefinizione01</title>
<meta name="description" content="" />
<meta name="keywords" content="mixdrop,share file,share video,upload file,upload video" />
<meta property="og:title" content="MixDrop - Watch 28_giorni_dopo_2002_HD_-_Altadefinizione01" />
<meta property="og:description" content="" />
<meta name="verified-code" content="035b8906-2381-4a3a-9d4c-3b2ae07293e4">
<!--<meta name="robots" content="nosnippet">-->
<meta name="a.validate.02" content="ctm1Vhh9zx0o7ew5xlkxmA8MjHBDjK2gY_5x" />
<link rel="icon" type="image/png" href="/imgs/v2/favicon-32x32.png" sizes="32x32" />
<link rel="icon" type="image/png" href="/imgs/v2/favicon-16x16.png" sizes="16x16" />
<meta name="csrf" content="2928b10d4f03dafd5a62f1db31d164f0">
<meta name="clckd" content="ebd626d580ab61986c788e761c305e41" />
<meta name="monetag" content="d1dda856d50c7dd239c4daa5c545e3d3">
<meta name="41e891e66eaaca8fc8294c24cc35a2b1eee3aa09" content="41e891e66eaaca8fc8294c24cc35a2b1eee3aa09" />
<link rel="stylesheet" href="/js/slidebars/slidebars.css?v=0.1" />
<link rel="stylesheet" href="/css/style.v2.0.2.min.css" />
<script src="https://code.jquery.com/jquery-3.6.4.min.js" integrity="sha256-oP6HI9z1XaZNBrJURtCoUT5SUnxFr8s3BzRl+cbzUq8=" crossorigin="anonymous"></script>
</head>
<body>
<div class="container" canvas="container">
<div class="panel header">
<div class="wrapper">
<a href="/"><img src="/imgs/v2/logo.png" class="logo" alt="mixdrop" /></a>
<div class="menu">
<a href="javascript:void(0)" class="btn btn1 openModal" data-modal="signup">SIGNUP</a>
<a href="javascript:void(0)" class="btn btn2 openModal" data-modal="login">LOGIN</a>
</div> <div class="menu-mobile"><img src="/imgs/v2/menu.png" alt="menu"></div>
</div>
</div>
<div class="panel download video">
<div class="wrapper">
<div class="download-top">
<iframe width="100%" height="100%" src="/e/knq0kj8waq44l8" frameborder="0" scrolling="no" allowfullscreen></iframe>
</div>
<div class="player-bottom block">
<div class="tbl">
<div class="tbl-c c-l title">
<img src="/imgs/v2/i-download.png" class="icon" /> <b title="28_giorni_dopo_2002_HD_-_Altadefinizione01.mp4">28_giorni_dopo_2002_HD_-_Altadefinizione01.mp4</b> 1,010.71 MB </div>
<div class="tbl-c txt-r">
<div class="download download-wrapper">
<div class="s-wrapper">
<a class="sc fb" onclick="MDCore.share_fb('https://mxdrop.to/f/knq0kj8waq44l8');return false;" title="Share"></a><a class="sc tw" onclick="MDCore.share_twitter('https://mxdrop.to/f/knq0kj8waq44l8','Watch%2028_giorni_dopo_2002_HD_-_Altadefinizione01%0A');return false;" title="Share"></a>
</div>
<a class="btn btn3 download-btn player" href="?download">DOWNLOAD</a>
</div>
</div>
</div>
</div>
<div class="download-embed block">
<div class="embed-wrapper">
<label>EMBED</label>
<textarea onclick="this.select()"><iframe width="560" height="315" src="https://mxdrop.to/e/knq0kj8waq44l8" frameborder="0" allowfullscreen></iframe></textarea>
</div>
</div>
<div style="padding: 30px 0">
</div>
</div>
</div>
<footer class="panel">
<div class="wrapper">
<div class="col-3">
<a href="/"><img src="/imgs/v2/logo.png" class="logo" alt="mixdrop" /></a>
<a href="javascript:void(0)" class="openModal" data-modal="contact">Contact</a>
<a href="/news/">News</a>
<a href="/faq/">FAQ</a>
</div>
<div class="col-3">
<div class="hdr">POLICY</div>
<a href="/terms/">Terms And Conditions</a>
<a href="/privacy/">Privacy Policy</a>
<a href="/copyright/">Copyright Policy</a>
<a href="javascript:void(0)" class="openModal" data-modal="abuse">Report Abuse</a>
</div>
<div class="col-3">
<div class="hdr">SERVICES</div>
<a href="/panel/">User Panel</a>
<a href="/api/">API</a>
</div>
<!--
<div class="col-lang">
<div class="langSwitch">
<a href="javascript:void(0)" title="English"><img src="/imgs/flag_en.png" alt="english"> EN</a>
<div class="langOptions" style="display: none;">
</div>
</div>
</div>-->
</div>
</footer>
</div>
<div class="uploadbox">
<div class="header">Uploads ( <span>0 / 0</span> ) <i class="toggle"></i></div>
<div class="scroll">
<div class="tbl">
</div>
</div>
</div>
<div id="goUp" class="scrollTo floating" data-scrollto='.container'></div>
<div class="modal" id="modal-login">
<div class="modal-wrapper">
<form action="/actions/global.php">
<input type="text" name="email" placeholder="E-Mail" class="ic ic-in-mail" />
<input type="password" name="password" placeholder="Password" class="ic ic-in-pass" />
<div class="2fa-content" style="display:none">
<label class="hdr">2FA Confirmation Code</label>
<p>A confirmation code was sent to your e-mail address, please confirm it below</p>
<input type="text" name="code" placeholder="" style="text-transform: uppercase;font-size: 2rem;letter-spacing: .5rem;" />
</div>
<button type="button" class="submit btn2">LOGIN</button>
<a href="javascript:void(0)" class="forgot">Forgot your password?</a>
<div class="mbError">&nbsp;</div>
<input type="hidden" name="step" value="0" />
<input type="hidden" name="a" value="login" />
</form>
</div>
</div>
<div class="modal" id="modal-recover">
<div class="modal-wrapper">
<form action="/actions/global.php">
<input type="text" name="email" placeholder="E-Mail" class="ic ic-in-mail" />
<button type="button" class="submit btn2">RECOVER</button>
<div class="mbError">&nbsp;</div>
<input type="hidden" name="a" value="recover" />
</form>
</div>
</div>
<div class="modal" id="modal-signup">
<div class="modal-wrapper">
<form action="/actions/global.php">
<input type="text" name="email" placeholder="E-Mail" class="ic ic-in-mail" />
<input type="password" name="password" placeholder="Password" class="ic ic-in-pass" />
<input type="password" name="passwordconfirm" placeholder="Repeat Password" class="ic ic-in-pass" />
<button type="button" class="submit btn2">SIGNUP</button>
<a href="javascript:void(0)" class="mlogin">Already have an account?</a>
<div class="mbError">&nbsp;</div>
<input type="hidden" name="a" value="signup" />
</form>
</div>
</div>
<div class="modal" id="modal-contact">
<div class="modal-wrapper">
<form action="/actions/global.php">
<input type="text" name="name" placeholder="Your name" class="ic ic-in-user" />
<input type="text" name="email" placeholder="Your E-Mail" class="ic ic-in-mail" />
<textarea name="message" placeholder="Your message" class="ic ic-in-compose" rows="6"></textarea>
<button type="button" class="submit btn2">SEND MESSAGE</button>
<div class="mbError">&nbsp;</div>
<input type="hidden" name="a" value="contact" />
</form>
</div>
</div>
<div class="modal" id="modal-abuse">
<div class="modal-wrapper">
<form action="/actions/global.php">
<select name="reason" class="ic ic-in-list">
<option>Reason</option>
<option value="copyright">Copyright infringement</option>
<option value="cp">Child Pornography</option>
<option value="terrorism">Terrorism Content</option>
</select>
<input type="text" name="name" placeholder="Your name" class="ic ic-in-user" />
<input type="text" name="email" placeholder="Your E-Mail" class="ic ic-in-mail" />
<textarea name="message" placeholder="Your message" class="ic ic-in-compose" rows="6"></textarea>
<button type="button" class="submit btn2">SEND MESSAGE</button>
<div class="mbError">&nbsp;</div>
<input type="hidden" name="a" value="abuse" />
</form>
</div>
</div>
<div off-canvas="menu right push" class="toggleMenu">
<a href="javascript:void(0)" class="openModal" data-modal="login">LOGIN</a>
<a href="javascript:void(0)" class="openModal" data-modal="signup">SIGNUP</a>
<a href="javascript:void(0)" class="scrollTo" data-scrollto=".landing">HOME</a>
<a href="/panel/">USER PANEL</a>
<a href="javascript:void(0)" class="scrollTo" data-scrollto=".share">SHARE</a>
<a href="javascript:void(0)" class="scrollTo" data-scrollto=".embed">EMBED</a>
<a href="" class="scrollTo" data-scrollto=".affiliate">AFFILIATE</a>
<a href="/faq/">FAQ</a>
<a href="/news/">NEWS</a>
<a href="javascript:void(0)" class="openModal" data-modal="contact">CONTACT</a>
</div>
<script src="https://code.jquery.com/ui/1.13.2/jquery-ui.min.js" integrity="sha256-lSjKY0/srUM9BE3dPm+c4fBo1dky2v27Gdjm2uoZaL0=" crossorigin="anonymous"></script>
<script src="/js/modal/modal.js?v=2.0.1"></script>
<script src="/js/slidebars/slidebars.min.js?v=2.0.1"></script>
<script src="/js/circular-progress/circle-progress.min.js?v=2.0.1"></script>
<script src="/js/jquery-upload/js/jquery.iframe-transport.js?v=2.0.1"></script>
<script src="/js/jquery-upload/js/jquery.fileupload.js?v=2.0.1"></script>
<script src="/js/jquery-upload/js/main.js?v=2.0.1"></script>
<script src="/panel/js/scroll/perfect-scrollbar.min.js?v=2.0.1"></script>
<link rel="stylesheet" href="/panel/js/scroll/perfect-scrollbar.css?v=2.0.1" />
<script src="/js/script.v2.min.js?v=2.0.1"></script>
<script src="/js/ads.js"></script>
<script defer data-domain="mixdrop.ag/f" src="https://mdstats.info/js/script.js"></script>
</body>
</html>

View file

@ -0,0 +1,19 @@
// Jest Snapshot v1, https://jestjs.io/docs/snapshot-testing
exports[`Mixdrop deleted or expired file 1`] = `[]`;
exports[`Mixdrop mixdrop.my /e/ 1`] = `
[
{
"label": "Mixdrop",
"meta": {
"bytes": 1059806248,
"countryCode": "de",
"title": "28_giorni_dopo_2002_HD_-_Altadefinizione01.mp4",
},
"sourceId": "mixdrop_de",
"ttl": 0,
"url": "https://mediaflow-proxy.test/extractor/video?host=Mixdrop&redirect_stream=true&api_password=asdfg&d=https%3A%2F%2Fmixdrop.my%2Fe%2Fknq0kj8waq44l8",
},
]
`;

View file

@ -8,6 +8,7 @@ import { Soaper } from './Soaper';
import { SuperVideo } from './SuperVideo';
import { VidSrc } from './VidSrc';
import { Fetcher } from '../utils';
import { Mixdrop } from './Mixdrop';
export * from './Extractor';
export * from './ExtractorRegistry';
@ -18,6 +19,7 @@ export const createExtractors = (fetcher: Fetcher): Extractor[] => [
new Fsst(fetcher),
new SuperVideo(fetcher),
new KinoGer(fetcher),
new Mixdrop(fetcher),
new Soaper(fetcher),
new VidSrc(fetcher),
new ExternalUrl(fetcher), // fallback extractor which must come last

View file

@ -9,7 +9,7 @@ export interface Context {
export type ManifestWithConfig = Manifest & { config: ManifestConfig[] };
export type Config = Partial<Record<CountryCode | 'includeExternalUrls', string>>;
export type Config = Partial<Record<CountryCode | 'includeExternalUrls' | 'mediaFlowProxyUrl' | 'mediaFlowProxyPassword', string>>;
export enum CountryCode {
de = 'de',

View file

@ -8,6 +8,18 @@ exports[`buildManifest has checked includeExternalUrls 1`] = `
"title": "Include external URLs from results",
"type": "checkbox",
},
{
"default": "",
"key": "mediaFlowProxyUrl",
"title": "MediaFlow Proxy URL",
"type": "text",
},
{
"default": "",
"key": "mediaFlowProxyPassword",
"title": "MediaFlow Proxy Password",
"type": "password",
},
]
`;
@ -35,6 +47,18 @@ exports[`buildManifest has checked source with appropriate config 1`] = `
"title": "Include external URLs from results",
"type": "checkbox",
},
{
"default": "",
"key": "mediaFlowProxyUrl",
"title": "MediaFlow Proxy URL",
"type": "text",
},
{
"default": "",
"key": "mediaFlowProxyPassword",
"title": "MediaFlow Proxy Password",
"type": "password",
},
]
`;
@ -60,6 +84,18 @@ exports[`buildManifest has unchecked source without a config 1`] = `
"title": "Include external URLs from results",
"type": "checkbox",
},
{
"default": "",
"key": "mediaFlowProxyUrl",
"title": "MediaFlow Proxy URL",
"type": "text",
},
{
"default": "",
"key": "mediaFlowProxyPassword",
"title": "MediaFlow Proxy Password",
"type": "password",
},
]
`;
@ -70,5 +106,17 @@ exports[`buildManifest includeExternalUrls is unchecked by default 1`] = `
"title": "Include external URLs from results",
"type": "checkbox",
},
{
"default": "",
"key": "mediaFlowProxyUrl",
"title": "MediaFlow Proxy URL",
"type": "text",
},
{
"default": "",
"key": "mediaFlowProxyPassword",
"title": "MediaFlow Proxy Password",
"type": "password",
},
]
`;

View file

@ -5,3 +5,18 @@ export const getDefaultConfig = (): Config => {
};
export const showExternalUrls = (config: Config): boolean => 'includeExternalUrls' in config;
export const hasMediaFlowProxy = (config: Config): boolean => !!(config['mediaFlowProxyUrl'] && config['mediaFlowProxyPassword']);
export const buildMediaFlowProxyUrl = (config: Config, host: string, url: URL): URL => {
const mediaFlowProxyUrl = new URL(`${config.mediaFlowProxyUrl}/extractor/video`);
const params = new URLSearchParams();
params.append('host', host);
params.append('redirect_stream', 'true');
params.append('api_password', `${config.mediaFlowProxyPassword}`);
params.append('d', url.href);
mediaFlowProxyUrl.search = params.toString();
return mediaFlowProxyUrl;
};

View file

@ -57,5 +57,19 @@ export const buildManifest = (sources: Source[], config: Config): ManifestWithCo
...('includeExternalUrls' in config && { default: 'checked' }),
});
manifest.config.push({
key: 'mediaFlowProxyUrl',
type: 'text',
title: 'MediaFlow Proxy URL',
default: config['mediaFlowProxyUrl'] ?? '',
});
manifest.config.push({
key: 'mediaFlowProxyPassword',
type: 'password',
title: 'MediaFlow Proxy Password',
default: config['mediaFlowProxyPassword'] ?? '',
});
return manifest;
};