Greasy Fork

Greasy Fork is available in English.

B站♥视频评级

计算B站视频的互动播放比并显示,点击可复制信息并随机显示酷炫或可爱浮动特效

当前为 2025-03-25 提交的版本,查看 最新版本

// ==UserScript==
// @name         B站♥视频评级
// @namespace    http://tampermonkey.net/
// @version      1.13
// @description  计算B站视频的互动播放比并显示,点击可复制信息并随机显示酷炫或可爱浮动特效
// @author       Zola
// @match        https://www.bilibili.com/video/*
// @grant        none
// @license      MIT
// ==/UserScript==

(function() {
    'use strict';

    // 工具函数:解析包含“万”或“亿”的数字
    function parseCount(text) {
        if (!text) return 0;
        if (text.includes('万')) return parseFloat(text) * 10000;
        if (text.includes('亿')) return parseFloat(text) * 100000000;
        return parseInt(text.replace(/,/g, '')) || 0;
    }

    // 计算互动与播放量的比率
    function calculateRatio(totalInteractions, viewCount) {
        return ((totalInteractions / viewCount) * 100).toFixed(2);
    }

    // 获取带颜色的评级HTML
    function getRating(ratio) {
        const r = parseFloat(ratio);
        const ratings = [
            { min: 30, text: '满分视频', color: '#02c8d3' },
            { min: 19, text: '好评如潮', color: 'green' },
            { min: 16, text: '特别好评', color: 'limegreen' },
            { min: 14, text: '多半好评', color: 'yellowgreen' },
            { min: 8, text: '褒贬不一', color: 'orange' },
            { min: 4, text: '多半差评', color: 'orangered' },
            { min: 1, text: '差评如潮', color: 'red' },
            { min: 0, text: '惨不忍睹', color: 'grey' }
        ];
        const { text, color } = ratings.find(rating => r >= rating.min) || ratings[ratings.length - 1];
        return `<span style="color:${color}">${text}</span>`;
    }

    // 获取纯文本评级(无HTML)
    function getPlainRating(ratio) {
        const r = parseFloat(ratio);
        if (r > 30) return '满分视频';
        if (r >= 19) return '好评如潮';
        if (r >= 16) return '特别好评';
        if (r >= 14) return '多半好评';
        if (r >= 8) return '褒贬不一';
        if (r >= 4) return '多半差评';
        if (r >= 1) return '差评如潮';
        return '惨不忍睹';
    }

    // 创建并显示浮动特效(随机酷炫或可爱)
    function showCopyEffect(event) {
        const effect = document.createElement('div');
        const isCool = Math.random() > 0.5; // 50%概率选择酷炫或可爱

        // 基础样式
        effect.style.position = 'absolute';
        effect.style.left = `${event.pageX}px`;
        effect.style.top = `${event.pageY - 30}px`;
        effect.style.padding = '6px 12px';
        effect.style.zIndex = '9999';
        effect.style.pointerEvents = 'none';
        effect.style.opacity = '1';
        effect.style.transition = 'all 0.6s ease-out';

        if (isCool) {
            // 酷炫风格
            effect.textContent = 'Copied!';
            effect.style.background = 'linear-gradient(45deg, #ff00cc, #3333ff)';
            effect.style.color = '#fff';
            effect.style.borderRadius = '8px';
            effect.style.fontSize = '14px';
            effect.style.fontFamily = 'monospace';
            effect.style.boxShadow = '0 0 15px rgba(255, 0, 204, 0.8)';
            effect.style.transform = 'translateY(0) rotate(5deg)';
            setTimeout(() => {
                effect.style.opacity = '0';
                effect.style.transform = 'translateY(-30px) rotate(-5deg)';
            }, 50);
        } else {
            // 可爱风格
            effect.textContent = '复制啦~';
            effect.style.background = 'rgba(255, 182, 193, 0.9)';
            effect.style.color = '#fff';
            effect.style.border = '2px solid #ff69b4';
            effect.style.borderRadius = '15px';
            effect.style.fontSize = '14px';
            effect.style.fontFamily = 'Comic Sans MS, cursive';
            effect.style.transform = 'translateY(0) scale(1)';
            setTimeout(() => {
                effect.style.opacity = '0';
                effect.style.transform = 'translateY(-20px) scale(1.1)';
            }, 50);
        }

        document.body.appendChild(effect);
        setTimeout(() => effect.remove(), 650); // 动画结束后移除
    }

    // 绑定复制事件
    function bindCopyEvent(element, displayText, ratio, viewCount) {
        if (element.hasAttribute('data-click-bound')) return;
        element.addEventListener('click', (event) => {
            event.stopPropagation();
            const title = document.title;
            const url = `${window.location.origin}${window.location.pathname}`;
            const praiseRate = displayText.replace('好评:', '');
            const plainRating = viewCount < 1000 ? '' : getPlainRating(ratio);
            const textToCopy = `【${title}】【${url}】 好评率: ${praiseRate} 好评分级: ${plainRating}`;

            navigator.clipboard.writeText(textToCopy).then(() => {
                showCopyEffect(event);
            }).catch(err => {
                console.error('复制失败:', err);
                alert('复制失败,请手动复制');
            });
        });
        element.setAttribute('data-click-bound', 'true');
    }

    // 创建工具栏元素
    function createToolbarItem(className, title, content) {
        const wrapper = document.createElement('div');
        wrapper.className = 'toolbar-left-item-wrap';
        wrapper.setAttribute('data-v-1359e6fc', '');

        const item = document.createElement('div');
        item.className = `${className} video-toolbar-left-item`;
        item.setAttribute('data-v-1359e6fc', '');
        item.setAttribute('title', title);
        item.innerHTML = `<span class="${className}-info video-toolbar-item-text">${content}</span>`;

        wrapper.appendChild(item);
        return { wrapper, item };
    }

    // 更新或添加比率和评级
    function updateRatioDisplay() {
        const viewText = document.querySelector('.view-text')?.innerText.trim() || '0';
        const likeText = document.querySelector('.video-like-info.video-toolbar-item-text')?.innerText.trim().replace(/,/g, '') || '0';
        const coinText = document.querySelector('.video-coin-info.video-toolbar-item-text')?.innerText.trim().replace(/,/g, '') || '0';
        const favText = document.querySelector('.video-fav-info.video-toolbar-item-text')?.innerText.trim().replace(/,/g, '') || '0';
        const shareText = document.querySelector('.video-share-info-text')?.innerText.trim().replace(/,/g, '') || '0';

        const viewCount = parseCount(viewText);
        const totalInteractions = parseCount(likeText) + parseCount(coinText) + parseCount(favText) + parseCount(shareText);

        if (isNaN(viewCount) || isNaN(totalInteractions)) return;

        const ratio = viewCount < 1000 ? 0 : calculateRatio(totalInteractions, viewCount);
        const displayText = viewCount < 1000 ? '播放不足' : `好评:${(ratio * 5).toFixed(1)}%`;
        const ratingText = viewCount < 1000 ? '' : getRating(ratio);

        const toolbarLeftMain = document.querySelector('.video-toolbar-left-main');
        if (!toolbarLeftMain) return;

        let ratioElement = document.querySelector('.video-like-ratio');
        let ratingElement = document.querySelector('.video-like-rating');

        if (ratioElement) {
            ratioElement.querySelector('.video-like-ratio-info').innerText = displayText;
        } else {
            const { wrapper, item } = createToolbarItem('video-like-ratio', '互动播放比', displayText);
            toolbarLeftMain.appendChild(wrapper);
            ratioElement = item;
        }

        if (ratingElement) {
            ratingElement.querySelector('.video-like-rating-info').innerHTML = ratingText;
        } else {
            const { wrapper, item } = createToolbarItem('video-like-rating', '评价', ratingText);
            toolbarLeftMain.appendChild(wrapper);
            ratingElement = item;
        }

        bindCopyEvent(ratioElement, displayText, ratio, viewCount);
        bindCopyEvent(ratingElement, displayText, ratio, viewCount);
    }

    // 定期刷新显示
    function startPeriodicRefresh() {
        setInterval(updateRatioDisplay, 3000);
    }

    // 初始化
    window.addEventListener('load', startPeriodicRefresh);
})();