如何防止浏览器预加载 <video> 标签?
How do I prevent the browser from preloading the <video> tag?
我用 JavaScript 为 Chrome 编写了一个用户脚本扩展,以防止在页面加载时自动下载视频和音频标签
这是代码:
var videoTags = document.getElementsByTagName("Video");
var i;
for(i=0; i<videoTags.length; i++)
{
videoTags[i].setAttribute("preload", "none");
videoTags[i].removeAttribute("autoplay");
}
var audioTags = document.getElementsByTagName("audio");
var i;
for(i=0; i<audioTags.length; i++)
{
audioTags[i].setAttribute("preload", "none");
audioTags[i].removeAttribute("autoplay");
}
这是 manifest.json 文件:
{
"content_scripts": [ {
"exclude_globs": [ ],
"exclude_matches": [ ],
"include_globs": [ "*" ],
"js": [ "script.js" ],
"matches": [ "http://*/*", "https://*/*" ],
"run_at": "document_start"
} ],
"converted_from_user_script": true,
"description": "",
"key": "an2xaeZJluPfnpmcsHPXI4aajQPL1cBm5C2kKjaQwXA=",
"name": "test.user.js",
"version": "1.0"
}
问题是我的脚本会在片刻之后运行,然后浏览器 (Chrome) 下载 video/audio 文件的一部分。
检查你认为的是否真的发生了。这应该是不可能的,因为 "run_at": "document_start"
和 "run_at": "document_end"
都应该在加载任何内容之前使您的代码 运行。
来自 developer.chrome.com 中的文档:
In the case of "document_start", the files are injected after any files from css, but before any other DOM is constructed or any other script is run.
In the case of "document_end", the files are injected immediately after the DOM is complete, but before subresources like images and frames have loaded.
此外,由于 document_start
中的代码 运行,document.getElementsByTagName("Video")
应该会失败,因为甚至还没有构造 DOM。
尝试调试您的代码(从检查控制台中的错误开始)。此外,请在此处阅读有关 "run_at"
属性的更多信息:https://developer.chrome.com/extensions/content_scripts#run_at
尝试存储 <audio>
、<video>
src
值,然后从 <audio>
、<video>
元素中删除 src
属性以设置 preload
, autoplay
属性;使用 DOMContentLoaded
事件
The DOMContentLoaded
event is fired when the initial HTML document
has been completely loaded and parsed, without waiting for
stylesheets, images, and subframes to finish loading.
<!DOCTYPE html>
<html xmlns="http://www.w3.org/1999/xhtml">
<head>
<script>
var sources = [];
document.addEventListener("DOMContentLoaded", function(event) {
var media = document.querySelectorAll("audio, video");
[].forEach.call(media, function(el) {
if (el.src) {
sources.push(el.src);
el.removeAttribute("src");
}
var src = el.querySelectorAll("source");
if (src.length) {
[].forEach.call(src, function(source) {
sources.push(source.src);
source.removeAttribute("src");
});
};
});
console.log(sources);
});
</script>
</head>
<body style="height:270px">
<video src="http://mirrors.creativecommons.org/movingimages/webm/ScienceCommonsJesseDylan_240p.webm" controls></video>
<audio controls>
<source src="https://upload.wikimedia.org/wikipedia/commons/6/6e/Micronesia_National_Anthem.ogg" type="video/ogg" />
</audio>
</body>
</html>
编辑、更新
can you test it in user script ?
在 manifest.json
中使用 content_scripts
、"run_at": "document_start"
作为 chromium、chrome 扩展返回预期结果;也就是说,<audio>
、<video>
、<source>
元素的 src
属性应该从 document
中删除。
manifest.json
{
"manifest_version": 2,
"name": "blockmedia",
"description": "remove src from audio, video elements",
"version": "1.0",
"permissions": ["<all_urls>"],
"content_scripts": [
{
"matches": ["<all_urls>"],
"js": ["script.js"],
"run_at": "document_start"
}
]
}
script.js
var sources = [];
document.addEventListener("DOMContentLoaded", function(event) {
var media = document.querySelectorAll("audio, video");
[].forEach.call(media, function(el) {
if (el.src) {
sources.push(el.src);
el.removeAttribute("src");
}
var src = el.querySelectorAll("source");
if (src.length) {
[].forEach.call(src, function(source) {
sources.push(source.src);
source.removeAttribute("src");
});
};
});
console.log(sources);
});
一个似乎可行的肮脏解决方案是使用用户脚本中的 MutationObserver
,一旦您确定它在文档开始时确实 运行。
这个 TamperMonkey 脚本对我有用:
// ==UserScript==
// @name Block videos preloading
// @include *
// @run-at document-start
// ==/UserScript==
(function() {
'use strict';
var observer = new MutationObserver(function(mutations) {
mutations.forEach(function(mutation) {
var nodes = mutation.addedNodes;
for (var i = 0; i < nodes.length; i++) {
if (nodes[i].nodeName == "VIDEO") {
nodes[i].setAttribute('preload', 'none');
nodes[i].removeAttribute('autoplay');
}
}
})
});
observer.observe(document.documentElement, {
childList: true,
subtree: true
});
})();
如果您不希望脚本随后插入其他视频元素,您可能希望在 DOMContentLoaded
上调用 observer.disconnect()
。
您正在与 Chrome 解析器预加载器作斗争。
即使您使用 Mutation Observer 或上面建议的其他技术在文档开始时注入内容脚本,您仍然无法在浏览器预加载器之前激活 HTML。
阅读这篇文章,对我有帮助。
https://andydavies.me/blog/2013/10/22/how-the-browser-pre-loader-makes-pages-load-faster/
要实现你想做的事情,你将需要使用 Chrome webRequest API 来阻止请求。
https://developer.chrome.com/extensions/webRequest
您需要根据媒体类型过滤请求,然后在 headers 中搜索要阻止的文件类型。
我用 JavaScript 为 Chrome 编写了一个用户脚本扩展,以防止在页面加载时自动下载视频和音频标签
这是代码:
var videoTags = document.getElementsByTagName("Video");
var i;
for(i=0; i<videoTags.length; i++)
{
videoTags[i].setAttribute("preload", "none");
videoTags[i].removeAttribute("autoplay");
}
var audioTags = document.getElementsByTagName("audio");
var i;
for(i=0; i<audioTags.length; i++)
{
audioTags[i].setAttribute("preload", "none");
audioTags[i].removeAttribute("autoplay");
}
这是 manifest.json 文件:
{
"content_scripts": [ {
"exclude_globs": [ ],
"exclude_matches": [ ],
"include_globs": [ "*" ],
"js": [ "script.js" ],
"matches": [ "http://*/*", "https://*/*" ],
"run_at": "document_start"
} ],
"converted_from_user_script": true,
"description": "",
"key": "an2xaeZJluPfnpmcsHPXI4aajQPL1cBm5C2kKjaQwXA=",
"name": "test.user.js",
"version": "1.0"
}
问题是我的脚本会在片刻之后运行,然后浏览器 (Chrome) 下载 video/audio 文件的一部分。
检查你认为的是否真的发生了。这应该是不可能的,因为 "run_at": "document_start"
和 "run_at": "document_end"
都应该在加载任何内容之前使您的代码 运行。
来自 developer.chrome.com 中的文档:
In the case of "document_start", the files are injected after any files from css, but before any other DOM is constructed or any other script is run.
In the case of "document_end", the files are injected immediately after the DOM is complete, but before subresources like images and frames have loaded.
此外,由于 document_start
中的代码 运行,document.getElementsByTagName("Video")
应该会失败,因为甚至还没有构造 DOM。
尝试调试您的代码(从检查控制台中的错误开始)。此外,请在此处阅读有关 "run_at"
属性的更多信息:https://developer.chrome.com/extensions/content_scripts#run_at
尝试存储 <audio>
、<video>
src
值,然后从 <audio>
、<video>
元素中删除 src
属性以设置 preload
, autoplay
属性;使用 DOMContentLoaded
事件
The
DOMContentLoaded
event is fired when the initial HTML document has been completely loaded and parsed, without waiting for stylesheets, images, and subframes to finish loading.
<!DOCTYPE html>
<html xmlns="http://www.w3.org/1999/xhtml">
<head>
<script>
var sources = [];
document.addEventListener("DOMContentLoaded", function(event) {
var media = document.querySelectorAll("audio, video");
[].forEach.call(media, function(el) {
if (el.src) {
sources.push(el.src);
el.removeAttribute("src");
}
var src = el.querySelectorAll("source");
if (src.length) {
[].forEach.call(src, function(source) {
sources.push(source.src);
source.removeAttribute("src");
});
};
});
console.log(sources);
});
</script>
</head>
<body style="height:270px">
<video src="http://mirrors.creativecommons.org/movingimages/webm/ScienceCommonsJesseDylan_240p.webm" controls></video>
<audio controls>
<source src="https://upload.wikimedia.org/wikipedia/commons/6/6e/Micronesia_National_Anthem.ogg" type="video/ogg" />
</audio>
</body>
</html>
编辑、更新
can you test it in user script ?
在 manifest.json
中使用 content_scripts
、"run_at": "document_start"
作为 chromium、chrome 扩展返回预期结果;也就是说,<audio>
、<video>
、<source>
元素的 src
属性应该从 document
中删除。
manifest.json
{
"manifest_version": 2,
"name": "blockmedia",
"description": "remove src from audio, video elements",
"version": "1.0",
"permissions": ["<all_urls>"],
"content_scripts": [
{
"matches": ["<all_urls>"],
"js": ["script.js"],
"run_at": "document_start"
}
]
}
script.js
var sources = [];
document.addEventListener("DOMContentLoaded", function(event) {
var media = document.querySelectorAll("audio, video");
[].forEach.call(media, function(el) {
if (el.src) {
sources.push(el.src);
el.removeAttribute("src");
}
var src = el.querySelectorAll("source");
if (src.length) {
[].forEach.call(src, function(source) {
sources.push(source.src);
source.removeAttribute("src");
});
};
});
console.log(sources);
});
一个似乎可行的肮脏解决方案是使用用户脚本中的 MutationObserver
,一旦您确定它在文档开始时确实 运行。
这个 TamperMonkey 脚本对我有用:
// ==UserScript==
// @name Block videos preloading
// @include *
// @run-at document-start
// ==/UserScript==
(function() {
'use strict';
var observer = new MutationObserver(function(mutations) {
mutations.forEach(function(mutation) {
var nodes = mutation.addedNodes;
for (var i = 0; i < nodes.length; i++) {
if (nodes[i].nodeName == "VIDEO") {
nodes[i].setAttribute('preload', 'none');
nodes[i].removeAttribute('autoplay');
}
}
})
});
observer.observe(document.documentElement, {
childList: true,
subtree: true
});
})();
如果您不希望脚本随后插入其他视频元素,您可能希望在 DOMContentLoaded
上调用 observer.disconnect()
。
您正在与 Chrome 解析器预加载器作斗争。
即使您使用 Mutation Observer 或上面建议的其他技术在文档开始时注入内容脚本,您仍然无法在浏览器预加载器之前激活 HTML。
阅读这篇文章,对我有帮助。
https://andydavies.me/blog/2013/10/22/how-the-browser-pre-loader-makes-pages-load-faster/
要实现你想做的事情,你将需要使用 Chrome webRequest API 来阻止请求。
https://developer.chrome.com/extensions/webRequest
您需要根据媒体类型过滤请求,然后在 headers 中搜索要阻止的文件类型。