Greasy Fork is available in English.

Seed Like Button for Seed Hunt

Adds a like button to seeds on Seed Hunt.

// ==UserScript==
// @name        Seed Like Button for Seed Hunt
// @description Adds a like button to seeds on Seed Hunt.
// @version     1.0
// @author      Veeno
// @include     https://seedhunt.net/*
// @grant       none
// @namespace   slb-seedhunt.net
// ==/UserScript==

/******************************************************************************/

function GM_addStyle(aCss) {
    "use strict";
    let head = document.getElementsByTagName("head")[0];
    if(head){
        let style = document.createElement("style");
        style.setAttribute("type", "text/css");
        style.textContent = aCss;
        head.appendChild(style);
        return style;
    }
    return null;
}

const __GM_STORAGE_PREFIX = ["", GM_info.script.namespace, GM_info.script.name, ""].join("***");

function GM_getValue(aKey, aDefault) {
    "use strict";
    let val = localStorage.getItem(__GM_STORAGE_PREFIX + aKey)
    if (null === val && "undefined" != typeof aDefault) return aDefault;
    return val;
}

function GM_setValue(aKey, aVal) {
    "use strict";
    localStorage.setItem(__GM_STORAGE_PREFIX + aKey, aVal);
}

/******************************************************************************/

const base64Digits = "0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz+/";

function numberToBase64(number){
    let residual = Math.floor(Math.abs(Number(number)));
    let result = [];

    do{
        result.push(base64Digits.charAt(residual & 63));
        // Not "residual >> 6" because bitwise operators truncate to 32 bits.
        residual = Math.floor(residual / 64);
    } while(residual > 0);

    return result.reverse().join("");
}

/******************************************************************************/

let seeds = null;

function loadSeeds(){
    let seedList = GM_getValue("seedList", "");
    if(seedList.length < 1) seeds = new Set();
    else seeds = new Set(seedList.split(","));
}

function saveSeeds(){
    GM_setValue("seedList", Array.from(seeds).join(","));
}

/******************************************************************************/

let cards = null;

function processCards(){
    for(let i = cards.length - 1; i >= 0; --i){
        let card = cards[i];
        if(card.dataset.slbB64Seed) continue;

        let seedContainer = card.getElementsByClassName("v-card__title")[0];
        if(!seedContainer) continue;

        let seed = numberToBase64(seedContainer.innerHTML.trim());
        card.dataset.slbB64Seed = seed;
        if(seeds.has(seed)) card.classList.add("slb-liked-seed");

        let likeButton = document.createElement("div");
        likeButton.appendChild(document.createTextNode("👍"));
        likeButton.classList.add("slb-like-button");
        seedContainer.parentElement.appendChild(likeButton);

        likeButton.addEventListener("mousedown", event => event.stopPropagation());

        likeButton.addEventListener("click", event => {
            event.stopPropagation();
            let card = event.target.parentElement;
            while(!card.dataset.slbB64Seed) card = card.parentElement;
            if(card.classList.contains("slb-liked-seed")){
                card.classList.remove("slb-liked-seed");
                seeds.delete(card.dataset.slbB64Seed);
            } else{
                card.classList.add("slb-liked-seed");
                seeds.add(card.dataset.slbB64Seed);
            }
            saveSeeds();
        });
    }
}

/******************************************************************************/

let main = null;
const styleText = [
    ".slb-like-button {",
    "    position: absolute;",
    "    bottom: 5px;",
    "    right: 5px;",
    "    filter: grayscale() brightness(0.5);",
    "    font-size: 25px;",
    "    line-height: normal;",
    "}",
    "",
    ".slb-liked-seed .slb-like-button {",
    "    filter: none;",
    "}",
    "",
    ".slb-liked-seed > div {",
    "    background-color: rgba(0, 255, 0, 0.25);",
    "}"
].join("\n");

function start(){
    main = document.getElementsByTagName("main")[0];
    if(!main){
        setTimeout(start, 25);
        return;
    }

    GM_addStyle(styleText);

    loadSeeds();

    cards = main.getElementsByClassName("v-card v-card--link v-sheet");
    processCards();

    let observer = new MutationObserver(processCards);
    observer.observe(main, { childList: true, subtree: true });
}

start();