From 299b2314a8880da7cf11e73ed7e165ccb1a9223e Mon Sep 17 00:00:00 2001 From: ryanbr Date: Tue, 7 Apr 2026 13:06:02 +1200 Subject: [PATCH] Hook revokeObjectURL to protect injected worker blob (release) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Prevents Twitch from silently breaking our worker by revoking the blob URL we created. Only blocks revocation of our one blob URL — all other revokeObjectURL calls pass through unchanged. Co-Authored-By: Claude Opus 4.6 (1M context) --- vaft/vaft-ublock-origin.js | 10 +++++++++- vaft/vaft.user.js | 10 +++++++++- 2 files changed, 18 insertions(+), 2 deletions(-) diff --git a/vaft/vaft-ublock-origin.js b/vaft/vaft-ublock-origin.js index f927c53..7f10eb5 100644 --- a/vaft/vaft-ublock-origin.js +++ b/vaft/vaft-ublock-origin.js @@ -121,7 +121,14 @@ twitch-videoad.js text/javascript return !hasConflict || hasReinsert; } // Replace window.Worker to intercept Twitch's video worker and inject ad-blocking logic + let injectedBlobUrl = null; function hookWindowWorker() { + // Prevent Twitch from revoking our injected worker blob URL + const originalRevokeObjectURL = URL.revokeObjectURL; + URL.revokeObjectURL = function(url) { + if (url === injectedBlobUrl) return; + return originalRevokeObjectURL.call(this, url); + }; const reinsert = getWorkersForReinsert(window.Worker); const newWorker = class Worker extends getCleanWorker(window.Worker) { constructor(twitchBlobUrl, options) { @@ -205,7 +212,8 @@ twitch-videoad.js text/javascript hookWorkerFetch(); eval(workerString); `; - super(URL.createObjectURL(new Blob([newBlobStr])), options); + injectedBlobUrl = URL.createObjectURL(new Blob([newBlobStr])); + super(injectedBlobUrl, options); twitchWorkers.length = 0; twitchWorkers.push(this); this.addEventListener('message', (e) => { diff --git a/vaft/vaft.user.js b/vaft/vaft.user.js index 1066138..b0b5fc4 100644 --- a/vaft/vaft.user.js +++ b/vaft/vaft.user.js @@ -132,7 +132,14 @@ return !hasConflict || hasReinsert; } // Replace window.Worker to intercept Twitch's video worker and inject ad-blocking logic + let injectedBlobUrl = null; function hookWindowWorker() { + // Prevent Twitch from revoking our injected worker blob URL + const originalRevokeObjectURL = URL.revokeObjectURL; + URL.revokeObjectURL = function(url) { + if (url === injectedBlobUrl) return; + return originalRevokeObjectURL.call(this, url); + }; const reinsert = getWorkersForReinsert(window.Worker); const newWorker = class Worker extends getCleanWorker(window.Worker) { constructor(twitchBlobUrl, options) { @@ -216,7 +223,8 @@ hookWorkerFetch(); eval(workerString); `; - super(URL.createObjectURL(new Blob([newBlobStr])), options); + injectedBlobUrl = URL.createObjectURL(new Blob([newBlobStr])); + super(injectedBlobUrl, options); twitchWorkers.length = 0; twitchWorkers.push(this); this.addEventListener('message', (e) => {