AI comes for YouTube’s thumbnail industry
26
votes
@Sam (from Wendover): One thing I hate is just how well negativity works. Of our top 10 performers over the past year, eight (in my view) include direct or indirect negativity in the title/thumbnail. (A🧵) pic.twitter.com/tqIz9v6CTh
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;
}