您需要先安装一个扩展,例如 篡改猴、Greasemonkey 或 暴力猴,之后才能安装此脚本。
您需要先安装一个扩展,例如 篡改猴 或 暴力猴,之后才能安装此脚本。
您需要先安装一个扩展,例如 篡改猴 或 暴力猴,之后才能安装此脚本。
您需要先安装一个扩展,例如 篡改猴 或 Userscripts ,之后才能安装此脚本。
您需要先安装一款用户脚本管理器扩展,例如 Tampermonkey,才能安装此脚本。
您需要先安装用户脚本管理器扩展后才能安装此脚本。
Automatically add and rate movies to your IMDb watchlist
// ==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();