Everynoise Enhancement Script

A script to slightly enhance everynoise's user experience

Från och med 2023-12-02. Se den senaste versionen.

// ==UserScript==
// @name         Everynoise Enhancement Script
// @namespace    http://tampermonkey.net/
// @version      0.4.2
// @description  A script to slightly enhance everynoise's user experience
// @author       NeroYuki
// @match        https://everynoise.com/*
// @icon         https://www.google.com/s2/favicons?sz=64&domain=https://everynoise.com/
// @license      MIT
// ==/UserScript==

/**
function highlight(which) {
    if (gdivs.length == 0) {
        gdivs = document.getElementsByClassName('genre');
    }
    for (i=0; i<gdivs.length; i++) {
        thisdiv = gdivs[i];
        thistext = thisdiv.firstChild.textContent;
        if (thisdiv.className.indexOf('scanme') > -1) {
            basename = 'genre scanme';
        } else {
            basename = 'genre';
        }
        if (which.length > 0 && which.trim() == thistext.trim().replace('"', '')) {
            thisdiv.className = basename + ' current';
            if(typeof thisdiv.scrollIntoViewIfNeeded == 'function') {
                thisdiv.scrollIntoViewIfNeeded();
            } else {
                thisdiv.scrollIntoView({behavior: "smooth", block: "center", inline: "center"});
            }
        } else {
            thisdiv.className = basename;
        }
    }
}
**/

(function() {
    'use strict';

    // Your code here...
    var head = document.getElementsByTagName('head')[0];
    var thisScript = document.scripts[0]
    var cloneScript= document.createElement('script');
    if (thisScript) {
        cloneScript.textContent = thisScript.textContent.replace(/scandur \= 6000/g, 'scandur = 29000');
        cloneScript.textContent = cloneScript.textContent.replace('function playx(key, genre, me) {', 'async function playx(key, genre, me) {');
        cloneScript.textContent = cloneScript.textContent.replace('highlight(genre);', 'highlight(genre, sample_title);');
        cloneScript.textContent = cloneScript.textContent.replace('function highlight(which)', 'function highlight(which, sample_title = "")');
        cloneScript.textContent = cloneScript.textContent.replace('me.setAttribute(\'played\', clicknumber++);', '');
        cloneScript.textContent = cloneScript.textContent.replace('async function playx(key, genre, me) {', 'async function playx(key, genre, me, loop = false) {');
        cloneScript.textContent = cloneScript.textContent.replace('if (nowplaying == genre) {', 'if (nowplaying == genre && !loop) {');
        cloneScript.textContent = cloneScript.textContent.replace('window.clearTimeout(nowpending);', '');
        cloneScript.textContent = cloneScript.textContent.replace('picked.onclick();', 'if (!isLooping) { window.clearTimeout(nowpending); picked.onclick(); } else { window.clearTimeout(nowpending); }');
        cloneScript.textContent = cloneScript.textContent.replace('thisdiv.scrollIntoViewIfNeeded(false);', 'thisdiv.scrollIntoViewIfNeeded(true);');
        var cloneScriptLines = cloneScript.textContent.split('\n');
        var dataInsertLine = 0
        cloneScriptLines.splice(dataInsertLine, 0, `
var genreData = [];
fetch('https://raw.githubusercontent.com/NeroYuki/AnotherElaina/master/resources/spotify_genres.json')
    .then(async (response) => {
        genreData = await response.json();
    });

var isLooping = false;

const dbName = "everynoise_ext";
let db = null;

const request = indexedDB.open(dbName, 2);

request.onerror = (event) => {
    alert('error, please disable the userscript');
};

request.onsuccess = (event) => {
    db = event.target.result;

    db.transaction("genres")
        .objectStore("genres").get("pop").onsuccess = (event) => {
            const res = event.target.result
            if (!res) {
                console.log('adding data');
                fetch('https://raw.githubusercontent.com/NeroYuki/AnotherElaina/master/resources/spotify_genres_artists_top50.json')
                    .then(async (response) => {
                        console.log('fetched artists genre mapping');
                        genreArtist = await response.json();
                        for (const genre of genreArtist) {
                            db
                                .transaction("genres", "readwrite")
                                .objectStore("genres")
                                .add(genre);
                        }
                    });
            }
        }
};

request.onupgradeneeded = (event) => {
    db = event.target.result;

    const objectStore = db.createObjectStore("genres", { keyPath: "genre" });

    // Use transaction oncomplete to make sure the objectStore creation is
    // finished before adding data into it.
    objectStore.transaction.oncomplete = (event) => {
        console.log('creation done')
    };
};

function getData(dataStore, key) {
    return new Promise((resolve, reject) => {
        const dataFetch = db.transaction(dataStore)
            .objectStore(dataStore).get(key);
        dataFetch.onsuccess = (event) => {
            const res = event.target.result
            resolve(res);
        }
        dataFetch.onerror = (event) => {
            reject(event);
        }

    })
}
        `);
        var insertLoopLine = cloneScriptLines.findIndex(val => val.includes('var spotifyplayer = document.getElementById(\'spotifyplayer\');')) + 1;
        cloneScriptLines.splice(insertLoopLine, 0, `
        console.log(genre, key);
        spotifyplayer.onended = () => {
            console.log('ended')
            playx(key, genre, me, true);
        };
        `);
        var insertSelectionLine = cloneScriptLines.findIndex(val => val.includes('previewurl = me.getAttribute(\'preview_url\')')) + 1;
        cloneScriptLines.splice(insertSelectionLine, 0, `
        let sample_title = me.getAttribute('title').replace('e.g. ', '');
        const res = await getData('genres', genre)
        var selectionIndex = res?.artists ? Math.floor(Math.random() * res.artists.length + 1) : 0;
        if (selectionIndex > 1) {
            previewurl = res.artists[selectionIndex - 1].preview_url;
            sample_title = res.artists[selectionIndex - 1].sample_song;
        }
        `);

        var insertStartResetStateLine = cloneScriptLines.findIndex(val => val.includes('if (state == \'stop\') {')) - 1;
        cloneScriptLines.splice(insertStartResetStateLine, 0, `
        if (state == 'start') {
            isLooping = false;
        }
        `);

        var insertLine = cloneScriptLines.findIndex(val => val.includes('thisdiv.scrollIntoView({behavior: "smooth", block: "center", inline: "center"});')) + 2;
        cloneScriptLines.splice(insertLine, 0, `
            var label = document.getElementById('genre_label');
            if (!label) {
                label = document.createElement('div');
                document.body.appendChild(label);
            }
            var title_label = document.getElementById('title_label');
            if (!title_label) {
                title_label = document.createElement('div');
                document.body.appendChild(title_label);
            }
            var loop_label = document.getElementById('loop_label');
            if (!loop_label) {
                loop_label = document.createElement('div');
                document.body.appendChild(loop_label);
            }
            let genreInfo = genreData.find(val => val.genre === which.trim())
            label.id = 'genre_label';
            title_label.id = 'title_label';
            loop_label.id = 'loop_label';
            label.style.position = title_label.style.position = loop_label.style.position = 'absolute';
            label.style.color = title_label.style.color = loop_label.style.color = 'black';
            label.style.backgroundColor = title_label.style.backgroundColor = 'white';
            loop_label.style.backgroundColor = isLooping ? 'green' : 'white';
            label.style.padding = title_label.style.padding = loop_label.style.padding = '5px';
            label.style.display = title_label.style.display = loop_label.style.display = 'none';
            label.textContent = genreInfo ? genreInfo.desc : "No description";
            title_label.textContent = '▶  ' + (sample_title ? sample_title : "Unknown title");
            loop_label.textContent = '↻'
            // set the label position to be above the highlighted div
            var rect = thisdiv.getBoundingClientRect();

            label.style.left = Math.max(10, (parseInt(thisdiv.style.left) - 100)) + 'px';
            label.style.width = '300px'
            label.style.top = (parseInt(thisdiv.style.top) + 96) + 'px';
            label.style.border = 'solid 1px black';
            // show the label
            label.style.display = 'block';

            title_label.style.left = Math.max(10, (parseInt(thisdiv.style.left) - 100)) + 'px';
            title_label.style.top = (parseInt(thisdiv.style.top) + 36) + 'px';
            title_label.style.border = 'solid 1px black';
            // show the label
            title_label.style.display = sample_title ? 'block' : 'none';

            loop_label.style.left = Math.max(10, (parseInt(thisdiv.style.left) - 124)) + 'px';
            loop_label.style.top = (parseInt(thisdiv.style.top) + 36) + 'px';
            loop_label.style.border = 'solid 1px black';
            // show the label
            loop_label.style.display = 'block';

            loop_label.onclick = () => {
                isLooping = !isLooping;
                loop_label.style.backgroundColor = isLooping ? 'green' : 'white';
            }

            if(typeof label.scrollIntoViewIfNeeded == 'function') {
                label.scrollIntoViewIfNeeded();
            }
        `);
        cloneScript.textContent = cloneScriptLines.join('\n');
        head.appendChild(cloneScript);
        thisScript.remove();
    }
})();