fix(extractor): handle Fastream deleted or expired file

This commit is contained in:
WebStreamr 2025-10-24 14:55:52 +00:00
parent cc7b0be150
commit bd1e184023
No known key found for this signature in database
4 changed files with 243 additions and 2 deletions

View file

@ -13,4 +13,8 @@ describe('Fastream', () => {
test('fastream.to embed', async () => {
expect(await extractorRegistry.handle(ctx, new URL('https://fastream.to/embed-3aooif4ozt10.html'))).toMatchSnapshot();
});
test('expired or deleted', async () => {
expect(await extractorRegistry.handle(ctx, new URL('https://fastream.to/embed-a9rp1d1pqom7.html'))).toMatchSnapshot();
});
});

View file

@ -1,4 +1,5 @@
import bytes from 'bytes';
import { NotFoundError } from '../error';
import { Context, Format, Meta, UrlResult } from '../types';
import { buildMediaFlowProxyExtractorStreamUrl, supportsMediaFlowProxy } from '../utils';
import { Extractor } from './Extractor';
@ -21,11 +22,15 @@ export class Fastream extends Extractor {
protected async extractInternal(ctx: Context, url: URL, meta: Meta): Promise<UrlResult[]> {
const headers = { Referer: meta.referer ?? url.href };
const playlistUrl = await buildMediaFlowProxyExtractorStreamUrl(ctx, this.fetcher, 'Fastream', url, headers);
const downloadUrl = new URL(url.href.replace('/embed-', '/d/'));
const html = await this.fetcher.text(ctx, downloadUrl, { headers });
if (/No such file/.test(html)) {
throw new NotFoundError();
}
const playlistUrl = await buildMediaFlowProxyExtractorStreamUrl(ctx, this.fetcher, 'Fastream', url, headers);
const heightAndSizeMatch = html.match(/\d{3,}x(\d{3,}), ([\d.]+ ?[GM]B)/) as string[];
const titleMatch = html.match(/>Download (.*?)</) as string[];

View file

@ -0,0 +1,230 @@
<!DOCTYPE html>
<html>
<head>
<meta charset="utf-8">
<title>Fastream</title>
<meta http-equiv="X-UA-Compatible" content="IE=edge">
<meta name="viewport" content="width=device-width, initial-scale=1, shrink-to-fit=no">
<meta name="theme-color" content="#FFF">
<link rel="apple-touch-icon" href="https://fastream.to/images2/favicon/apple-touch-icon.png" sizes="180x180">
<link rel="icon" href="https://fastream.to/images2/favicon/favicon-32x32.png" sizes="32x32">
<link rel="icon" href="https://fastream.to/images2/favicon/favicon-16x16.png" sizes="16x16">
<link rel="manifest" href="https://fastream.to/images2/favicon/site.webmanifest" crossorigin="use-credentials">
<link rel="icon" href="https://fastream.to/images2/favicon/favicon.ico">
<link rel="preconnect" href="https://fonts.googleapis.com">
<link rel="preconnect" href="https://fonts.gstatic.com" crossorigin>
<link href="https://fonts.googleapis.com/css2?family=Manrope:wght@400..800&display=swap" rel="stylesheet">
<link href="https://fastream.to/css2/bootstrap.css?" rel="stylesheet">
<link href="https://fastream.to/css2/style.css?" rel="stylesheet">
<script src="https://fastream.to/js2/jquery.min.js?"></script>
<script src="https://fastream.to/js2/bootstrap.bundle.min.js?"></script>
<script src="https://fastream.to/js2/app.js?aс1"></script>
<script src="https://fastream.to/js2/xupload.js?aс1"></script>
</head>
<body class="">
<header class="header">
<div class="container">
<div class="row header-row align-items-center flex-nowrap">
<div class="col-auto flex-grow-1 flex-shrink-1">
<div class="row align-items-center">
<div class="col-auto d-lg-none">
<div class="dropdown">
<button class="btn icon-btn" data-bs-toggle="dropdown" data-bs-offset="0, 16">
<svg xmlns="http://www.w3.org/2000/svg" xml:space="preserve" width="22" height="16" viewBox="0 0 22 16">
<path d="M0 0h22v2H0V0zm0 7h22v2H0V7zm0 7h22v2H0v-2z"></path>
</svg>
</button>
<ul class="dropdown-menu dropdown-menu-end">
<a href="/premium" class="dropdown-item">Premium</a>
<a href="/make_money" class="dropdown-item">Make Money</a>
<a href="/check_files" class="dropdown-item">Link Checker</a>
<a href="/api.html" class="dropdown-item">API</a>
<a href="/tos" class="dropdown-item">Terms of service</a>
<a href="/contact" class="dropdown-item">Contact Us</a>
<a href="/faq" class="dropdown-item">FAQ</a>
</ul>
</div>
</div>
<div class="col-auto me-lg-4">
<a href="/" class="logo">
<img src="https://fastream.to/images2/logo.svg?" alt="">
</a>
</div>
<div class="col-auto d-none d-lg-block">
<nav class="nav">
<a class="nav-link link-body-emphasis" href="/premium">Premium</a>
<a class="nav-link link-body-emphasis" href="/make_money">Make Money</a>
</nav>
</div>
</div>
</div>
<div class="col-auto">
<div class="dropdown header-lang">
<button type="button" class="btn icon-btn" data-bs-toggle="dropdown" data-bs-offset="0, 16">
<img src="https://fastream.to/images2/flags/english.svg" alt="">
</button>
<div class="dropdown-menu">
<a href="/?op=change_lang&lang=English" class="dropdown-item"><img src="https://fastream.to/images2/flags/english.svg" alt="">English</a>
<a href="/?op=change_lang&lang=Russian" class="dropdown-item"><img src="https://fastream.to/images2/flags/russian.svg" alt="">Russian</a>
</div>
</div>
</div>
<div class="col-auto d-none d-lg-block">
<a href="/login.html" class="btn me-2 login-btn link-body-emphasis">Login</a>
<a href="/?op=registration" class="btn btn-primary reg-btn">Sign Up</a>
</div>
<div class="col-auto d-lg-none">
<div class="dropdown">
<button class="btn icon-btn" data-bs-toggle="dropdown" data-bs-offset="0, 16">
<svg xmlns="http://www.w3.org/2000/svg" xml:space="preserve" width="22" height="22" viewBox="0 0 22 22">
<path d="M11 22C4.9 22 0 17.1 0 11S4.9 0 11 0s11 4.9 11 11-4.9 11-11 11zm0-20c-5 0-9 4-9 9s4 9 9 9 9-4 9-9-4-9-9-9z"></path>
<path d="M11 15.3c-3 0-5.4-2.4-5.4-5.4S8 4.4 11 4.4s5.4 2.4 5.4 5.4-2.4 5.5-5.4 5.5zm0-8.9c-1.9 0-3.4 1.5-3.4 3.4s1.5 3.4 3.4 3.4 3.4-1.5 3.4-3.4-1.5-3.4-3.4-3.4z"></path>
<path d="M4.9 19.8c-.2 0-.3 0-.5-.1-.5-.3-.6-.9-.4-1.4 1.5-2.5 3.9-3.8 7-3.8s5.5 1.3 7 3.8c.3.5.1 1.1-.3 1.4-.5.3-1.1.1-1.4-.3-1.1-1.9-2.9-2.8-5.2-2.8-2.4 0-4.1.9-5.3 2.8-.2.2-.6.4-.9.4z"></path>
</svg>
</button>
<div class="dropdown-menu dropdown-menu-end">
<a class="dropdown-item" href="/login.html">Login</a>
<a class="dropdown-item" href="/?op=registration">Sign Up</a>
<a class="dropdown-item" href="/?op=forgot_pass">Forgot your password?</a>
</div>
</div>
</div>
</div>
</div>
</header>
<main>
<div class="container">
<div class="alert alert-danger" role="alert">
No such file=a9rp1d1pqom7
</div>
</div>
</main>
<footer class="footer">
<div class="container">
<div class="footer-main">
<div class="row justify-content-center justify-content-lg-start">
<div class="col-12 col-lg-4 col-xl-3 text-center text-lg-start">
<div class="mb-4">
<a href="https://fastream.to/" class="logo">
<img src="https://fastream.to/images2/logo-w.svg?" alt="">
</a>
</div>
<div class="mb-2 text-uppercase"><!--Share us: --></div>
<div class="mb-3">
<!--span class="me-1">
<a href="#"><img src="https://fastream.to/images2/social/fb.svg" alt=""></a>
</span>
<span class="me-1">
<a href="#"><img src="https://fastream.to/images2/social/red.svg" alt=""></a>
</span>
<span class="me-1">
<a href="#"><img src="https://fastream.to/images2/social/wha.svg" alt=""></a>
</span>
<span class="me-1">
<a href="#"><img src="https://fastream.to/images2/social/x.svg" alt=""></a>
</span>
<span class="me-1">
<a href="#"><img src="https://fastream.to/images2/social/msg.svg" alt=""></a>
</span>
<span class="me-1">
<a href="#"><img src="https://fastream.to/images2/social/in.svg" alt=""></a>
</span-->
</div>
</div>
<div class="col-lg-8 col-xl-7 d-none d-lg-block">
<div class="row">
<div class="col">
<div class="text-uppercase text-dark large">Info</div>
<div class="nav flex-column">
<a href="https://fastream.to/" class="nav-link">Home</a>
<a href="/api.html" class="nav-link">API</a>
<a href="/tos" class="nav-link">Terms of service</a>
</div>
</div>
<div class="col">
<div class="text-uppercase text-dark large">Features</div>
<div class="nav flex-column">
<a href="/premium" class="nav-link">Premium</a>
<a href="/make_money" class="nav-link">Make Money</a>
<a href="/check_files" class="nav-link">Link Checker</a>
</div>
</div>
<div class="col">
<div class="text-uppercase text-dark large">Support</div>
<div class="nav flex-column">
<a href="/contact" class="nav-link">Contact Us</a>
<a href="/faq" class="nav-link">FAQ</a>
</div>
</div>
</div>
</div>
<div class="col-xl-auto text-nowrap text-end d-none d-xl-block">
<a href="https://fastream.to/login.html" class="btn btn-light login-btn me-2">Login</a>
<a href="https://fastream.to/?op=registration" class="btn btn-primary reg-btn">Sign Up</a>
</div>
</div>
</div>
</div>
<div class="footer-bottom small">
<div class="container">
<div class="row align-items-center justify-content-between">
<div class="col-auto">
<div class="text-muted">&copy; 2024 Fastream</div>
</div>
<div class="col-auto">
</div>
</div>
</div>
</div>
</footer>
<div style ="display:none"><script id="_wau1xg">var _wau = _wau || []; _wau.push(["classic", "y7jk20u14x", "1xg"]);</script><script async src="//waust.at/c.js"></script></div>
<script>(function(){function c(){var b=a.contentDocument||a.contentWindow.document;if(b){var d=b.createElement('script');d.innerHTML="window.__CF$cv$params={r:'993a4e2d4ac5d2ab',t:'MTc2MTMxNzYyMw=='};var a=document.createElement('script');a.src='/cdn-cgi/challenge-platform/scripts/jsd/main.js';document.getElementsByTagName('head')[0].appendChild(a);";b.getElementsByTagName('head')[0].appendChild(d)}}if(document.body){var a=document.createElement('iframe');a.height=1;a.width=1;a.style.position='absolute';a.style.top=0;a.style.left=0;a.style.border='none';a.style.visibility='hidden';document.body.appendChild(a);if('loading'!==document.readyState)c();else if(window.addEventListener)document.addEventListener('DOMContentLoaded',c);else{var e=document.onreadystatechange||function(){};document.onreadystatechange=function(b){e(b);'loading'!==document.readyState&&(document.onreadystatechange=e,c())}}}})();</script></body>
</html>

View file

@ -1,5 +1,7 @@
// Jest Snapshot v1, https://jestjs.io/docs/snapshot-testing
exports[`Fastream expired or deleted 1`] = `[]`;
exports[`Fastream fastream.to embed 1`] = `
[
{