11// ==UserScript==
22// @name YT Music Autoclicker API (Stealth Trap Edition)
33// @namespace https://github.com/fgirolami29
4- // @version 2.2 .0
5- // @description Bypassa popup YT Music con Notifiche Interattive, IntersectionObserver e API di debug configurabili . Zero errori TS.
4+ // @version 2.3 .0
5+ // @description Bypassa popup YT Music con rilevamento transizioni animating-bezel via MutationObserver, Spacebar emulato e fallback interattivo . Zero errori TS.
66// @author Tu & Gemini
77// @icon data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAACsAAAAgCAYAAACLmoEDAAABo0lEQVR4AdSXAZKDIBAEiR878zL1Zbmf5aY3txaWpqKyWCS1I4jotiMi6VLh75lSv1eFqdIKNks8qv7I9FR9JQE89mrr/KzNc5HXpOsuYgGrE0cd9eSD6n0mVauG5yKvCR7kWWdYNSoSnfxYCyU8g8C4kdcw0A6OtgD3jgHoF6x62I7KVsNe4k6umsWtUmZcA2P2W2DnYZDdQLPVHmd/AvB+A67x8RLAfuy0o8N0S0mRplTxFwVriKJlCqwGDGzoCwawpIh3GVhzJXoj2lFSxEFXg/WbF60PjeLhUR0WaICR6kXAl8AK0oMpDvn+ofISWD7pki89T7/Q1WEFyZgF9DSk218NFkhJEbdGBvb0GPI7zkvRsZzDyfBlJ7B5rtP1DBLQ4ke+BRIFi4vVIB08CvaQk578aAls0UR9NGFJf2BLzr/y3KnTZzB0NqhJ7842PxRk6miwVORIyw6bmQYr0CTgu0prVNlKYOBdbHyyl/9uaZQUCWhEZ3QFPHlc5AYS0Wb5Z2dt738jWlb5iM7opraV1J2ncVhb11IbeVzkniGVx+IPAAD///H503IAAAAGSURBVAMApvWIs8xfbPkAAAAASUVORK5CYII=
88// @include *://music.youtube.com/**
1313/* eslint-env browser, greasemonkey */
1414/* global globalThis */
1515
16- const VERSION = '2.2 .0' ;
16+ const VERSION = '2.3 .0' ;
1717const ICON_BASE64 =
1818 'data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAACsAAAAgCAYAAACLmoEDAAABo0lEQVR4AdSXAZKDIBAEiR878zL1Zbmf5aY3txaWpqKyWCS1I4jotiMi6VLh75lSv1eFqdIKNks8qv7I9FR9JQE89mrr/KzNc5HXpOsuYgGrE0cd9eSD6n0mVauG5yKvCR7kWWdYNSoSnfxYCyU8g8C4kdcw0A6OtgD3jgHoF6x62I7KVsNe4k6umsWtUmZcA2P2W2DnYZDdQLPVHmd/AvB+A67x8RLAfuy0o8N0S0mRplTxFwVriKJlCqwGDGzoCwawpIh3GVhzJXoj2lFSxEFXg/WbF60PjeLhUR0WaICR6kXAl8AK0oMpDvn+ofISWD7pki89T7/Q1WEFyZgF9DSk218NFkhJEbdGBvb0GPI7zkvRsZzDyfBlJ7B5rtP1DBLQ4ke+BRIFi4vVIB08CvaQk578aAls0UR9NGFJf2BLzr/y3KnTZzB0NqhJ7842PxRk6miwVORIyw6bmQYr0CTgu0prVNlKYOBdbHyyl/9uaZQUCWhEZ3QFPHlc5AYS0Wb5Z2dt738jWlb5iM7opraV1J2ncVhb11IbeVzkniGVx+IPAAD///H503IAAAAGSURBVAMApvWIs8xfbPkAAAAASUVORK5CYII=' ;
1919
@@ -23,6 +23,7 @@ const ICON_BASE64 =
2323 * @property {number } maxAttempts - Numero massimo di iterazioni del loop prima del timeout.
2424 * @property {number } restartDelayMs - Ritardo avvio loop dopo il click sulla notifica (ms).
2525 * @property {number } observerThreshold - Ratio di visibilità per triggerare l'observer (0.0 - 1.0).
26+ * @property {number } fallbackTimeoutMs - Tempo limite per l'attuazione dell'evento prima del fallback interattivo (ms).
2627 * @property {boolean } debugMode - Flag per abilitare/disabilitare l'output di debug.
2728 */
2829
@@ -32,6 +33,7 @@ const CONFIG = {
3233 maxAttempts : 50 ,
3334 restartDelayMs : 150 ,
3435 observerThreshold : 0.1 ,
36+ fallbackTimeoutMs : 1500 ,
3537 debugMode : true ,
3638} ;
3739
@@ -49,10 +51,11 @@ const CONFIG = {
4951 * @property {() => void } forceClick
5052 * @property {(delayMs?: number) => void } testTrap
5153 * @property {Function } notify
52- * @property {{ yesButton: () => Element | null, modal: () => Element | null } } DOM
54+ * @property {{ yesButton: () => Element | null, modal: () => Element | null, player: () => Element | null } } DOM
5355 * @property {number | undefined } [interval]
5456 * @property {MutationObserver | undefined } [bodyObserver]
5557 * @property {IntersectionObserver | undefined } [visibilityObserver]
58+ * @property {MutationObserver | undefined } [playerObserver]
5659 */
5760
5861 /** @type {any } */
@@ -167,10 +170,12 @@ const CONFIG = {
167170 document . querySelector ( 'yt-button-renderer[dialog-confirm] button' ) ||
168171 document . querySelector ( 'ytmusic-you-there-renderer button' ) ,
169172 modal : ( ) => document . querySelector ( 'ytmusic-you-there-renderer' ) ,
173+ player : ( ) => document . querySelector ( 'ytmusic-player' ) ,
170174 } ,
171175 interval : undefined ,
172176 bodyObserver : undefined ,
173177 visibilityObserver : undefined ,
178+ playerObserver : undefined ,
174179 } ;
175180
176181 const startClickLoop = ( ) => {
@@ -232,17 +237,76 @@ const CONFIG = {
232237 ( entries ) => {
233238 for ( const entry of entries ) {
234239 if ( entry . isIntersecting ) {
235- debug ( '⚠️ Il modal di pausa è apparso! Innesco la notifica-trappola...' ) ;
236-
237- // Sospende l'esecuzione e attende il click sulla notifica
238- sendInteractiveNotification (
239- 'YT Music in Pausa ⏸️' ,
240- 'YouTube chiede se ci sei. Clicca qui per riprendere la musica!' ,
241- ( ) => {
242- debug ( "Notifica cliccata! Riprendo l'ascolto e chiudo il popup." ) ;
243- setTimeout ( startClickLoop , CONFIG . restartDelayMs ) ;
244- } ,
245- ) ;
240+ debug ( '⚠️ Il modal di pausa è apparso! Iniezione evento Spacebar ed esame del player...' ) ;
241+
242+ const playerEl = API . DOM . player ( ) ;
243+ let isBypassed = false ;
244+ let fallbackTimeout = null ;
245+
246+ // Funzione di clean-up dei listener temporanei per l'evento corrente
247+ const clearBypassContext = ( ) => {
248+ if ( API . playerObserver ) {
249+ API . playerObserver . disconnect ( ) ;
250+ API . playerObserver = undefined ;
251+ }
252+ if ( fallbackTimeout ) {
253+ clearTimeout ( fallbackTimeout ) ;
254+ fallbackTimeout = null ;
255+ }
256+ } ;
257+
258+ if ( playerEl ) {
259+ // Monitoraggio mutazioni attributi su ytmusic-player
260+ API . playerObserver = new MutationObserver ( ( mutations ) => {
261+ for ( const mutation of mutations ) {
262+ if ( mutation . attributeName === 'animating-bezel' || playerEl . hasAttribute ( 'animating-bezel' ) ) {
263+ isBypassed = true ;
264+ clearBypassContext ( ) ;
265+ debug ( '🎉 Transizione "animating-bezel" intercettata. Riproduzione riavviata.' ) ;
266+
267+ sendInteractiveNotification (
268+ 'Bypass COMPLETATO! ✅' ,
269+ 'La riproduzione è stata ripristinata automaticamente.' ,
270+ ) ;
271+
272+ // Avvio loop di allineamento DOM per forzare la chiusura del modal residuo
273+ setTimeout ( startClickLoop , CONFIG . restartDelayMs ) ;
274+ break ;
275+ }
276+ }
277+ } ) ;
278+
279+ API . playerObserver . observe ( playerEl , {
280+ attributes : true ,
281+ attributeFilter : [ 'animating-bezel' ] ,
282+ } ) ;
283+ }
284+
285+ // Generazione e dispatch dell'evento sintetico KeyboardEvent sul body
286+ const spaceEvent = new KeyboardEvent ( 'keydown' , {
287+ key : ' ' ,
288+ code : 'Space' ,
289+ keyCode : 32 ,
290+ bubbles : true ,
291+ cancelable : true ,
292+ } ) ;
293+ document . body . dispatchEvent ( spaceEvent ) ;
294+
295+ // Fallback di sicurezza (Estrema Unzione): attivato solo se l'evento Spacebar fallisce l'aggancio entro il timeout definito
296+ fallbackTimeout = setTimeout ( ( ) => {
297+ clearBypassContext ( ) ;
298+ if ( ! isBypassed ) {
299+ debug ( '❌ Rilevamento transizione fallito o timeout esaurito. Innesco notifica interattiva standard.' ) ;
300+ sendInteractiveNotification (
301+ 'YT Music in Pausa ⏸️' ,
302+ 'YouTube chiede se ci sei. Clicca qui per riprendere la musica!' ,
303+ ( ) => {
304+ debug ( 'Notifica cliccata! Esecuzione routine di sblocco.' ) ;
305+ setTimeout ( startClickLoop , CONFIG . restartDelayMs ) ;
306+ } ,
307+ ) ;
308+ }
309+ } , CONFIG . fallbackTimeoutMs ) ;
246310 }
247311 }
248312 } ,
@@ -293,6 +357,7 @@ const CONFIG = {
293357 if ( API . interval !== undefined ) clearInterval ( API . interval ) ;
294358 if ( API . bodyObserver ) API . bodyObserver . disconnect ( ) ;
295359 if ( API . visibilityObserver ) API . visibilityObserver . disconnect ( ) ;
360+ if ( API . playerObserver ) API . playerObserver . disconnect ( ) ;
296361 dispatchLog ( 'ytbyp:stop' , 'Tutti gli Observer ARRESTATI.' ) ;
297362 } ;
298363
0 commit comments