Greasy Fork

RYM Track Rating Sorter

Sort RYM track ratings by score with a toggle button

目前为 2025-01-28 提交的版本。查看 最新版本

// ==UserScript==
// @name         RYM Track Rating Sorter
// @namespace    http://tampermonkey.net/
// @version      0.1
// @description  Sort RYM track ratings by score with a toggle button
// @author       You
// @match        https://rateyourmusic.com/release/*
// @icon         https://www.google.com/s2/favicons?domain=rateyourmusic.com
// @grant        GM_addStyle
// @grant        GM_log
// @run-at       document-idle
// ==/UserScript==

(function() {
    'use strict';

    GM_addStyle(`
        #rymSortBtn {
            all: unset !important;
            padding: 8px 15px !important;
            margin: 15px 0 !important;
            background: #4CAF50 !important;
            color: white !important;
            border-radius: 4px !important;
            font-size: 14px !important;
            cursor: pointer !important;
            position: relative !important;
            z-index: 9999 !important;
            font-family: Arial !important;
            display: block !important;
        }
    `);

    function log(message) {
        console.log('[RYM Sorter]', message);
    }

    function findTracklistContainer() {
        // Try multiple selectors in priority order
        const selectors = [
            'div[data-testid="tracklist"]', // New RYM selector
            '.release_tracklist',
            '.tracklist_wrapper',
            '.tracklist',
            '.tracklist_list',
            '#tracks',
            'div.tracks'
        ];

        for (const selector of selectors) {
            const element = document.querySelector(selector);
            if (element) {
                log(`Found container using selector: ${selector}`);
                return element;
            }
        }

        console.error('Tracklist container not found. Tried selectors:', selectors);
        return null;
    }

    function initialize() {
        const container = findTracklistContainer();
        if (!container) {
            // Retry after short delay for dynamic content
            setTimeout(initialize, 1000);
            return;
        }

        log('Initializing with container:', container);

        // Create and insert button
        const btn = document.createElement('button');
        btn.id = 'rymSortBtn';
        btn.textContent = 'Sort by Rating ▼';
        container.parentNode.insertBefore(btn, container);

        // Tracklist handling logic
        let originalHTML = container.innerHTML;
        let isSorted = false;

        btn.addEventListener('click', () => {
            if (isSorted) {
                container.innerHTML = originalHTML;
                btn.textContent = 'Sort by Rating ▼';
            } else {
                const tracks = Array.from(container.querySelectorAll('.track, [data-testid="track"]'));
                tracks.sort((a, b) => {
                    const getRating = el => {
                        const ratingEl = el.querySelector('.track_rating, .track_rating_value, [class*="rating"]');
                        return ratingEl ? parseFloat(ratingEl.textContent.replace('%', '')) || 0 : 0;
                    };
                    return getRating(b) - getRating(a);
                });

                container.replaceChildren(...tracks);
                btn.textContent = 'Restore Original Order ▲';
            }
            isSorted = !isSorted;
        });
    }

    // Start initialization with multiple fallbacks
    const init = () => {
        if (findTracklistContainer()) {
            initialize();
        } else {
            // Use MutationObserver as fallback
            const observer = new MutationObserver((mutations) => {
                if (findTracklistContainer()) {
                    observer.disconnect();
                    initialize();
                }
            });
            observer.observe(document.body, {
                childList: true,
                subtree: true
            });

            // Final fallback timeout
            setTimeout(() => {
                if (!document.getElementById('rymSortBtn')) {
                    initialize();
                }
            }, 3000);
        }
    };

    if (document.readyState === 'complete') {
        init();
    } else {
        window.addEventListener('load', init);
        document.addEventListener('DOMContentLoaded', init);
    }
})();