fix(scenes): sxyprn detail thumbnail + stronger WebView pre-play mute
Some checks are pending
Backend tests / test (push) Waiting to run

1) _build_scene_out (detal) nie stosował _sxyprn_thumb_url jak lista → detal
pokazywał martwy trafficdeposit URL, refresh nie pomagał (sxyprn IP-bound). Teraz
detal też podmienia na żywy /proxy/sxyprn-thumb/<id>. Backend-only.

2) Mute WebView-scrape: attribute-autoplay (<video autoplay>) omijał override play()
i grał unmuted. Dokładam proaktywne ciszenie na play/loadeddata/volumechange +
poll 40ms do gestu (property-lock trzyma między tickami). Web Audio i tak gated
autoplay-policy. Raport usera: dalej głos przed ExoPlayerem.
This commit is contained in:
goon-foss 2026-07-22 11:16:44 +02:00
parent 3b225c1d5e
commit 2d1800a461
3 changed files with 41 additions and 0 deletions

View file

@ -980,6 +980,15 @@ def _build_scene_out(session: Session, scene: Scene, *, device_id: str = LEGACY_
playback_out: list[PlaybackSourceOut] = []
for p in playback_rows:
out = PlaybackSourceOut.model_validate(p)
# sxyprn: podmień martwy trafficdeposit URL na żywy on-demand resolver
# (/proxy/sxyprn-thumb/<id>) — TAK JAK lista (_build_scenes_out_batch). Bez tego
# detal sceny pokazywał martwą miniaturę sxyprn mimo że lista działała, i "refresh
# thumbnail" nie pomagał (sxyprn IP-bound, enrich z VPS pada). Report 2026-07-22.
sxy = _sxyprn_thumb_url(p.page_url)
if sxy:
out.thumbnail_url = sxy
elif out.thumbnail_url and _is_rotting_thumb(out.thumbnail_url):
out.thumbnail_url = None
# Wrap thumbnail URL-e przez backend image proxy gdy CDN wymaga Refera
# (hqporner — fastporndelivery zwraca 403 bez Referer headera, expo-image
# nie wysyła go domyślnie). Token ma 30-dniowy TTL bo thumby są stabilne.

View file

@ -16,6 +16,13 @@ export type ChangelogEntry = {
};
export const CHANGELOG: ChangelogEntry[] = [
{
id: '2026-07-22b',
date: 'July 2026',
items: [
'The brief burst of sound before a video starts is now fully silenced, including sites whose player auto-plays with sound as the app grabs the stream.',
],
},
{
id: '2026-07-22',
date: 'July 2026',

View file

@ -1043,6 +1043,31 @@ const INJECTED_JS = `
};
window.addEventListener('touchstart', _goonAllowSound, { once: true, capture: true });
window.addEventListener('click', _goonAllowSound, { once: true, capture: true });
// Attribute-autoplay (<video autoplay>) NIE przechodzi przez override play() (wywołanie
// wewnętrzne silnika) i element domyślnie jest UNMUTED → dźwięk buchał mimo locka
// (raport usera 2026-07-22: "dalej stream nie jest wyciszony przed ExoPlayerem").
// Proaktywnie ciszymy: na zdarzeniu 'play'/'loadeddata' (firują też dla attr-autoplay)
// + krótki poll (scrape trwa ~sekundy). Property-lock wyżej trzyma je wyciszone między
// tickami. Web Audio nie ruszamy — przeglądarka i tak gate'uje AudioContext do gestu.
var _goonForceMute = function() {
if (window.__goonUserGestured) return;
try {
var els = document.querySelectorAll('video, audio');
for (var i = 0; i < els.length; i++) {
try { els[i].muted = true; els[i].volume = 0; } catch (e) {}
}
} catch (e) {}
};
document.addEventListener('play', _goonForceMute, { capture: true });
document.addEventListener('loadeddata', _goonForceMute, { capture: true });
document.addEventListener('volumechange', _goonForceMute, { capture: true });
var _goonMutePoll = setInterval(function() {
if (window.__goonUserGestured) { clearInterval(_goonMutePoll); return; }
_goonForceMute();
}, 40);
// Bezpiecznik: przestań pollować po 20s (scrape dawno skończony), nie zżeraj CPU.
setTimeout(function() { try { clearInterval(_goonMutePoll); } catch (e) {} }, 20000);
} catch (e) {}
// -- 0. Anti-adblock detection bypass --------------------------------------