PTP Ratings Exporter for IMDb

Automatically add and rate movies to your IMDb watchlist

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

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

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

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

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

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

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

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

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

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

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

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

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

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

// ==UserScript==
// @name         PTP Ratings Exporter for IMDb
// @namespace    PTP Ratings Exporter for IMDb
// @version      1.1.0
// @description  Automatically add and rate movies to your IMDb watchlist
// @author       Delgan
// @match        https://passthepopcorn.me/forums.php?*&threadid=37787&*
// @match        https://passthepopcorn.me/forums.php?*&threadid=37787
// @match        https://passthepopcorn.me/forums.php?threadid=37787&*
// @grant        GM_xmlhttpRequest
// ==/UserScript==

function main() {
    let placeholder = `Fill in this text box with an JSON array looking like this:
    [
        {"title": "Sonatine", "year": 1993, "imdb": {"id": "tt0108188", "url": "https://www.imdb.com/title/tt0108188/", "my_rating": 9}},
        {"title": "Se7en", "year": 1995, "imdb": {"id": "tt0114369", "url": "https://www.imdb.com/title/tt0114369/", "my_rating": 6}}
    ]`

    let textarea = `<textarea id='ptp-ratings-exporter-textarea' style='width: 100%; height: 7rem; padding: 10px;' placeholder='${placeholder}'></textarea>`;
    let button = `<button id='ptp-ratings-exporter-button' style='display:block; margin: auto; margin-top: 10px;'>Rate my movies</button>`;
    let checkbox = `<label style='cursor:pointer;display:block;text-align:center;margin-top:5px;'><input id='ptp-ratings-exporter-checkbox-watchlist' type="checkbox" /> Add movies to watchlist</label>`;
    let progression = `<div id='ptp-ratings-exporter-progression' data-count="0" data-progress="0" style='text-align:center; margin-top: 5px;'></div>`;

    document.getElementById("content").insertAdjacentHTML("afterbegin", textarea + checkbox + button + progression);
    document.getElementById("ptp-ratings-exporter-button").addEventListener("click", rateMovies);
    renderProgression();
}

function getAuthToken(imdbId, onSuccess) {
    GM_xmlhttpRequest({
        url: `https://www.imdb.com/title/${imdbId}/`,
        method: "PUT",
        timeout: 30000,
        onload: function (response) {
            let auth;
            try {
                let html = document.createElement("html");
                html.innerHTML = response.responseText;
                auth = html.querySelector("#star-rating-widget").getAttribute("data-auth");
            } catch (err) {
                alert(`An error occurred while fetching IMDb auth token: '${err.message}'`);
                return;
            }
            onSuccess(auth);
        },
        onerror: function (_) {
            alert(`The HTTP request for auth token  failed`);
        },
        ontimeout: function (_) {
            alert(`The HTTP request for auth token timed out`);
        },
    });
}

function addMovieToWatchlist(imdbId) {
    GM_xmlhttpRequest({
        url: `https://www.imdb.com/watchlist/${imdbId}`,
        method: "PUT",
        timeout: 30000,
        onload: function (_) {
            console.log(`Successfully added movie '${imdbId}' to watchlist`);
        },
        onerror: function (_) {
            alert(`The HTTP request for movie '${imdbId}' failed`);
        },
        ontimeout: function (_) {
            alert(`The HTTP request for movie '${imdbId}' timed out`);
        },
    });
}

function rateMovie(imdbId, rating, auth) {
    let data = {
        "tconst": imdbId,
        "rating": Math.min(Math.max(rating, 1), 10).toFixed(),
        "auth": auth,
        "tracking_tag": "title-maindetails",
        "pageId": imdbId,
        "pageType": "title",
        "subpageType": "main",
    };

    let payload = "";
    for (let field in data) {
        payload += `${field}=${encodeURIComponent(data[field])}&`;
    }

    let headers = {
        'User-Agent': 'Mozilla/5.0 (X11; Linux x86_64; rv:77.0) Gecko/20100101 Firefox/77.0',
        'Accept': 'application/json, text/javascript, */*; q=0.01',
        'Content-Type': 'application/x-www-form-urlencoded; charset=UTF-8',
        'X-Requested-With': 'XMLHttpRequest',
    };

    GM_xmlhttpRequest({
        url: `https://www.imdb.com/ratings/_ajax/title`,
        method: "POST",
        headers: headers,
        timeout: 30000,
        data: payload,
        onload: function (_) {
            console.log(`Successfully rated movie '${imdbId}'`);
        },
        onerror: function (_) {
            alert(`The HTTP request for movie '${imdbId}' failed`);
        },
        ontimeout: function (_) {
            alert(`The HTTP request for movie '${imdbId}' timed out`);
        },
    });
}

function disableForm() {
    document.getElementById("ptp-ratings-exporter-textarea").setAttribute("disabled", "disabled");
    document.getElementById("ptp-ratings-exporter-button").setAttribute("disabled", "disabled");
}

function enableForm() {
    document.getElementById("ptp-ratings-exporter-textarea").removeAttribute("disabled");
    document.getElementById("ptp-ratings-exporter-button").removeAttribute("disabled");
}


function resetProgression(progress, count) {
    let progression = document.getElementById("ptp-ratings-exporter-progression");
    progression.setAttribute("data-progress", progress);
    progression.setAttribute("data-count", count);
    renderProgression();
}

function updateProgression() {
    let progression = document.getElementById("ptp-ratings-exporter-progression");
    let progress = parseInt(progression.getAttribute("data-progress"));
    progression.setAttribute("data-progress", progress + 1);
    renderProgression();

    if (progress + 1 === parseInt(progression.getAttribute("data-count"))) {
        enableForm();
    }
}

function renderProgression() {
    let progression = document.getElementById("ptp-ratings-exporter-progression");
    let progress = progression.getAttribute("data-progress")
    let count = progression.getAttribute("data-count");
    if (count === "0") {
        progression.innerHTML = "Progression: ---";
    } else {
        progression.innerHTML = `Progression: ${progress} / ${count}`;
    }
}

function rateMovies() {
    disableForm();

    resetProgression(0, 0);

    let text = document.getElementById("ptp-ratings-exporter-textarea").value;

    if (text === "") {
        alert("No data to parse");
        enableForm();
        return;
    }

    let movies;

    try {
        movies = JSON.parse(text);
    } catch (err) {
        alert(`Unable to parse the JSON array: "${err.message}"`);
        enableForm();
        return;
    }

    if (!Array.isArray(movies)) {
        alert("Invalid parsed JSON, it should be an array");
        enableForm();
        return;
    }

    if (movies.length === 0) {
        enableForm();
        return;
    }

    resetProgression(0, movies.length);

    let addMoviesToWatchList = document.getElementById("ptp-ratings-exporter-checkbox-watchlist");

    let delay = 1000;

    for (let movie of movies) {
        if (!movie.hasOwnProperty("imdb")) {
            alert("Missing 'imdb' property in one data entry");
            updateProgression();
            continue;
        }
        if (!movie.imdb.hasOwnProperty("id")) {
            alert("Missing 'id' property in one data entry");
            updateProgression();
            continue;
        }
        if (!movie.imdb.hasOwnProperty("my_rating")) {
            alert("Missing 'my_rating' property in one data entry");
            updateProgression();
            continue;
        }

        let imdbId = movie.imdb.id;
        let myRating = parseFloat(movie.imdb.my_rating);

        if (!imdbId.match(/tt[0-9]+/)) {
            alert(`The imdb id format is incorrect: '${imdbId}'`);
            updateProgression();
            continue;
        }
        if (Number.isNaN(myRating) || myRating < 0 || myRating > 10) {
            alert(`The rating value is incorrect: '${myRating}'`);
            updateProgression();
            continue;
        }

        setTimeout(function () {addMoviesToWatchList
            updateProgression();
            getAuthToken(imdbId, function (auth) {
                if (addMoviesToWatchList) {
                    addMovieToWatchlist(imdbId);
                }
                rateMovie(imdbId, myRating, auth);
            });
        }, delay);

        delay += 1000;
    }
}

main();