I'm writing a userscript to try to decrease an overly loud audio element. How do I get access to an audio element that has been created, but not placed in the DOM anywhere?
On the site itself, it has something akin to:
function () {
var audioElement = document.createElement('audio');
audioElement.setAttribute('src', 'http://www.example.com/sound.mp3');
callbackFn = function() {
audioElement.volume = way_too_high;
audioElement.load();
audioElement.play();
};
//...
}();
In my userscript, I want to do something like
function () {
newCallbackFunction = function() {
var audioElement = document.querySelector('audio'); // doesn't work, presumably because never added to DOM
audioElement.volume = 0.1 * audioElement.volume;
audioElement.load();
audioElement.play();
};
// ...
}();
I can't seem to get access to it, though. I don't really understand where these objects live. If they're not in the DOM, how can they be played? They just seem to exist in the document somewhere since they can be played, but it is not obvious to me how to find them.
Because the callbackFn
is called asynchronously, you can alter HTMLMediaElement.prototype
's setter on its volume
property, so that changes to the volume on an element with the src
you're interested in will result in the original setter being called with a volume 1/10th of what it would be called with by default:
const { prototype } = HTMLMediaElement;
const { set: setter, get: getter } = Object.getOwnPropertyDescriptor(prototype, 'volume');
Object.defineProperty(prototype, 'volume', {
get() {
return getter.call(this);
},
set(arg) {
const newArg = this.src.endsWith('/sounds/warframe_alarm.mp3')
? arg / 10
: arg;
setter.call(this, newArg);
}
});
Of course, note that this is only a hack for when you can't alter the existing JS of a page, such as with a userscript.
I'm looking for a way to access audio elements that exist in the webpage but have not been added to the DOM
Pretty sure the only way to do something like this would be to use a hack like overwriting document.createElement
with code that runs before the page's code that uses createElement
runs.
Given the code at the question and the fact that autoplay
policy of modern browsers have changed, one you locate which element in the DOM
begins media playback after user action you can remove and replace the event handler with a function which sets volume
and calls the original handler, for example
<!DOCTYPE html>
<html>
<head>
</head>
<body>
click
<script>
(function() {
var audioElement = document.createElement('audio');
audioElement.setAttribute('src', 'https://upload.wikimedia.org/wikipedia/commons/6/6e/Micronesia_National_Anthem.ogg');
callbackFn = function() {
audioElement.load();
audioElement.play();
};
document.onclick = callbackFn;
//...
function intercept(volume, audioElement) {
const fn = document.onclick;
document.onclick = null;
document.onmouseup = function() {
audioElement.volume = volume;
fn();
};
}
intercept(.2, audioElement)
})();
</script>
</body>
</html>
The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.