Greasy Fork

RottenTomatoes Utility Library

Utility library for grabbing info from rottentomatoes.com

目前为 2019-09-06 提交的版本。查看 最新版本

此脚本不应直接安装,它是一个供其他脚本使用的外部库。如果您需要使用该库,请在脚本元属性加入:// @require https://update.greasyfork.icu/scripts/389810/731011/RottenTomatoes%20Utility%20Library.js

// ==UserScript==
// @name         RottenTomatoes Utility Library
// @namespace    driver8.net
// @version      0.1.1
// @description  Utility library for grabbing info from rottentomatoes.com
// @author       driver8
// @grant        GM_xmlhttpRequest
// @connect      rottentomatoes.com
// ==/UserScript==

console.log('hi rt');

var MAX_YEAR_DIFF = 2;

function _parse(query, regex, doc) {
    doc = doc || document;
    try {
        let text = doc.querySelector(query).textContent.trim();
        if (regex) {
            text = text.match(regex)[1];
        }
        return text.trim();
    } catch (e) {
        console.log('error', e);
        return '';
    }
};

function getRtIdFromTitle(title, tv, year) {
    tv = tv || false;
    year = parseInt(year) || 1800;
    return new Promise(function(resolve) {
        GM_xmlhttpRequest({
            method: 'GET',
            responseType: 'json',
            url: 'https://www.rottentomatoes.com/api/private/v2.0/search/?limit=10&q=' + title,
            onload: (resp) => {
                let movies = tv ? resp.response.tvSeries : resp.response.movies;

                let sorted = movies.concat();
                if (year) {
                    sorted.sort((a, b) => {
                        if (Math.abs(a.year - year) !== Math.abs(b.year - year)) {
                            // Prefer closest year to the given one
                            return Math.abs(a.year - year) - Math.abs(b.year - year);
                        } else {
                            return b.year - a.year; // In a tie, later year should come first
                        }
                    });
                }

                // Search for matches with exact title in order of proximity by year
                let bestMatch;
                for (let m of sorted) {
                    m.title = m.title || m.name;
                    if (m.title.toLowerCase() === title.toLowerCase()) {
                        bestMatch = m;
                        break;
                    }
                }
                //console.log('sorted', sorted, 'bestMatch', bestMatch, movies);

                // Fall back on closest year match if with 2 years, or whatever the first result was.
                bestMatch = bestMatch || (sorted && Math.abs(sorted[0].year - year) <= MAX_YEAR_DIFF && sorted[0]) || (movies && movies[0]);

                let id = bestMatch.url.replace(/\/s\d{2}\/?$/, ''); // remove season suffix from tv matches

                console.log('found id', id);
                resolve(id);
            }
        });
    });
}

function getRtInfoFromId(id) {
    return new Promise(function(resolve) {
        let url = 'https://www.rottentomatoes.com' + id + (id.startsWith('/tv/') ? '/s01' : ''); // Look up season 1 for TV shows
        GM_xmlhttpRequest({
            method: 'GET',
            responseType: 'document',
            url: url,
            onload: (resp) => {
                let text = resp.responseText;

                // Create DOM from responseText
                const doc = document.implementation.createHTMLDocument().documentElement;
                doc.innerHTML = text;
                let year = parseInt(_parse('.h3.year, .movie_title .h3.subtle, .meta-row .meta-value time', /(\d{4})/, doc));

                // Find the javascript snippet storing the tomatometer/score info.
                // Everything is named different for TV shows for some stupid reason.
                let m = text.match(/root\.RottenTomatoes\.context\.scoreInfo = ({.+});/);
                m = m || text.match(/root\.RottenTomatoes\.context\.scoreboardCriticInfo = ({.+});/);
                let dataString = m[1];
                let scoreInfo = JSON.parse(dataString);
                let all = scoreInfo.tomatometerAllCritics || scoreInfo.all || {},
                    top = scoreInfo.tomatometerTopCritics || scoreInfo.top || {};
                //console.log('scoreInfo', scoreInfo);

                // TV consensus is stored in a totally different object :/
                m = text.match(/root\.RottenTomatoes\.context\.result = ({.+});/);
                let contextResult = m && JSON.parse(m[1]);

                // Try field names used for movie data, then TV show data.
                const data = {
                    id: id,
                    score: all.score || all.tomatometer,
                    rating: all.avgScore || all.averageRating,
                    votes: all.numberOfReviews || all.totalCount,
                    consensus: all.consensus || (contextResult && contextResult.seasonData && contextResult.seasonData.tomatometer.consensus), // TV consensus is stored in a totally different object :/
                    state: all.tomatometerState || all.state,
                    topScore: top.score || top.tomatometer,
                    topRating: top.avgScore || top.averageRating,
                    topVotes: top.numberOfReviews || top.totalCount,
                    year: year,
                    fetched: new Date()
                };

                console.log('found data', data);
                resolve(data);
            }
        });
    });
}

function getRtInfoFromTitle(title, tv, year) {
    return getRtIdFromTitle(title, tv, year).then((id) => {
        return getRtInfoFromId(id);
    })
}