Home > Software engineering >  How to save youtube thumbnails on hdd with javascript?
How to save youtube thumbnails on hdd with javascript?

Time:12-29

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();
})();
  • Related