80 lines
2.3 KiB
JavaScript
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);
|