1+ ( function ( ) {
2+ // Initialize state if not exists
3+ if ( ! window . _mediaControlState ) {
4+ window . _mediaControlState = {
5+ observer : null ,
6+ userInitiated : false ,
7+ originalPlay : HTMLMediaElement . prototype . play ,
8+ originalLoad : HTMLMediaElement . prototype . load ,
9+ isPaused : false
10+ } ;
11+ }
12+ const state = window . _mediaControlState ;
13+
14+ // Block playback handler
15+ const blockPlayback = function ( event ) {
16+ event . preventDefault ( ) ;
17+ event . stopPropagation ( ) ;
18+ return false ;
19+ } ;
20+
21+ // The actual media control function
22+ function mediaControl ( pause ) {
23+ state . isPaused = pause ;
24+
25+ if ( pause ) {
26+ // Capture play events at the earliest possible moment
27+ document . addEventListener ( 'play' , blockPlayback , true ) ;
28+ document . addEventListener ( 'playing' , blockPlayback , true ) ;
29+
30+ // Block HTML5 video/audio playback methods
31+ HTMLMediaElement . prototype . play = function ( ) {
32+ this . pause ( ) ;
33+ return Promise . reject ( new Error ( 'Playback blocked' ) ) ;
34+ } ;
35+
36+ // Override load to ensure media starts paused
37+ HTMLMediaElement . prototype . load = function ( ) {
38+ this . autoplay = false ;
39+ this . pause ( ) ;
40+ return state . originalLoad . apply ( this , arguments ) ;
41+ } ;
42+
43+ // Listen for user interactions that may lead to playback
44+ document . addEventListener ( 'touchstart' , ( ) => {
45+ state . userInitiated = true ;
46+
47+ // Remove the early blocking listeners
48+ document . removeEventListener ( 'play' , blockPlayback , true ) ;
49+ document . removeEventListener ( 'playing' , blockPlayback , true ) ;
50+
51+ // Reset HTMLMediaElement.prototype.play
52+ HTMLMediaElement . prototype . play = state . originalPlay ;
53+
54+ // Unmute all media elements when user interacts
55+ document . querySelectorAll ( 'audio, video' ) . forEach ( media => {
56+ media . muted = false ;
57+ } ) ;
58+
59+ // Reset after a short delay
60+ setTimeout ( ( ) => {
61+ state . userInitiated = false ;
62+
63+ // Re-add blocking if still in paused state
64+ if ( state . isPaused ) {
65+ document . addEventListener ( 'play' , blockPlayback , true ) ;
66+ document . addEventListener ( 'playing' , blockPlayback , true ) ;
67+ HTMLMediaElement . prototype . play = function ( ) {
68+ this . pause ( ) ;
69+ return Promise . reject ( new Error ( 'Playback blocked' ) ) ;
70+ } ;
71+ }
72+ } , 500 ) ;
73+ } , true ) ;
74+
75+ // Initial pause of all media
76+ document . querySelectorAll ( 'audio, video' ) . forEach ( media => {
77+ media . pause ( ) ;
78+ media . muted = true ;
79+ media . autoplay = false ;
80+ } ) ;
81+
82+ // Monitor DOM for newly added media elements
83+ if ( state . observer ) {
84+ state . observer . disconnect ( ) ;
85+ }
86+
87+ state . observer = new MutationObserver ( mutations => {
88+ mutations . forEach ( mutation => {
89+ // Check for added nodes
90+ mutation . addedNodes . forEach ( node => {
91+ if ( node . tagName === 'VIDEO' || node . tagName === 'AUDIO' ) {
92+ if ( ! state . userInitiated ) {
93+ node . pause ( ) ;
94+ node . muted = true ;
95+ node . autoplay = false ;
96+ }
97+ } else if ( node . querySelectorAll ) {
98+ node . querySelectorAll ( 'audio, video' ) . forEach ( media => {
99+ if ( ! state . userInitiated ) {
100+ media . pause ( ) ;
101+ media . muted = true ;
102+ media . autoplay = false ;
103+ }
104+ } ) ;
105+ }
106+ } ) ;
107+ } ) ;
108+ } ) ;
109+
110+ state . observer . observe ( document . documentElement || document . body , {
111+ childList : true ,
112+ subtree : true ,
113+ attributes : true ,
114+ attributeFilter : [ 'autoplay' , 'src' , 'playing' ]
115+ } ) ;
116+ } else {
117+ // Restore original methods
118+ HTMLMediaElement . prototype . play = state . originalPlay ;
119+ HTMLMediaElement . prototype . load = state . originalLoad ;
120+
121+ // Remove listeners
122+ document . removeEventListener ( 'play' , blockPlayback , true ) ;
123+ document . removeEventListener ( 'playing' , blockPlayback , true ) ;
124+
125+ // Clean up observer
126+ if ( state . observer ) {
127+ state . observer . disconnect ( ) ;
128+ state . observer = null ;
129+ }
130+
131+ // Unmute all media
132+ document . querySelectorAll ( 'audio, video' ) . forEach ( media => {
133+ media . muted = false ;
134+ } ) ;
135+ }
136+ }
137+
138+ // Export function
139+ window . mediaControl = mediaControl ;
140+ } ) ( ) ;
0 commit comments