Greasy Fork

Greasy Fork is available in English.

AniList Tier Labels

Adds a tier badge next to ratings on Anilist, including Mean Score. Supports different scoring systems.

当前为 2025-02-12 提交的版本,查看 最新版本

您需要先安装一款用户脚本管理器扩展,例如 Tampermonkey 篡改猴Greasemonkey 油猴子Violentmonkey 暴力猴,才能安装此脚本。

您需要先安装一款用户脚本管理器扩展,例如 Tampermonkey 篡改猴,才能安装此脚本。

您需要先安装一款用户脚本管理器扩展,例如 Tampermonkey 篡改猴Violentmonkey 暴力猴,才能安装此脚本。

您需要先安装一款用户脚本管理器扩展,例如 Tampermonkey 篡改猴Userscripts ,才能安装此脚本。

您需要先安装一款用户脚本管理器扩展,例如 Tampermonkey 篡改猴,才能安装此脚本。

您需要先安装一款用户脚本管理器扩展后才能安装此脚本。

(我已经安装了用户脚本管理器,让我安装!)

您需要先安装一款用户样式管理器扩展,比如 Stylus,才能安装此样式。

您需要先安装一款用户样式管理器扩展,比如 Stylus,才能安装此样式。

您需要先安装一款用户样式管理器扩展,比如 Stylus,才能安装此样式。

您需要先安装一款用户样式管理器扩展后才能安装此样式。

您需要先安装一款用户样式管理器扩展后才能安装此样式。

您需要先安装一款用户样式管理器扩展后才能安装此样式。

(我已经安装了用户样式管理器,让我安装!)

// ==UserScript==
// @name         AniList Tier Labels
// @namespace    http://tampermonkey.net/
// @version      2.1
// @description  Adds a tier badge next to ratings on Anilist, including Mean Score. Supports different scoring systems.
// @author       hiddenhokage, Claude, ChatGPT
// @match        *://anilist.co/*
// @grant        none
// ==/UserScript==

(function () {
    'use strict';

    // Updated tier definitions with colors
    const tiers = [
        { min: 95, max: 100, label: 'S+', color: '#FFD700', textColor: '#000000' }, // S+ Tier, Gold
        { min: 85, max: 94.9, label: 'S', color: '#ff7f00', textColor: '#FFFFFF' }, // S Tier, Orange
        { min: 75, max: 84.9, label: 'A', color: '#aa00ff', textColor: '#FFFFFF' }, // A Tier, Purple
        { min: 65, max: 74.9, label: 'B', color: '#007fff', textColor: '#FFFFFF' }, // B Tier, Blue
        { min: 55, max: 64.9, label: 'C', color: '#00aa00', textColor: '#FFFFFF' }, // C Tier, Green
        { min: 41, max: 54.9, label: 'D', color: '#aaaaaa', textColor: '#FFFFFF' }, // D Tier, Gray
        { min: 0, max: 40.9, label: 'F', color: '#666666', textColor: '#FFFFFF' } // F Tier, Dark Gray
    ];

    function getTier(rating) {
        return tiers.find(tier => rating >= tier.min && rating <= tier.max) || null;
    }

    function createBadge(tier, isBlockView = false) {
        let badge = document.createElement('span');
        badge.textContent = tier.label;

        badge.style.cssText = `
            background-color: ${tier.color};
            color: ${tier.textColor};
            font-size: ${isBlockView ? '10px' : '12px'};
            font-weight: bold;
            padding: ${isBlockView ? '1px 4px' : '2px 6px'};
            border-radius: 4px;
            display: inline-block;
            margin-left: 5px;
            vertical-align: middle;
            white-space: nowrap;
        `;
        return badge;
    }

    function getScoreSystem() {
        const container = document.querySelector('.content.container');
        if (container) {
            if (container.querySelector('.medialist.table.POINT_100')) return 'POINT_100';
            if (container.querySelector('.medialist.table.POINT_10_DECIMAL')) return 'POINT_10';
            if (container.querySelector('.medialist.table.POINT_5')) return 'POINT_5';
        }
        return 'UNKNOWN';
    }

    function normalizeScore(score, scoreSystem, isPercentage = false) {
        if (isPercentage) return score; // Percentage scores are already in the right format

        const numericScore = parseFloat(score);
        if (isNaN(numericScore)) return null;

        switch (scoreSystem) {
            case 'POINT_100':
                return numericScore; // Already in 100-point scale
            case 'POINT_10':
                return numericScore * 10; // Convert 10-point to 100-point
            case 'POINT_5':
                return numericScore * 20; // Convert 5-point to 100-point (5 → 100, 4 → 80, 3 → 60, 2 → 40, 1 → 20)
            default:
                return numericScore * 10; // Default to 10-point conversion
        }
    }

    function processScoreElement(el, isPercentage = false, isBlockView = false) {
        if (el.dataset.tierModified) return;
        el.dataset.tierModified = "true";

        const scoreSystem = getScoreSystem();
        let ratingText = el.getAttribute('score') || el.innerText.trim().replace('%', '');
        let normalizedRating = normalizeScore(ratingText, scoreSystem, isPercentage);

        if (normalizedRating === null) return;

        let tier = getTier(normalizedRating);
        if (tier) {
            const container = document.createElement('div');
            container.style.cssText = `
                display: inline-flex;
                align-items: center;
                gap: 4px;
                ${isBlockView ? 'background-color: rgba(0, 0, 0, 0.5); padding: 2px 6px; border-radius: 4px; overflow: hidden;' : ''}
            `;

            const scoreEl = document.createElement('span');
            scoreEl.textContent = isPercentage ? `${ratingText}%` : ratingText;

            container.appendChild(scoreEl);
            container.appendChild(createBadge(tier, isBlockView));

            el.textContent = '';
            el.appendChild(container);
        }
    }

    function addTierIndicators() {
        // List View (Decimal Scores)
        document.querySelectorAll('.score:not(.media-card .score)').forEach(el => {
            processScoreElement(el, false, false);
        });

        // Block View (Media Cards)
        document.querySelectorAll('.entry-card .score').forEach(el => {
            processScoreElement(el, false, true);
        });

        // Process both Average Score and Mean Score
        document.querySelectorAll('.data-set').forEach(dataSet => {
            const label = dataSet.querySelector('.type');
            const value = dataSet.querySelector('.value');

            if (label && value && !value.dataset.tierModified &&
                (label.innerText.includes('Average Score') || label.innerText.includes('Mean Score'))) {
                processScoreElement(value, true, false);
            }
        });
    }

    function initializeScript() {
        addTierIndicators();

        const statsObserver = new MutationObserver((mutations) => {
            mutations.forEach((mutation) => {
                if (mutation.type === 'childList' || mutation.type === 'subtree') {
                    addTierIndicators();
                }
            });
        });

        statsObserver.observe(document.body, {
            childList: true,
            subtree: true,
            characterData: true
        });
    }

    if (document.readyState === 'loading') {
        document.addEventListener('DOMContentLoaded', initializeScript);
    } else {
        initializeScript();
    }

    window.addEventListener('popstate', () => {
        setTimeout(addTierIndicators, 100);
    });

    const pushState = history.pushState;
    history.pushState = function () {
        pushState.apply(history, arguments);
        setTimeout(addTierIndicators, 100);
    };
})();