0

Using Tampermonkey, I have set up a script that monitors a webpage and alerts me whenever a set of conditions are met.

It works fine as long as the page has focus and being interacted with which is not the point of the script. It is meant to monitor the page while in background (open tab but not selected).

It seems to be due to the Chrome's Autoplay policy as explained by the console's warning:

The AudioContext was not allowed to start. It must be resumed (or created) after a user gesture on the page. https://developer.chrome.com/blog/autoplay/#webaudio

Is there anyway to bypass this limitation?

Otherwise, feel free to suggest any other way to achieve the following: In Tampermonkey, start an audio alarm on demand whenever a given condition is met on a given page. The page is opened but has no focus necessarily.

Working snippet:

let audioCtx = new (window.AudioContext || window.webkitAudioContext)();
const url = 'https://assets.mixkit.co/active_storage/sfx/1005/1005.wav';
function playAlarm() {
  GM.xmlHttpRequest({
    method: "GET",
    url: url,
    responseType: 'arraybuffer',
    onload: function(response) {

      let playsound = (audioBuffer) => {
        let source = audioCtx.createBufferSource();
        source.buffer = audioBuffer;
        source.connect(audioCtx.destination);
        source.loop = false;
        source.start();

        // recursive call!
        setTimeout(function () {
          playsound(audioBuffer);
        }, 10000 + Math.random()*2500);
      };
      audioCtx.decodeAudioData(response.response).then(playsound);
    }
  });
}
cssyphus
  • 37,875
  • 18
  • 96
  • 111
Enissay
  • 4,969
  • 3
  • 29
  • 56
  • 2
    Does this answer your question? [Audio file not playing with userscript in tampermoney](https://stackoverflow.com/questions/51982540/audio-file-not-playing-with-userscript-in-tampermoney) – double-beep Feb 26 '23 at 14:06
  • @double-beep Sadly there is no such flag in chrome anymore :[ – Enissay Feb 26 '23 at 14:50

1 Answers1

0

Edit: I should note that I do this myself on a webpage... I use the AudioContext to play sounds when certain conditions are met, same as you are asking - and I ran into the problem of the code not working when the web page lost the focus (i.e. was not actively-engaged). (HOWEVER I am not doing this via a TamperMonkey script...) The following solution worked for me on a self-managed web page, I see no reason why it would not help with TamperMonkey -- in fact, it was through TamperMonkey scripting (and wOxxOm-the-brilliant) that I first discovered these particular properties of web workers.


The AudioContext does require a user gesture on the page to be allowed to play audio, but that is only required once. If you load the page and then move your mouse, the AudioContext will be enabled henceforth after that.

What you might be running into is the throttling of the page's javascript when that tab no longer has the focus. (But, to be sure, when you first open that particular page you must move the mouse over the page - Audio is now enabled.)

The solution to that is to use a web worker. A web worker is just a second javascript file that is initiated as a new Worker in the main script. For some mysterious reason, web workers are NOT throttled, and the main script "wakes up" every time it gets a message from the worker -- allowing you to essentially remove the throttling.

CAUTION - Web Workers cannot themselves access the DOM - so for your specific application, the important thing to note is that the main script "wakes up" every time it gets a message from the web worker. Perhaps every time the main script wakes up, it can check the page and see if your condition is met, and then do something.

MAIN SCRIPT:

let myWorker = new Worker('secondjs.js');

//IF you need to send data to the worker:
ouiworker.postMessage( {someData:'this is my data'} );

//READING messages coming back from the worker:
ouiworker.onmessage = function (e){
   console.log(`Worker said: ${ e.data }`);
}


SECONDJS.JS (the worker)

let my_global='What it was';

//Check for messages from the main script
self.addEventListener('message', function(e){
   let data = e.data;
   my_global = data.someData;
}

function my_loop(){
   //watch for something - perhaps a change in the DB
   if (myThingFound){
      this.self.postMessage( 'This is the service worker speaking...' );
   }
   //Also check for incoming messages from main script
   if ( my_global !== 'What it was' ){
      //do something
   }

   setTimeout( () => { my_loop() },1000);
}

setTimeout( () => { my_loop() },1000);

Resources:

Web workers vs Service workers

What can service workers do that web workers cannot?

Web Workers - A Beginners Guide - 8 min Video Tutorial

cssyphus
  • 37,875
  • 18
  • 96
  • 111