RadioGoose Stations

Affiche les stations

Чтобы установить этот скрипт, вы сначала должны установить расширение браузера, например Tampermonkey, Greasemonkey или Violentmonkey.

Для установки этого скрипта вам необходимо установить расширение, такое как Tampermonkey.

Чтобы установить этот скрипт, вы сначала должны установить расширение браузера, например Tampermonkey или Violentmonkey.

Чтобы установить этот скрипт, вы сначала должны установить расширение браузера, например Tampermonkey или Userscripts.

Чтобы установить этот скрипт, сначала вы должны установить расширение браузера, например Tampermonkey.

Чтобы установить этот скрипт, вы должны установить расширение — менеджер скриптов.

(у меня уже есть менеджер скриптов, дайте мне установить скрипт!)

Чтобы установить этот стиль, сначала вы должны установить расширение браузера, например Stylus.

Чтобы установить этот стиль, сначала вы должны установить расширение браузера, например Stylus.

Чтобы установить этот стиль, сначала вы должны установить расширение браузера, например Stylus.

Чтобы установить этот стиль, сначала вы должны установить расширение — менеджер стилей.

Чтобы установить этот стиль, сначала вы должны установить расширение — менеджер стилей.

Чтобы установить этот стиль, сначала вы должны установить расширение — менеджер стилей.

(у меня уже есть менеджер стилей, дайте мне установить скрипт!)

// ==UserScript==
// @name         RadioGoose Stations
// @namespace    rgenchantement
// @version      1.5
// @description  Affiche les stations 
// @author       veho
// @match        https://radiogoose.ru/play/
// @grant        GM_addStyle
// @run-at       document-idle
// ==/UserScript==

(function() {
    'use strict';

    // Styles
    GM_addStyle(`
        .radio-goose-stations {
            position:fixed;left:20px;bottom:20px;z-index:9999;max-width:300px;
            background:rgba(0,0,0,0.8);backdrop-filter:blur(10px);
            border:1px solid #ff4500;border-radius:12px;padding:15px;
        }
        .stations-title {
            color:#ff4500;font-size:1.2em;text-align:center;margin-bottom:10px;
        }
        .stations-list {
            display:grid;gap:8px;max-height:60vh;overflow-y:auto;
        }
        .station-item {
            padding:10px;border:1px solid #ff450033;border-radius:6px;
            background:transparent;color:#fff;cursor:pointer;
            transition:all 0.2s ease;white-space:nowrap;overflow:hidden;text-overflow:ellipsis;
        }
        .station-item:hover {
            border-color:#ff4500;background:rgba(255,69,0,0.1);
        }
        .station-item.active {
            border-color:#ff4500;background:rgba(255,69,0,0.1);
            box-shadow:0 0 8px rgba(255,69,0,0.3);
        }
    `);

    const stationNamesMap = {
        "radiogoose": "Goose Radio",
        "bigroom": "Goose Bigroom",
        "dancecore": "Goose Denscore",
        "deep": "Goose Deep House",
        "drum": "Goose Drum",
        "electro": "Goose Electro",
        "hardstyle": "Goose Hardstyle",
        "midtempo": "Goose Midtempo",
        "oldschool": "Goose Oldschool",
        "phonk": "Goose Phonk",
        "rock": "Goose Rock",
        "rus": "Goose Rus",
        "technorave": "Goose Techno",
        "trance": "Goose Trance",
        "moscow_madness": "Moscow Madness"
    };

    function createList() {
        const container = document.createElement('div');
        container.className = 'radio-goose-stations';
        container.innerHTML = `<div class="stations-title">            <img src="https://image.noelshack.com/fichiers/2025/22/1/1748267933-music-note-icon-orange-neon-260nw-1129600895-removebg-preview.png"
                 alt="music icon"
                 style="height: 30px; display: inline-block; vertical-align: middle; margin-right: 5px;;"> Stations Disponibles</div><div class="stations-list"></div>`;
        document.body.appendChild(container);
        return container;
    }

    function fillStations(container) {
        const list = container.querySelector('.stations-list');
        list.innerHTML = '';
        document.querySelectorAll('#stations .station').forEach(button => {
            const hash = button.getAttribute('data-hash');
            const name = stationNamesMap[hash] || button.textContent.trim();
            const btn = document.createElement('button');
            btn.className = 'station-item';
            btn.dataset.hash = hash;
            btn.textContent = name;
            btn.onclick = () => button.click();
            list.appendChild(btn);
        });
    }

    function updateHighlight(container) {
        const list = container.querySelector('.stations-list');
        container.querySelectorAll('.station-item').forEach(btn => {
            const hash = btn.dataset.hash;
            const original = document.querySelector(`#stations .station[data-hash="${hash}"]`);
            const isActive = original?.classList.contains('is-active');
            btn.classList.toggle('active', isActive);

            if (isActive && !isInViewport(btn)) btn.scrollIntoView({ behavior: 'smooth', block: 'center' });
        });
    }

    function isInViewport(el) {
        const rect = el.getBoundingClientRect();
        const parent = el.closest('.stations-list');
        const parentRect = parent.getBoundingClientRect();
        return rect.top >= parentRect.top && rect.bottom <= parentRect.bottom;
    }

    function observeChanges(container) {
        new MutationObserver(() => {
            fillStations(container);
            updateHighlight(container);
        }).observe(document.querySelector('#stations'), {
            childList: true,
            subtree: true,
            attributes: true,
            attributeFilter: ['class']
        });
    }

    // Initialisation
    setTimeout(() => {
        const container = createList();
        fillStations(container);
        updateHighlight(container);
        observeChanges(container);
    }, 3000);
})();