Greasy Fork

Filmweb External Ratings

Add IMDb, Rotten Tomatoes, and Metacritic ratings to Filmweb

目前为 2025-03-29 提交的版本。查看 最新版本

// ==UserScript==
// @name         Filmweb External Ratings
// @namespace    http://tampermonkey.net/
// @version      1.0
// @description  Add IMDb, Rotten Tomatoes, and Metacritic ratings to Filmweb
// @author       mrkkr
// @match          http*://www.filmweb.pl/serial/*
// @match          http*://www.filmweb.pl/film/*
// @match          http*://www.filmweb.pl/tvshow/*
// @match          http*://www.imdb.com/*
// @match          http*://www.rottentomatoes.com/*
// @match          http*://www.metacritic.com/*
// @grant        GM_xmlhttpRequest
// @connect      imdb.com
// @connect      rottentomatoes.com
// @connect      metacritic.com
// ==/UserScript==

(function() {
    'use strict';

    const ICONS = {
        imdb: 'data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAABAAAAAQCAYAAAAf8/9hAAAACXBIWXMAAAsTAAALEwEAmpwYAAAA6ElEQVQ4ja2TsQ3CMBBF/0UMgSgYgBkyAANkBEZgBLqUkWgzAiPQMgINI7CBaGgQhbElY4JQPsnS6c7/7/587wB/GAA7ADcAKYAYJ+IL9bV0JoX73I0AKgmqAbQAngBGAE8JagCcdG5MUEQGqT0AGwBHOZ8A7LXxCmCpdR1LyVyqL3rj2mm6AnCQzEbzRZ1dVMWdU5VIHqPFKJc+c5MC0CvTWvPGBE34JV0JwFwL3GfqtKi7WQbVHlXY1Dwp/Gv3w2I6W6MjgK0UzRpHXX1qXQN4fwsITRmAfaSp86bKHNgF8L9kpXEeE/QBWUU9pW4s4WYAAAAASUVORK5CYII=',
        rotten: 'data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAABAAAAAQCAYAAAAf8/9hAAAACXBIWXMAAAsTAAALEwEAmpwYAAABP0lEQVQ4jZWSPUsDQRCGn7vceSpiYSMIAUEQRLCxsLSxFgv/goWNjYU/wcI/YGlhYWdlYyEIFoJgIQiCIBgQBU0uzd3u7FjcJZcYc+oLL8w+M/PO7MwK/hm+5wngxvdcqT1nwRmwD/QkSS7DMLyW1k5cK8ltxJmwNgQuAC0iQ2BDRC6ttdPGUkQi4AfYBHaAHeAd6AFC0zQP1tqRqvzFHSilWiKyBawppUZhGN7XwDmXK6UcMPX9WVFV6jWIyJox5tj3/XPf91/CMHwDMMaMAE9ExsCZMebUWvtVOVBKrQJdYB5fVBTFR3WmtR4Dpz+Ps8YLlNYqpZaAh6IoPqvAOZc75144514rQGayB6K1XhGRO+dc3DRutdYbwKDMZO4EVdtF8gocAQNjzKQEp8AYeAL6ZSZzG4lI2xgzKRtXRG6/AduYkKWrJqV7AAAAAElFTkSuQmCC',
        metacritic: 'data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAABAAAAAQCAYAAAAf8/9hAAAACXBIWXMAAAsTAAALEwEAmpwYAAAAtUlEQVQ4jWNgoBAwQun/+BSzYBH7j0UNXgW4DPgPBTjlYQrwGYBNDqcBMAOI0YzTAGI1YzcAj2asBhDQjGEAIc3oBox/u3b3PwMDw38GBob/x95s2Y1LM7IBr7+c3//405n9/xkYGP4ffX1i/pH3x3bj0oxiwJsvF/Yfen9s938GBob/h94d2X3o3ZHd2DQjG3Dg3eHdB94d3v2fgYHh/4G3B3cfendkNy7NSAacs7XlGXEpBgDZMJSlUEFhkwAAAABJRU5ErkJggg=='
    };

    async function getIMDbRating(title, year) {
        try {
            const imdbIdMatch = document.querySelector('a[href*="www.imdb.com/title/tt"]');
            if (!imdbIdMatch) return null;
            
            const imdbId = imdbIdMatch.href.match(/tt\d+/)[0];
            
            const response = await fetch(`https://www.imdb.com/title/${imdbId}/`);
            const text = await response.text();
            
            const ratingMatch = text.match(/"ratingValue":\s*"([^"]+)"/);
            if (!ratingMatch) return null;
            
            return {
                rating: ratingMatch[1],
                url: `https://www.imdb.com/title/${imdbId}/`
            };
        } catch (error) {
            console.error('Error fetching IMDb rating:', error);
            return null;
        }
    }

    async function getRottenTomatoesRating(title, year) {
        try {
            const url = `https://www.rottentomatoes.com/search?search=${encodeURIComponent(title)}`;
            const response = await fetch(url);
            const text = await response.text();
            
            const rtUrlMatch = text.match(new RegExp(`href="([^"]+${year}[^"]+)"`));
            if (!rtUrlMatch) return null;
            
            const rtUrl = 'https://www.rottentomatoes.com' + rtUrlMatch[1];
            const movieResponse = await fetch(rtUrl);
            const movieText = await movieResponse.text();
            
            const ratingMatch = movieText.match(/tomatometer">(\d+)%/);
            if (!ratingMatch) return null;
            
            return {
                rating: ratingMatch[1] + '%',
                url: rtUrl
            };
        } catch (error) {
            console.error('Error fetching Rotten Tomatoes rating:', error);
            return null;
        }
    }

    async function getMetacriticRating(title, year) {
        try {
            const searchUrl = `https://www.metacritic.com/search/movie/${encodeURIComponent(title)}/results`;
            const response = await fetch(searchUrl);
            const text = await response.text();
            
            const mcUrlMatch = text.match(new RegExp(`href="([^"]+${year}[^"]+)"`));
            if (!mcUrlMatch) return null;
            
            const mcUrl = 'https://www.metacritic.com' + mcUrlMatch[1];
            const movieResponse = await fetch(mcUrl);
            const movieText = await movieResponse.text();
            
            const ratingMatch = movieText.match(/metascore_w[^>]+>(\d+)</);
            if (!ratingMatch) return null;
            
            return {
                rating: ratingMatch[1],
                url: mcUrl
            };
        } catch (error) {
            console.error('Error fetching Metacritic rating:', error);
            return null;
        }
    }

    function createRatingElement(icon, rating, url) {
        const container = document.createElement('div');
        container.style.cssText = `
            display: inline-flex;
            align-items: center;
            margin: 0 10px;
            cursor: pointer;
            padding: 5px 10px;
            border-radius: 4px;
            background: rgba(0,0,0,0.05);
            transition: background 0.2s;
        `;
        
        container.onmouseover = () => container.style.background = 'rgba(0,0,0,0.1)';
        container.onmouseout = () => container.style.background = 'rgba(0,0,0,0.05)';
        
        const img = document.createElement('img');
        img.src = icon;
        img.style.cssText = `
            width: 16px;
            height: 16px;
            margin-right: 8px;
        `;
        
        const span = document.createElement('span');
        span.textContent = rating || 'N/A';
        span.style.cssText = `
            font-weight: bold;
            color: #333;
        `;
        
        container.appendChild(img);
        container.appendChild(span);
        
        if (url) {
            container.addEventListener('click', () => window.open(url, '_blank'));
        }
        
        return container;
    }

    async function init() {
        if (!document.querySelector('.filmCoverSection__title')) {
            setTimeout(init, 100);
            return;
        }

        const titleElement = document.querySelector('.filmCoverSection__title');
        if (!titleElement) return;

        const title = titleElement.textContent.trim();
        const year = document.querySelector('.filmCoverSection__year')?.textContent.trim() || '';
        
        const ratingsContainer = document.createElement('div');
        ratingsContainer.style.cssText = `
            margin-top: 15px;
            display: flex;
            justify-content: center;
            flex-wrap: wrap;
            gap: 10px;
        `;
        
        const filmCoverSection = document.querySelector('.filmCoverSection__card');
        if (!filmCoverSection) return;

        const placeholders = {
            imdb: createRatingElement(ICONS.imdb, 'Loading...', null),
            rotten: createRatingElement(ICONS.rotten, 'Loading...', null),
            metacritic: createRatingElement(ICONS.metacritic, 'Loading...', null)
        };

        Object.values(placeholders).forEach(el => ratingsContainer.appendChild(el));
        filmCoverSection.appendChild(ratingsContainer);

        try {
            const [imdb, rotten, metacritic] = await Promise.all([
                getIMDbRating(title, year),
                getRottenTomatoesRating(title, year),
                getMetacriticRating(title, year)
            ]);

            if (imdb) placeholders.imdb.replaceWith(createRatingElement(ICONS.imdb, imdb.rating, imdb.url));
            if (rotten) placeholders.rotten.replaceWith(createRatingElement(ICONS.rotten, rotten.rating, rotten.url));
            if (metacritic) placeholders.metacritic.replaceWith(createRatingElement(ICONS.metacritic, metacritic.rating, metacritic.url));
        } catch (error) {
            console.error('Error fetching ratings:', error);
        }
    }

    init();
})();