Javascript 在userscript中编辑音频元素音量
我正在编写一个用户脚本,试图减少过于响亮的音频元素。如何访问已创建但未放置在DOM anywhere中的音频元素 在网站本身,它有一些类似于:Javascript 在userscript中编辑音频元素音量,javascript,html5-audio,userscripts,Javascript,Html5 Audio,Userscripts,我正在编写一个用户脚本,试图减少过于响亮的音频元素。如何访问已创建但未放置在DOM anywhere中的音频元素 在网站本身,它有一些类似于: function () { var audioElement = document.createElement('audio'); audioElement.setAttribute('src', 'http://www.example.com/sound.mp3'); callbackFn = function() {
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();
};
//...
}();
在我的userscript中,我想做如下事情
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();
};
// ...
}();
不过,我似乎无法访问它。我真的不明白这些东西住在哪里。如果它们不在DOM中,如何播放它们?它们似乎存在于文档中的某个地方,因为它们可以播放,但我不知道如何找到它们。因为
callbackFn
是异步调用的,所以可以更改HTMLMEDIALEMENT。prototype
的setter在其volume
属性上,因此,对您感兴趣的带有src
的元素上的卷所做的更改将导致调用原始setter时使用默认值的1/10卷:
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);
}
});
当然,请注意,这只是当您无法更改页面的现有JS时的一种攻击,例如使用用户脚本
我正在寻找一种方法来访问网页中存在但尚未添加到DOM中的音频元素
可以肯定的是,这样做的唯一方法是使用类似于重写
文档的黑客。createElement
的代码在使用createElement
的页面代码运行之前运行。考虑到问题中的代码以及现代浏览器的自动播放
策略已经改变的事实,如果您找到DOM
中的哪个元素在用户操作后开始媒体播放,则可以删除事件处理程序,并使用设置volume
并调用原始处理程序的函数替换事件处理程序,例如
<!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>
点击
(功能(){
var audioElement=document.createElement('audio');
audioElement.setAttribute('src','https://upload.wikimedia.org/wikipedia/commons/6/6e/Micronesia_National_Anthem.ogg');
callbackFn=函数(){
audioElement.load();
audioElement.play();
};
document.onclick=callbackFn;
//...
功能截取(音量、音频元素){
const fn=document.onclick;
document.onclick=null;
document.onmouseup=函数(){
audioElement.volume=音量;
fn();
};
}
截距(.2,音频元素)
})();
plnkr该站点的Javascript多久运行一次?在函数执行之前,你能自己运行任何东西吗?(可能会发布一个到站点的链接,这样我们就可以自己测试解决方案了?)可以创建和播放音频对象,而不必成为DOM层次结构的一部分。在这种情况下,您需要手动跟踪音频对象的集合,而不是依靠文档查询来获取音频对象。考虑到最近更改的浏览器自动播放策略,一些用户操作应该调用
callbackFn
,否则htmlmediaoelement
不应该以任何音量输出音频。什么用户操作会触发音频播放?@CertainPerformance FWIW如果问题OP中包含了所有代码,则只需在单击
或参考audioElement
触发媒体播放的其他用户操作事件处移除并替换处理程序即可<代码>让a=Element附加ClickEvent;a、 removeEventListener('click',callbackFn);a、 addEventListener('click',modifiedCallbackFn/*set volume*/)@CertainPerformance是我写这篇文章的目的地,当前的用户脚本正在(虽然目前不起作用)现场演示:(虽然只需将代码粘贴到OP页面上的用户脚本中比较容易,但它确实起作用。).volume
可以随时设置,无论何时设置.src
,这种方法都完全忽略src
部分,只截获更改.volume
的调用