fix(player): lock WebView muted/volume until gesture (kill audio-during-scrape)
Some checks are pending
Backend tests / test (push) Waiting to run
Some checks are pending
Backend tests / test (push) Waiting to run
Przy scrape ścieżce (WebView otwiera stronę hostera żeby przechwycić stream) player hostera po autostarcie ustawiał video.muted=false / volume=1 i dźwięk buchał zanim ExoPlayer przejął (raport usera). Sam override play() łapał za wcześnie. Teraz LOCKujemy muted/volume na HTMLMediaElement.prototype: próba odciszenia przed gestem usera jest ignorowana. Po tapie (watch-in-WebView dla CF-blocked hosterów) odblokowanie + odciszenie istniejących <video>/<audio>. Patch leci injectedJavaScriptBeforeContentLoaded, więc przed page JS.
This commit is contained in:
parent
e2cb8df670
commit
f55f87410a
2 changed files with 49 additions and 7 deletions
|
|
@ -16,6 +16,13 @@ export type ChangelogEntry = {
|
|||
};
|
||||
|
||||
export const CHANGELOG: ChangelogEntry[] = [
|
||||
{
|
||||
id: '2026-07-20b',
|
||||
date: 'July 2026',
|
||||
items: [
|
||||
'No more burst of sound when opening a video: the page we briefly load to grab the stream now stays fully muted until it hands off to the player (or until you tap, for the few sites that play in the web view).',
|
||||
],
|
||||
},
|
||||
{
|
||||
id: '2026-07-20',
|
||||
date: 'July 2026',
|
||||
|
|
|
|||
|
|
@ -994,18 +994,53 @@ const INJECTED_JS = `
|
|||
if (window.__goonPatched) return;
|
||||
window.__goonPatched = true;
|
||||
|
||||
// -- 0a. Mute autoplay until the FIRST user gesture (kills the brief unmuted-audio
|
||||
// flash gdy WebView otwiera stronę żeby przechwycić stream, report dccc05e4).
|
||||
// Override play() PRZED page JS: bez gestu → muted; po tapie usera → dźwięk
|
||||
// dozwolony (zgodne z "dźwięk dopiero po geście usera"). Element-level mute
|
||||
// niżej łapał za późno (autoplay z dźwiękiem zdążył ruszyć).
|
||||
// -- 0a. Mute autoplay until the FIRST user gesture (kills the unmuted-audio flash
|
||||
// gdy WebView otwiera stronę żeby przechwycić stream, report dccc05e4).
|
||||
// Sam override play() nie wystarczał: player hostera po starcie ustawiał
|
||||
// \`video.muted = false\` / \`video.volume = 1\` i dźwięk wracał (raport usera
|
||||
// 2026-07-20: "łapie z głosem przed ExoPlayerem"). Więc LOCKUJEMY muted/volume
|
||||
// na poziomie prototypu — każda próba odciszenia PRZED gestem jest ignorowana.
|
||||
// Po tapie usera (watch-in-WebView dla CF-blocked hosterów) odblokowujemy i
|
||||
// odciszamy. W ścieżce scrape→native gestu nie ma → WebView zostaje niemy do
|
||||
// końca (i tak go nie słychać, gra ExoPlayer). Patch leci
|
||||
// injectedJavaScriptBeforeContentLoaded, więc jest PRZED elementami page JS.
|
||||
try {
|
||||
var _goonOrigPlay = HTMLMediaElement.prototype.play;
|
||||
HTMLMediaElement.prototype.play = function() {
|
||||
if (!window.__goonUserGestured) { try { this.muted = true; } catch (e) {} }
|
||||
if (!window.__goonUserGestured) { try { this.muted = true; this.volume = 0; } catch (e) {} }
|
||||
return _goonOrigPlay.apply(this, arguments);
|
||||
};
|
||||
var _goonAllowSound = function() { window.__goonUserGestured = true; };
|
||||
var _mDesc = Object.getOwnPropertyDescriptor(HTMLMediaElement.prototype, 'muted');
|
||||
if (_mDesc && _mDesc.get && _mDesc.set) {
|
||||
Object.defineProperty(HTMLMediaElement.prototype, 'muted', {
|
||||
configurable: true,
|
||||
get: function() { return _mDesc.get.call(this); },
|
||||
set: function(v) {
|
||||
if (!window.__goonUserGestured && v === false) { _mDesc.set.call(this, true); return; }
|
||||
_mDesc.set.call(this, v);
|
||||
},
|
||||
});
|
||||
}
|
||||
var _vDesc = Object.getOwnPropertyDescriptor(HTMLMediaElement.prototype, 'volume');
|
||||
if (_vDesc && _vDesc.get && _vDesc.set) {
|
||||
Object.defineProperty(HTMLMediaElement.prototype, 'volume', {
|
||||
configurable: true,
|
||||
get: function() { return _vDesc.get.call(this); },
|
||||
set: function(v) {
|
||||
if (!window.__goonUserGestured && v > 0) { _vDesc.set.call(this, 0); return; }
|
||||
_vDesc.set.call(this, v);
|
||||
},
|
||||
});
|
||||
}
|
||||
var _goonAllowSound = function() {
|
||||
if (window.__goonUserGestured) return;
|
||||
window.__goonUserGestured = true;
|
||||
// User tapnął → chce dźwięk: odcisz wszystko co już gra (watch-in-WebView).
|
||||
try {
|
||||
var els = document.querySelectorAll('video, audio');
|
||||
for (var i = 0; i < els.length; i++) { try { els[i].muted = false; els[i].volume = 1; } catch (e) {} }
|
||||
} catch (e) {}
|
||||
};
|
||||
window.addEventListener('touchstart', _goonAllowSound, { once: true, capture: true });
|
||||
window.addEventListener('click', _goonAllowSound, { once: true, capture: true });
|
||||
} catch (e) {}
|
||||
|
|
|
|||
Loading…
Add table
Reference in a new issue