Version 2.0.0 - update of everything

This commit is contained in:
raphix committed 2026-10-07 14:04:26 +02:00
1 parent 164a1da009
commit 6017e03eac
85 files changed
+13065 -2107

No files matched your search

+113
View File
@@ -0,0 +1,113 @@
const { check, done, req } = require('./_setup');
const plan = req('src/youtube/plan');
const W = 'http://warp:1080';
const ROUTES = { 'warp+direct': [W, null], 'direct': [null], 'warp seul': [W] };
const FB = 'web_safari,tv_downgraded';
const label = (a) => `${a.proxy ? 'W' : 'D'}/${a.identity === 'cookies' ? 'C' : 'A'}${a.clients ? '/fb' : ''}${a.seek ? '/' + a.seek : ''}`;
/**
* Simule getStream : chaque tentative échoue avec la classe donnée (tableau, ou fonction (attempt, i, history))
* okAt : index de la tentative qui réussit ; rotateAt : la tentative i invalide les cookies
*/
function simulate({ routes, mode = 'fallback', cookiesValid = true, cookiesOnProxy = false, fail, okAt = -1, rotateAt = -1, seekMode = null, fallbackClients = FB }) {
const history = [];
const seq = [];
let valid = cookiesValid;
for (let i = 0; i < 10; i++) {
const a = plan.planNext({ routes, mode, cookiesValid: valid, cookiesOnProxy, clients: '', fallbackClients, seekMode, history, maxAttempts: 4 });
if (!a) break;
seq.push(label(a));
if (i === okAt) { seq.push('OK'); break; }
const cls = typeof fail === 'function' ? fail(a, i, history) : (Array.isArray(fail) ? fail[Math.min(i, fail.length - 1)] : fail);
if (i === rotateAt) valid = false;
history.push({ ...a, cls });
}
return seq.join(' > ');
}
function expect(name, input, expected) {
const got = simulate(input);
check(`${name.padEnd(62)} ${got}`, got === expected, { expected });
}
console.log('# Mode never');
expect('never, warp+direct, UNKNOWN', { routes: ROUTES['warp+direct'], mode: 'never', fail: 'UNKNOWN' }, 'W/A > D/A');
expect('never, warp+direct, BOT_CHECK (jamais de cookies)', { routes: ROUTES['warp+direct'], mode: 'never', fail: 'BOT_CHECK' }, 'W/A > D/A');
expect('never, warp+direct, HTTP_403 (clients de repli une fois)', { routes: ROUTES['warp+direct'], mode: 'never', fail: 'HTTP_403' }, 'W/A > W/A/fb > D/A');
expect('never, direct, LOGIN_REQUIRED (arrêt)', { routes: ROUTES.direct, mode: 'never', fail: 'LOGIN_REQUIRED' }, 'D/A');
expect('never, warp seul, TIMEOUT', { routes: ROUTES['warp seul'], mode: 'never', fail: 'TIMEOUT' }, 'W/A');
expect('never, warp+direct, PRIVATE (fatal)', { routes: ROUTES['warp+direct'], mode: 'never', fail: 'PRIVATE' }, 'W/A');
expect('never, warp+direct, UNAVAILABLE (fatal)', { routes: ROUTES['warp+direct'], mode: 'never', fail: 'UNAVAILABLE' }, 'W/A');
expect('never, warp+direct, RATE_LIMITED (autre route uniquement)', { routes: ROUTES['warp+direct'], mode: 'never', fail: 'RATE_LIMITED' }, 'W/A > D/A');
expect('never, warp+direct, BINARY_MISSING (arrêt)', { routes: ROUTES['warp+direct'], mode: 'never', fail: 'BINARY_MISSING' }, 'W/A');
console.log('# Mode fallback (cookies valides)');
expect('fallback, warp+direct, BOT_CHECK', { routes: ROUTES['warp+direct'], fail: 'BOT_CHECK' }, 'W/A > D/A > D/C');
expect('fallback, warp+direct, IP_BLOCKED, cookiesOnProxy', { routes: ROUTES['warp+direct'], cookiesOnProxy: true, fail: 'IP_BLOCKED' }, 'W/A > D/A > W/C > D/C');
expect('fallback, direct, CAPTCHA', { routes: ROUTES.direct, fail: 'CAPTCHA' }, 'D/A > D/C');
expect('fallback, warp seul, BOT_CHECK (proxy = seule route)', { routes: ROUTES['warp seul'], fail: 'BOT_CHECK' }, 'W/A > W/C');
expect('fallback, warp+direct, AGE_RESTRICTED (compte directement)', { routes: ROUTES['warp+direct'], fail: 'AGE_RESTRICTED' }, 'W/A > D/C');
expect('fallback, warp+direct, MEMBERS_ONLY', { routes: ROUTES['warp+direct'], fail: 'MEMBERS_ONLY' }, 'W/A > D/C');
expect('fallback, warp+direct, LOGIN_REQUIRED, cookiesOnProxy (refus avec compte = arrêt)', { routes: ROUTES['warp+direct'], cookiesOnProxy: true, fail: 'LOGIN_REQUIRED' }, 'W/A > W/C');
expect('fallback, warp+direct, UNKNOWN (pas de cookies)', { routes: ROUTES['warp+direct'], fail: 'UNKNOWN' }, 'W/A > D/A');
expect('fallback, warp+direct, GEO_BLOCKED (autre route seulement)', { routes: ROUTES['warp+direct'], fail: 'GEO_BLOCKED' }, 'W/A > D/A');
expect('fallback, direct, GEO_BLOCKED', { routes: ROUTES.direct, fail: 'GEO_BLOCKED' }, 'D/A');
expect('fallback, direct, HTTP_403', { routes: ROUTES.direct, fail: 'HTTP_403' }, 'D/A > D/A/fb');
expect('fallback, direct, SABR', { routes: ROUTES.direct, fail: 'SABR' }, 'D/A > D/A/fb');
expect('fallback, direct, POT_MISSING', { routes: ROUTES.direct, fail: 'POT_MISSING' }, 'D/A > D/A/fb');
expect('fallback, direct, EMPTY_DOWNLOAD', { routes: ROUTES.direct, fail: 'EMPTY_DOWNLOAD' }, 'D/A > D/A/fb');
expect('fallback, direct, FORMAT_UNAVAILABLE, repli désactivé', { routes: ROUTES.direct, fail: 'FORMAT_UNAVAILABLE', fallbackClients: '' }, 'D/A');
expect('fallback, warp+direct, 403 puis BOT_CHECK', { routes: ROUTES['warp+direct'], fail: ['HTTP_403', 'BOT_CHECK'] }, 'W/A > W/A/fb > D/A > D/C');
expect('fallback, warp+direct, BOT puis 403 (max 4)', { routes: ROUTES['warp+direct'], fail: ['BOT_CHECK', 'BOT_CHECK', 'HTTP_403'] }, 'W/A > D/A > D/C > D/C/fb');
expect('fallback, warp+direct, réussite à la 2e', { routes: ROUTES['warp+direct'], fail: 'BOT_CHECK', okAt: 1 }, 'W/A > D/A > OK');
expect('fallback, cookies tournés pendant la tentative avec compte', { routes: ROUTES['warp+direct'], fail: 'BOT_CHECK', rotateAt: 2 }, 'W/A > D/A > D/C');
expect('fallback, cookies invalides, BOT_CHECK', { routes: ROUTES['warp+direct'], cookiesValid: false, fail: 'BOT_CHECK' }, 'W/A > D/A');
expect('fallback, cookies invalides, AGE_RESTRICTED (arrêt)', { routes: ROUTES['warp+direct'], cookiesValid: false, fail: 'AGE_RESTRICTED' }, 'W/A');
expect('fallback, compte refusé (AGE avec cookies) -> arrêt', { routes: ROUTES.direct, fail: 'AGE_RESTRICTED' }, 'D/A > D/C');
console.log('# Mode always');
expect('always, warp+direct (pas de compte via WARP)', { routes: ROUTES['warp+direct'], mode: 'always', fail: 'UNKNOWN' }, 'W/A > D/C');
expect('always, warp+direct, cookiesOnProxy', { routes: ROUTES['warp+direct'], mode: 'always', cookiesOnProxy: true, fail: 'UNKNOWN' }, 'W/C > D/C');
expect('always, direct, BOT_CHECK', { routes: ROUTES.direct, mode: 'always', fail: 'BOT_CHECK' }, 'D/C');
expect('always, warp seul (compte autorisé)', { routes: ROUTES['warp seul'], mode: 'always', fail: 'UNKNOWN' }, 'W/C');
expect('always, direct, rotation -> anonyme', { routes: ROUTES.direct, mode: 'always', fail: 'COOKIES_ROTATED', rotateAt: 0 }, 'D/C > D/A');
expect('always, warp+direct, AGE sur WARP anonyme -> compte', { routes: ROUTES['warp+direct'], mode: 'always', fail: 'AGE_RESTRICTED' }, 'W/A > D/C');
expect('always, direct, HTTP_403 -> clients de repli avec compte', { routes: ROUTES.direct, mode: 'always', fail: 'HTTP_403' }, 'D/C > D/C/fb');
expect('always sans cookies valides = never', { routes: ROUTES['warp+direct'], mode: 'always', cookiesValid: false, fail: 'BOT_CHECK' }, 'W/A > D/A');
expect('always, PRIVATE', { routes: ROUTES['warp+direct'], mode: 'always', fail: 'PRIVATE' }, 'W/A');
console.log('# Seek');
check('seekModeFor auto 30 -> native', plan.seekModeFor('auto', 30) === 'native');
check('seekModeFor auto 1200 -> native', plan.seekModeFor('auto', 1200) === 'native');
check('seekModeFor auto 1201 -> sections', plan.seekModeFor('auto', 1201) === 'sections');
check('seekModeFor ffmpeg 10 -> sections', plan.seekModeFor('ffmpeg', 10) === 'sections');
check('seekModeFor native 5000 -> native', plan.seekModeFor('native', 5000) === 'native');
check('seekModeFor sans seek -> null', plan.seekModeFor('auto', 0) === null);
expect('sections + HTTP_403 -> natif puis clients de repli', { routes: ROUTES.direct, seekMode: 'sections', fail: 'HTTP_403' }, 'D/A/sections > D/A/native > D/A/fb/native');
expect('sections + 403 sur warp+direct -> la suite en natif', { routes: ROUTES['warp+direct'], seekMode: 'sections', fail: ['HTTP_403', 'BOT_CHECK'] }, 'W/A/sections > W/A/native > D/A/native > D/C/native');
expect('natif + UNKNOWN', { routes: ROUTES['warp+direct'], seekMode: 'native', fail: 'UNKNOWN' }, 'W/A/native > D/A/native');
console.log('# Matrice (modes x routes x classes)');
const classes = ['BOT_CHECK', 'IP_BLOCKED', 'CAPTCHA', 'RATE_LIMITED', 'HTTP_403', 'HTTP_429', 'AGE_RESTRICTED', 'LOGIN_REQUIRED', 'MEMBERS_ONLY', 'PRIVATE', 'UNAVAILABLE', 'GEO_BLOCKED', 'POT_MISSING', 'SABR', 'JS_CHALLENGE', 'FORMAT_UNAVAILABLE', 'PAGE_RELOAD', 'COOKIES_ROTATED', 'EMPTY_DOWNLOAD', 'BINARY_MISSING', 'TIMEOUT', 'UNKNOWN'];
let maxLen = 0, dup = 0;
for (const mode of ['never', 'always', 'fallback']) {
for (const [rname, routes] of Object.entries(ROUTES)) {
const row = [];
for (const cls of classes) {
const seq = simulate({ routes, mode, fail: cls });
const parts = seq.split(' > ');
maxLen = Math.max(maxLen, parts.length);
if (new Set(parts).size !== parts.length) dup++;
row.push(`${cls}: ${seq}`);
}
console.log(` [${mode} | ${rname}]`);
for (const r of row) console.log(` ${r}`);
}
}
check('jamais plus de 4 tentatives', maxLen <= 4, maxLen);
check('jamais deux fois la même tentative', dup === 0, dup);
check('pas de compte en mode never', !['warp+direct', 'direct', 'warp seul'].some(r => classes.some(c => simulate({ routes: ROUTES[r], mode: 'never', fail: c }).includes('/C'))));
done();