Skip to content

Instantly share code, notes, and snippets.

@adisib
Last active October 30, 2016 19:16
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save adisib/6b0eac4e205691b1c40e1560d9d8edc7 to your computer and use it in GitHub Desktop.
Save adisib/6b0eac4e205691b1c40e1560d9d8edc7 to your computer and use it in GitHub Desktop.
// ==UserScript==
// @name Audio Indicators
// @author adisib
// @namespace namespace_adisib
// @description Show audio indicators (music note) in tabs for Pale Moon browser.
// @include *
// @grant none
// ==/UserScript==
(function(){
"use strict";
// --------------------
function addMediaCheckEvents(node, func)
{
node.addEventListener("pause", func, true);
node.addEventListener("playing", func, true);
node.addEventListener("volumechange", func, true);
node.addEventListener("emptied", func, true);
}
// --------------------
function isPlayingSound(node)
{
if ( ( node )
&& ( !node.paused )
&& ( !node.ended )
&& ( !node.muted && node.volume > 0 )
)
{
return true;
}
else
{
return false;
}
}
// --------------------
function checkPlaying()
{
if (checkPlaying.lastPlayingElement === undefined)
{
checkPlaying.lastPlayingElement = document.getElementsByTagName("audio")[0];
}
let lpe = checkPlaying.lastPlayingElement;
if (isPlayingSound(lpe))
{
return true;
}
let sounds = document.getElementsByTagName("audio");
for (let i=0; i < sounds.length; ++i)
{
let sound = sounds[i];
if (isPlayingSound(sound))
{
checkPlaying.lastPlayingElement = sound;
return true;
}
}
let vids = document.getElementsByTagName("video");
for (let i=0; i < vids.length; ++i)
{
let vid = vids[i];
if (isPlayingSound(vid))
{
checkPlaying.lastPlayingElement = vid;
return true;
}
}
return false;
}
// --------------------
function setAudioIndicator(playing)
{
if (setAudioIndicator.wasPlaying === undefined)
{
setAudioIndicator.wasPlaying = false;
}
if (setAudioIndicator.wasPlaying === playing)
{
return;
}
const indicator = "\u266B ";
if (playing)
{
document.title = indicator + document.title;
setAudioIndicator.wasPlaying = true;
}
else
{
if (document.title.startsWith(indicator))
{
document.title = document.title.slice(indicator.length);
}
setAudioIndicator.wasPlaying = false;
}
}
// --------------------
function updateIndicator()
{
let playing = checkPlaying();
setAudioIndicator(playing);
}
// --------------------
function addedElementHandler(mutations)
{
let sourcesChanged = false;
for (let j=0; j < mutations.length; ++j)
{
let nodes = mutations[j].addedNodes;
for (let i=0; i < nodes.length; ++i)
{
let node = nodes[i];
if (node.tagName === "VIDEO" || node.tagName === "AUDIO")
{
addMediaCheckEvents(node, updateIndicator);
sourcesChanged = true;
}
}
nodes = mutations[j].removedNodes;
for (let i=0; i<nodes.length; ++i)
{
let nodeName = nodes[i].tagName;
if (nodeName === "VIDEO" || nodeName === "AUDIO")
{
sourcesChanged = true;
break;
}
}
}
if (sourcesChanged)
{
updateIndicator();
}
}
// --------------------
function setObservers()
{
let soundElementsMutationObserver = new MutationObserver( addedElementHandler );
let SEMOInitOps = { childList: true, subtree: true };
soundElementsMutationObserver.observe(document.body, SEMOInitOps);
// Title changes can remove the indicator, so make sure to add it back
let titleMutationObserver = new MutationObserver( updateIndicator );
let TMOInitOps = { characterData: true, subtree: true };
titleMutationObserver.observe(document.head.getElementsByTagName("title")[0], TMOInitOps);
let sounds = document.getElementsByTagName("audio");
let vids = document.getElementsByTagName("video");
for (let i=0; i < sounds.length; ++i)
{
addMediaCheckEvents(sounds[i], updateIndicator);
}
for (let i=0; i < vids.length; ++i)
{
addMediaCheckEvents(vids[i], updateIndicator);
}
}
// --------------------
setObservers();
updateIndicator();
})();
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment