15 votes

Tildes User Script: Youtube Thumbnails Below Topic Title

A screenshot.

Following is a user script that embeds a thumbnail into the topic header. Was supposed to be trivial, but walking around the CSRP was not that easy. Luckily, someone had written a nice useful custom Base64 encoder, because I spent more than an hour trying to get btoa to do the thing.

// ==UserScript==
// @name     tildesYoutubeThumbs
// @version  1
// @grant    GM.xmlHttpRequest
// @namespace   tildes.net
// @include     https://tildes.net/~*/*
// ==/UserScript==

let youtubeIcon = document.querySelector('div.topic-icon-youtube_com')

if(youtubeIcon !== null) {
  let youtubeLink = youtubeIcon.nextSibling.nextSibling.href;
  let youtubeID = new URL(youtubeLink).searchParams.get('v');
  let thumbnailUrl = "https://img.youtube.com/vi/" + youtubeID + "/0.jpg";

  GM.xmlHttpRequest({
    method: "GET",
    url: thumbnailUrl,
    overrideMimeType: 'text/plain; charset=x-user-defined',
    onload: function(response) {
      if(response.status === 200) {
        let thumbElement = document.createElement('img');
        let thumbParentDiv = document.createElement('div');
        let header = document.querySelector('article.topic-full > header');
        let data = "data:image/jpeg;base64," + customBase64Encode(response.responseText);
        thumbElement.src = data;
        thumbElement.style = 'width: 60%; margin: auto';
        thumbElement.id = 'gk-youtube-thumbnail';
        thumbParentDiv.style = 'width: 100%; text-align:center;';
        header.appendChild(thumbParentDiv);
        thumbParentDiv.appendChild(thumbElement);
      }
    }
  });
}

// https://stackoverflow.com/questions/8778863/downloading-an-image-using-xmlhttprequest-in-a-userscript/8781262#8781262
function customBase64Encode (inputStr) {
    var
        bbLen               = 3,
        enCharLen           = 4,
        inpLen              = inputStr.length,
        inx                 = 0,
        jnx,
        keyStr              = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz"
                            + "0123456789+/=",
        output              = "",
        paddingBytes        = 0;
    var
        bytebuffer          = new Array (bbLen),
        encodedCharIndexes  = new Array (enCharLen);

    while (inx < inpLen) {
        for (jnx = 0;  jnx < bbLen;  ++jnx) {
            /*--- Throw away high-order byte, as documented at:
              https://developer.mozilla.org/En/Using_XMLHttpRequest#Handling_binary_data
            */
            if (inx < inpLen)
                bytebuffer[jnx] = inputStr.charCodeAt (inx++) & 0xff;
            else
                bytebuffer[jnx] = 0;
        }

        /*--- Get each encoded character, 6 bits at a time.
            index 0: first  6 bits
            index 1: second 6 bits
                        (2 least significant bits from inputStr byte 1
                         + 4 most significant bits from byte 2)
            index 2: third  6 bits
                        (4 least significant bits from inputStr byte 2
                         + 2 most significant bits from byte 3)
            index 3: forth  6 bits (6 least significant bits from inputStr byte 3)
        */
        encodedCharIndexes[0] = bytebuffer[0] >> 2;
        encodedCharIndexes[1] = ( (bytebuffer[0] & 0x3) << 4)   |  (bytebuffer[1] >> 4);
        encodedCharIndexes[2] = ( (bytebuffer[1] & 0x0f) << 2)  |  (bytebuffer[2] >> 6);
        encodedCharIndexes[3] = bytebuffer[2] & 0x3f;

        //--- Determine whether padding happened, and adjust accordingly.
        paddingBytes          = inx - (inpLen - 1);
        switch (paddingBytes) {
            case 1:
                // Set last character to padding char
                encodedCharIndexes[3] = 64;
                break;
            case 2:
                // Set last 2 characters to padding char
                encodedCharIndexes[3] = 64;
                encodedCharIndexes[2] = 64;
                break;
            default:
                break; // No padding - proceed
        }

        /*--- Now grab each appropriate character out of our keystring,
            based on our index array and append it to the output string.
        */
        for (jnx = 0;  jnx < enCharLen;  ++jnx)
            output += keyStr.charAt ( encodedCharIndexes[jnx] );
    }
    return output;
}

9 comments

  1. [3]
    cfabbro
    (edited )
    Link
    I hate this!!! But nice job. ;) Added to the customizing tildes entry in the ~tildes group wiki.

    I hate this!!! But nice job. ;) Added to the customizing tildes entry in the ~tildes group wiki.

    7 votes
    1. [2]
      unknown user
      Link Parent
      Thanks! That page is a treasure! You might want to add this and/or this to it too, these hide vote counts, the first is mine and is JS but there's Bauke's CSS in the comments, the other is another...

      Thanks! That page is a treasure! You might want to add this and/or this to it too, these hide vote counts, the first is mine and is JS but there's Bauke's CSS in the comments, the other is another pure CSS version by Soptik.

      2 votes
      1. cfabbro
        (edited )
        Link Parent
        Yeah, the group wikis are pretty handy in general. I am super glad they finally got added since they make all the snippits of useful stuff on tildes much easier to collect, organize, archive and...

        Yeah, the group wikis are pretty handy in general. I am super glad they finally got added since they make all the snippits of useful stuff on tildes much easier to collect, organize, archive and share.

        p.s. Added all three vote count hiding methods to the wiki.

        1 vote
  2. [3]
    suspended
    Link
    How would I implement this?

    How would I implement this?

    2 votes
    1. [2]
      unknown user
      Link Parent
      Install the Greasemonkey addon (available both for Chrome & Firefox AFAIK), copy the script, click Greasemonkey icon, then "New user script...", paste the script into the editor it opens, save...

      Install the Greasemonkey addon (available both for Chrome & Firefox AFAIK), copy the script, click Greasemonkey icon, then "New user script...", paste the script into the editor it opens, save (Ctrl+s), close, open a YouTube topic and see the effects.

      I've only tested this on Firefox Desktop BTW.

      3 votes
  3. [2]
    teaearlgraycold
    Link
    Looks like it will run on the main listing, but because it only uses document.querySelector instead of querySelectorAll it will only affect the first submission on the listing. I suggest you...

    Looks like it will run on the main listing, but because it only uses document.querySelector instead of querySelectorAll it will only affect the first submission on the listing. I suggest you either restrict the script to a URL pattern matching submission pages only, or fire this code once per item on the list pages.

    2 votes
    1. unknown user
      Link Parent
      Thanks! I will fix it in the script later.

      Thanks! I will fix it in the script later.

      1 vote
  4. unknown user
    Link
    I've just slightly updated the script so that it only runs on topic pages and not the listings (modified the @include line slightly). Thanks @teaearlgraycold!

    I've just slightly updated the script so that it only runs on topic pages and not the listings (modified the @include line slightly). Thanks @teaearlgraycold!

    2 votes