yenren
yenren

Reputation: 501

Chrome Extension: Play a notification sound when a web page element content changes

I want to monitor a dynamically changing value on a web page with a Chrome extension (only for my own use) and play a notification sound and display an alert when that value changes. This page is not necessarily in the active tab.

I have the following code so far, the only thing I need to do is to trigger the background.js when the value changes. My question is how to do that.

manifest.json

{
    "manifest_version": 2,
    "name": "Example Website Notifications",
    "description": "Displays notifications on Example Website.",
    "version": "1.0",

    "background": {
        "scripts": ["background.js"],
        "persistent": false
    },

    "content_scripts": [{
        "matches": ["https://www.example.com/*"],
        "js": ["jquery.js", "content.js"]
    }]
}

content.js

var value = $('#element').html();

window.setInterval(function() {
    var newValue = $('#element').html();
    if (newValue != value) {
        /* Run code in background.js */
        value = newValue;
    }
}, 5000);

I am checking the value in intervals of 5s. If there is a way to "know" when the value change happens, instead of checking every 5s, I am also open to that.

background.js

var sound = new Audio('sound.mp3').play();
alert('Value Changed');

The reason I have alert() in addition to the sound notification is so that the browser window icon will blink in the task bar, in case I miss hearing the sound alert.

When I tested background.js to see if the audio plays, the alert is displayed first, then the audio is played after clicking OK on the alert, even though the line to play the audio file comes before. Any ideas why that happens?

Upvotes: 1

Views: 8760

Answers (1)

Xan
Xan

Reputation: 77521

To communicate an event to a background page, you can use Messaging.

Example (slightly overengineered to be extensible):

// content.js
chrome.runtime.sendMessage({type: "alertUser"});

// background.js
chrome.runtime.onMessage.addListener(function(message, sender, sendResponse) {
  switch(message.type) {
    case "alertUser":
      /* play sound, draw attention */
      break;
  }
});

Note, you don't have to use the horrifying alert for the purpose of drawing attention. There's windows API for that:

// Assuming you have `sender` from the messaging API

// This will make the window blink/draw attention in the taskbar or equivalent
chrome.windows.update(sender.tab.windowId, {drawAttention: true});
// Optionally, switch to the tab inside the window as well
chrome.tabs.update(sender.tab.id, {active: true});

alert should be considered harmful: it suspends JS execution until dismissed, which explains the effect (delayed playback) that you experience. It should be avoided.

Another "organic" method of visually notifying a user would be to use toast-style notifications with notification API. It's far less ambiguous than the browser icon flashing.

If there is a way to "know" when the value change happens, instead of checking every 5s, I am also open to that.

Yes; primarily, with a tool called Mutation Observers. See this canonical question on the topic.

Upvotes: 2

Related Questions