Files
stream-control/tools/stream-capture/background.js
jeanotx32 da9025fbf1
Some checks failed
release / build (push) Successful in 16s
release / verify-windows (push) Failing after 1m0s
test : stream cap
2026-08-11 19:34:55 +02:00

80 lines
2.3 KiB
JavaScript

/**
* 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);