I have written a user script extension for Chrome with JavaScript in order to prevent video and audio tags from downloading automatically on pageload
This is the code:
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");
}
And this is the manifest.json file:
{
"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"
}
The problem is that my script runs after a moment and until then the browser (Chrome) downloads a part of video/audio file.
One dirty solution that seems to work is to use a MutationObserver
from your userscript, once you're sure it does run at document-start.
This TamperMonkey script does work for me :
// ==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
});
})();
You may want to call observer.disconnect()
on DOMContentLoaded
, if you're not expecting other video elements for being inserted afterwards by scripts.
Check if what you think really happens. It should be impossible, because both "run_at": "document_start"
and "run_at": "document_end"
should make your code run before anything is loaded.
From the documentation in 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.
In addition, because your code runs in document_start
, the document.getElementsByTagName("Video")
should fail because no DOM is even constructed yet.
Try debugging your code (start with checking for errors in the console). Also, read more about the "run_at"
attribute here: https://developer.chrome.com/extensions/content_scripts#run_at
Try storing <audio>
, <video>
src
value, then remove src
attribute from <audio>
, <video>
elements for setting preload
, autoplay
attributes; using DOMContentLoaded
event
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>
Edit, Updated
can you test it in user script ?
Utilizing content_scripts
, "run_at": "document_start"
in manifest.json
returned expected results as a chromium, chrome extension; that is, src
attribute of <audio>
, <video>
, <source>
elements should be removed from 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);
});
You're battling against the Chrome parser preloader.
Even if you inject a content script at document start, using Mutation Observer or another technique suggested above, you still cannot action the HTML before the browser preloader.
Read this article, which helped me.
https://andydavies.me/blog/2013/10/22/how-the-browser-pre-loader-makes-pages-load-faster/
To achieve what you want to do, you're going to need to use the Chrome webRequest API to block the request.
https://developer.chrome.com/extensions/webRequest
You will need to filter requests according to the media type and then search the headers for the file types you want to block.