SoundCloud Blacklist Manager (mit GUI)

Skippt Tracks von bestimmten Künstlern auf SoundCloud + GUI zum Verwalten der Blacklist

// ==UserScript==
// @name         SoundCloud Blacklist Manager (mit GUI)
// @namespace    http://tampermonkey.net/
// @version      1.5
// @description  Skippt Tracks von bestimmten Künstlern auf SoundCloud + GUI zum Verwalten der Blacklist
// @author       Du
// @match        https://soundcloud.com/*
// @grant        none
// ==/UserScript==

(function () {
    'use strict';

    const getStoredBlacklist = () => JSON.parse(localStorage.getItem('scBlacklist') || '[]');
    const saveBlacklist = (list) => localStorage.setItem('scBlacklist', JSON.stringify(list));
    const isBlacklisted = (artist) => getStoredBlacklist().includes(artist.toLowerCase());

    function getCurrentArtistElement() {
        return document.querySelector('.playbackSoundBadge__lightLink');
    }

    function getCurrentArtistName() {
        const el = getCurrentArtistElement();
        return el ? el.textContent.trim().toLowerCase() : null;
    }

    function skipTrack() {
        const skipButton = document.querySelector('.skipControl__next') ||
            [...document.querySelectorAll('button')].find(btn =>
                btn.getAttribute('title')?.toLowerCase().includes('next')
            );
        if (skipButton) {
            skipButton.click();
            setTimeout(() => skipButton.click(), 1000);
        }
    }

    let lastArtist = '';

    function checkAndAct() {
        const currentArtist = getCurrentArtistName();
        if (!currentArtist) return;

        const el = getCurrentArtistElement();
        if (!el) return;

        if (currentArtist !== lastArtist) {
            lastArtist = currentArtist;
        }

        if (isBlacklisted(currentArtist)) {
            el.innerHTML = `🚫 ${el.textContent}`;
            el.style.color = 'red';
            el.style.fontWeight = 'bold';
            skipTrack();
        } else {
            el.style.color = '';
            el.style.fontWeight = '';
        }
    }

    setInterval(checkAndAct, 3000);

    function createGUI() {
        if (document.getElementById('sc-blacklist-gui')) return;

        const container = document.createElement('div');
        container.id = 'sc-blacklist-container';
        container.style.position = 'fixed';
        container.style.bottom = '20px';
        container.style.right = '20px';
        container.style.zIndex = '9999';

        const gui = document.createElement('div');
        gui.id = 'sc-blacklist-gui';
        gui.style.background = 'rgba(0,0,0,0.85)';
        gui.style.color = 'white';
        gui.style.padding = '10px';
        gui.style.borderRadius = '8px';
        gui.style.fontFamily = 'sans-serif';
        gui.style.fontSize = '14px';
        gui.style.minWidth = '200px';
        gui.style.display = 'none';
        gui.style.position = 'absolute';
        gui.style.top = '50px';
        gui.style.left = '0';

        gui.innerHTML = `
            <strong>🚫 Blacklist</strong><br><br>
            <input id="bl-input" type="text" placeholder="Künstlername" style="width: 100%; padding: 5px; border-radius: 4px; margin-bottom: 5px;">
            <button id="bl-add" style="width: 100%; margin-bottom: 5px;">➕ Hinzufügen</button>
            <button id="bl-block-current" style="width: 100%; margin-bottom: 5px;">⛔ Aktuellen blocken</button>
            <ul id="bl-list" style="list-style: none; padding-left: 0; max-height: 150px; overflow-y: auto;"></ul>
        `;

        const toggleBtn = document.createElement('button');
        toggleBtn.id = 'sc-blacklist-toggle';
        toggleBtn.textContent = '⚙️';
        toggleBtn.style.background = '#333';
        toggleBtn.style.color = 'white';
        toggleBtn.style.border = 'none';
        toggleBtn.style.padding = '10px';
        toggleBtn.style.borderRadius = '50%';
        toggleBtn.style.cursor = 'move';
        toggleBtn.style.position = 'relative';

        let guiVisible = false;

        toggleBtn.addEventListener('click', function (e) {
            if (e.detail === 1) {
                setTimeout(() => {
                    if (e.detail === 1) {
                        guiVisible = !guiVisible;
                        gui.style.display = guiVisible ? 'block' : 'none';
                        updateList();
                    }
                }, 200);
            }
        });

        toggleBtn.addEventListener('mousedown', function (event) {
            event.preventDefault();
            let shiftX = event.clientX - container.getBoundingClientRect().left;
            let shiftY = event.clientY - container.getBoundingClientRect().top;

            function moveAt(pageX, pageY) {
                container.style.left = pageX - shiftX + 'px';
                container.style.top = pageY - shiftY + 'px';
                container.style.right = '';
                container.style.bottom = '';
            }

            function onMouseMove(event) {
                moveAt(event.pageX, event.pageY);
            }

            document.addEventListener('mousemove', onMouseMove);

            document.onmouseup = function () {
                document.removeEventListener('mousemove', onMouseMove);
                document.onmouseup = null;
            };
        });

        toggleBtn.ondragstart = () => false;

        container.appendChild(toggleBtn);
        container.appendChild(gui);
        document.body.appendChild(container);

        document.getElementById('bl-add').addEventListener('click', () => {
            const name = document.getElementById('bl-input').value.trim().toLowerCase();
            if (name && !isBlacklisted(name)) {
                const list = getStoredBlacklist();
                list.push(name);
                saveBlacklist(list);
                document.getElementById('bl-input').value = '';
                updateList();
            }
        });

        document.getElementById('bl-block-current').addEventListener('click', () => {
            const name = getCurrentArtistName();
            if (name && !isBlacklisted(name)) {
                const list = getStoredBlacklist();
                list.push(name);
                saveBlacklist(list);
                updateList();
            }
        });
    }

    function updateList() {
        const ul = document.getElementById('bl-list');
        if (!ul) return;
        ul.innerHTML = '';
        getStoredBlacklist().forEach((artist, index) => {
            const li = document.createElement('li');
            li.textContent = artist;
            li.style.display = 'flex';
            li.style.justifyContent = 'space-between';
            li.style.marginBottom = '3px';

            const delBtn = document.createElement('button');
            delBtn.textContent = '❌';
            delBtn.style.background = 'transparent';
            delBtn.style.color = 'red';
            delBtn.style.border = 'none';
            delBtn.style.cursor = 'pointer';
            delBtn.addEventListener('click', () => {
                const list = getStoredBlacklist();
                list.splice(index, 1);
                saveBlacklist(list);
                updateList();
            });

            li.appendChild(delBtn);
            ul.appendChild(li);
        });
    }

    let lastUrl = location.href;
    new MutationObserver(() => {
        const currentUrl = location.href;
        if (currentUrl !== lastUrl) {
            lastUrl = currentUrl;
            setTimeout(() => createGUI(), 1000);
        }
    }).observe(document, { subtree: true, childList: true });

    window.addEventListener('load', () => {
        const current = getStoredBlacklist();
        if (!current.includes('cheapex')) {
            current.push('cheapex');
            saveBlacklist(current);
        }
        createGUI();
    });
})();