I'm trying to write a Violentmonkey userscript to save youtube thumbnails on my harddrive, but can't get it to work. I think the fact that I'm trying to save images from ytimg.com while being on youtube.com complicates things.
Here is the code I wrote so far, copypaste this into your Web Developer Tools Javascript console, and then click the "TEST" button in the top right corner, here is the YouTube channel I test this on https://www.youtube.com/@user-qm6hx2ud3r/videos. With Firefox it saves the thumbnail, but also opens thumbnail, and I want to stay on the page I am. With Chromium it just throws an error, "has been blocked by CORS policy". Change download2
to download
inside forElement
to see the different approach.
// ==UserScript==
// @name Grab channel info - youtube.com
// @namespace Violentmonkey Scripts
// @match https://www.youtube.com/*
// @grant none
// @version 1.0
// @author -
// @description -
// ==/UserScript==
"mode strict";
function save(url, name) {
const link = document.createElement('a')
link.href = url
link.download = name
link.style.display = 'none';
document.body.appendChild(link)
link.click()
document.body.removeChild(link)
}
function download2(url, name) {
if (!url) return
if (!name) return
var xhr = new XMLHttpRequest();
xhr.onload = function() {
var reader = new FileReader();
reader.onloadend = function() {
//console.log(reader.result);
save(reader.result, name)
}
reader.readAsDataURL(xhr.response);
};
xhr.open('GET', url);
xhr.responseType = 'blob';
xhr.send();
}
async function download(url, name) {
if (!url) return
if (!name) return
const image = await fetch(url)
const imageBlog = await image.blob()
const imageURL = URL.createObjectURL(imageBlog)
const link = document.createElement('a')
link.href = imageURL
//link.download = name
link.style.display = 'none';
document.body.appendChild(link)
link.click()
document.body.removeChild(link)
}
function forElement(el) {
let thumb = el.querySelector('ytd-thumbnail img').src
console.log(thumb)
download2(thumb, "downloaded-thumbnail.webp")
}
function start() {
let testbutton = document.querySelector("button#test")
if (!testbutton) {
document.querySelector('ytd-masthead div#container div#end').insertAdjacentHTML('afterbegin', '<button id="test">TEST</button>')
testbutton = document.querySelector("button#test")
}
testbutton.onclick = function() {
forElement(document.querySelectorAll("div#content.ytd-rich-item-renderer")[0])
}
}
start()
I'm trying to do saving right from the browser because I hope to save a bit of traffic this way, browser already downloaded those thumbnails and I don't want to save an already downloaded thumbnails. I can try making a WebExtensions if a simple userscript isn't enough for this task.
Related resources: https://dev.to/sbodi10/download-images-using-javascript-51a9 Force browser to download image files on click How can I convert an image into Base64 string using JavaScript?
CodePudding user response:
Solved this, If I download https://i.ytimg.com/vi/L96kKIM0Vjo/hqdefault.jpg
instead of https://i.ytimg.com/vi/L96kKIM0Vjo/hqdefault.jpg?lotsofseeminglymeaninglessjibberish
, it works. The price of this is that thumbnail probably gets downloaded the second time, a bit wasteful.
CodePudding user response:
Use the native GM_download
method in combination with GM_getValue
and GM_setValue
to store already downloaded images and avoid downloading them again.
Here's an example:
// ==UserScript==
// @name Grab channel info - youtube.com
// @namespace Violentmonkey Scripts
// @match https://www.youtube.com/*
// @version 1.0
// @author -
// @description -
// @grant GM_getValue
// @grant GM_setValue
// @grant GM_download
// ==/UserScript==
(function() {
'use strict';
function setupStorage() {
const images = GM_getValue('images');
if (!images) {
GM_setValue('images', []);
}
}
function start() {
setupStorage();
const button = document.createElement('button');
button.id = 'test';
button.innerText = 'TEST';
const header = document.querySelector('ytd-masthead div#container div#end');
header.prepend(button);
button.addEventListener('click', () => {
const element = document.querySelectorAll('div#content.ytd-rich-item-renderer')[0];
const thumb = element.querySelector('ytd-thumbnail img').src;
const pathname = new URL(thumb).pathname;
const images = GM_getValue('images');
if (images.includes(pathname)) {
console.info(thumb, 'already downloaded');
return;
}
// download image:
console.info(thumb, 'not downloaded, downloading now');
const name = pathname.split('/')[2];
GM_download(thumb, `${name}.webp`);
// update storage
images.push(pathname);
GM_setValue('images', images);
});
}
start();
})();