/** * Copie les segments média que Firefox télécharge déjà, sans les redemander. * * `filterResponseData` donne accès au flux de réponse d'une requête que la page * a elle-même initiée. On lit les octets au passage et on les réécrit aussitôt * vers la page : le lecteur continue de fonctionner normalement, et l'extension * n'émet aucune requête vers la plateforme. * * C'est la différence avec un script qui irait rechercher le flux : ici on ne * fait que conserver ce que la session authentifiée a légitimement reçu. */ const RECEIVER = 'http://127.0.0.1:8099/ingest'; // Playlists et segments servis par le CDN média de la plateforme. const MEDIA_PATTERN = /\.(m3u8|m4s|mp4|ts)(\?|$)/i; let copied = 0; let failed = 0; function updateBadge() { const text = failed ? `${copied}/${failed}!` : String(copied); browser.browserAction.setBadgeText({ text: copied || failed ? text : '' }); browser.browserAction.setBadgeBackgroundColor({ color: failed ? '#b91c1c' : '#2563eb' }); } async function forward(url, chunks) { try { const blob = new Blob(chunks); const body = await blob.arrayBuffer(); await fetch(RECEIVER, { method: 'POST', headers: { 'content-type': 'application/octet-stream', 'x-source-url': url, }, body, }); copied += 1; } catch (err) { // Récepteur non lancé : on n'interrompt surtout pas la lecture pour autant. failed += 1; console.warn('stream-capture : envoi impossible', err); } updateBadge(); } browser.webRequest.onBeforeRequest.addListener( (details) => { if (!MEDIA_PATTERN.test(details.url)) return {}; const filter = browser.webRequest.filterResponseData(details.requestId); const chunks = []; filter.ondata = (event) => { chunks.push(event.data); // Réécriture immédiate : la page reçoit son flux inchangé. filter.write(event.data); }; filter.onstop = () => { filter.disconnect(); void forward(details.url, chunks); }; filter.onerror = () => { // Le filtre a lâché : la requête suit son cours normalement. console.warn('stream-capture : filtre interrompu', filter.error); }; return {}; }, { urls: ['*://*.doppiocdn.com/*'] }, ['blocking'], ); console.log('stream-capture : actif, récepteur attendu sur', RECEIVER);