Greasy Fork

TMDB plus plus

It adds IMDB, RottenTomatoes, MAL & Awards/Nominations to TMDB

目前为 2021-08-29 提交的版本。查看 最新版本

// ==UserScript==
// @name        TMDB plus plus
// @description It adds IMDB, RottenTomatoes, MAL & Awards/Nominations to TMDB
// @match       https://www.themoviedb.org/*
// @version     1.0
// @author      SH3LL
// @grant        GM_xmlhttpRequest
// @namespace https://greasyfork.org/users/762057
// ==/UserScript==


function TMDB_title_api(TMDB_id,content) { 
  
    if (content==="movie"){
        return new Promise(function (resolve, reject) {
            GM_xmlhttpRequest({
                method: 'GET',
                responseType: 'json',
                synchronous: false,
                url: 'https://api.themoviedb.org/3/movie/'+TMDB_id+'?api_key=8d6d91941230817f7807d643736e8a49&language=en&append_to_response=external_ids,keywords',
                onload: (resp) => {
                    
                    let json = JSON.parse(resp.responseText);
                    console.log('TMDB title api: https://api.themoviedb.org/3/movie/'+TMDB_id+'?api_key=8d6d91941230817f7807d643736e8a49&language=en&append_to_response=external_ids,keywords');
                    
                    if (json && json.Error) {
                      console.log("Error: " + json.Error);
                      resolve("error"); return; 
                    }
                   
                    let IMDB_id=0,TMDB_title=0, TMDB_original_title=0, TMDB_year=0,anime_flag=0;
                    
                    if(json.title!==undefined && json.title!==null) TMDB_title = json.title;
                    if(json.original_title!==undefined && json.original_title!==null) TMDB_original_title = json.original_title;
                    if(json.external_ids!==undefined && json.external_ids.imdb_id!== null) IMDB_id = json.external_ids.imdb_id;
                    if(json.release_date!==null && json.release_date!==undefined) TMDB_year=json.release_date.slice(0,4);
                    if(json.keywords!==undefined && json.keywords.keywords!==undefined && json.keywords.keywords!==null){
                      for(let keyword of json.keywords.keywords){
                        if(keyword.name==="anime"){anime_flag=1; break;}
                      }
                    }
                    resolve([TMDB_title,TMDB_original_title,TMDB_year,IMDB_id,anime_flag]); return;
                    
                }
            });
        });
      
    }else if(content==="tv"){
      return new Promise(function (resolve, reject) {
            GM_xmlhttpRequest({
                method: 'GET',
                responseType: 'json',
                synchronous: false,
                url: 'https://api.themoviedb.org/3/tv/'+TMDB_id+'?api_key=8d6d91941230817f7807d643736e8a49&language=en&append_to_response=external_ids,keywords',
                onload: (resp) => {
                  
                    let json = JSON.parse(resp.responseText);
                    console.log('TMDB title api: https://api.themoviedb.org/3/tv/'+TMDB_id+'?api_key=8d6d91941230817f7807d643736e8a49&language=en&append_to_response=external_ids,keywords');
                  
                    if (json && json.Error) {
                      console.log("Error: " + json.Error);
                      resolve("error"); return; 
                    }
                  
                    let IMDB_id=0,TMDB_title=0, TMDB_original_title=0,seasons_count=0,anime_flag=0;
                    
                    if(json.name!==undefined && json.name!==null) TMDB_title = json.name;
                    if(json.original_name!==undefined && json.original_name!==null) TMDB_original_title = json.original_name;
                    if(json.external_ids!==undefined && json.external_ids.imdb_id!== null) IMDB_id = json.external_ids.imdb_id; //imdb id
                    if(json.seasons!==undefined && json.seasons!== null) seasons_count = (json.seasons).length;
                    if(json.keywords!==undefined && json.keywords.results!==undefined && json.keywords.results!==null){
                      for(let keyword of json.keywords.results){
                        if(keyword.name==="anime"){anime_flag=1; break;}
                      }
                    }
                  
                    //years range
                    let first_year="N/A",last_year="N/A",years_range; 
                    if(json.first_air_date!==undefined && json.first_air_date!==null) first_year = json.first_air_date.slice(0,4);
                    if(json.last_air_date!==undefined && json.last_air_date!==null) {
                      if(json.last_air_date.slice(2,4) !== first_year.slice(2,4)) last_year = json.last_air_date.slice(2,4);
                    }
                    
                    if(last_year !=="N/A") years_range=first_year + "-" + last_year; else years_range=first_year;
                    
                    resolve([TMDB_title,TMDB_original_title,first_year,years_range,IMDB_id,seasons_count,anime_flag]); return; 
                    
                }
            });
        });
    }
}

function ScrapeIMDB(IMDB_id) {
    return new Promise(function (resolve, reject) {
        GM_xmlhttpRequest({
            method: 'GET',
            responseType: 'document',
            synchronous: false,
            url: "https://www.imdb.com/title/"+IMDB_id,
            onload: (resp) => {
                const doc = document.implementation.createHTMLDocument().documentElement;
                doc.innerHTML = resp.responseText;
                console.log("IMDB link: "+"https://www.imdb.com/title/"+IMDB_id)
                
                let IMDB_rating=0, IMDB_votes_number=0, IMDB_awards=0;
                IMDB_rating = doc.querySelectorAll('.AggregateRatingButton__RatingScore-sc-1ll29m0-1')[0].innerText;
                IMDB_votes_number = doc.querySelectorAll('.AggregateRatingButton__TotalRatingAmount-sc-1ll29m0-3')[0].innerText;
                if(doc.querySelectorAll('.Awards__Wrapper-sc-1qdt65t-0').length!==0) IMDB_awards = doc.querySelectorAll('.Awards__Wrapper-sc-1qdt65t-0')[0].children[1].children[0].children[0].innerText + ". " + doc.querySelectorAll('.Awards__Wrapper-sc-1qdt65t-0')[0].children[1].children[0].children[1].innerText;
                if(IMDB_awards===undefined) IMDB_awards=0;
                IMDB_awards=IMDB_awards.replaceAll("Awards. ", "");
                
                resolve([IMDB_rating,IMDB_votes_number,IMDB_awards]); return;
        }
        });
      })
}
                       
function RT_search_api(title,year,content) { 
    title = title.replaceAll(" ", "%20");
  
    if (content==="movie"){
        return new Promise(function (resolve, reject) {
            GM_xmlhttpRequest({
                method: 'GET',
                responseType: 'json',
                synchronous: false,
                url: 'https://www.rottentomatoes.com/api/private/v2.0/search/?limit=10&q='+ title +'&t=movie',
                onload: (resp) => {
                    
                    let json = JSON.parse(resp.responseText);
                    console.log('RT search api: https://www.rottentomatoes.com/api/private/v2.0/search/?limit=10&q='+ title +'&t=movie');
                    
                    if (json && json.Error) {
                      console.log("Error: " + json.Error);
                      resolve("error"); return;
                    }
                    
                    if(json.movieCount === 0){
                      console.log("Error: No movies found in RT");
                      resolve("error"); return;
                    }
                    
                    let fresh_certificate=0, meterscore = 0, url=0;
                    for(let movie of json.movies){
                      if(parseInt(movie.year) === parseInt(year)){ //fix rotten tomatoes errors
                        
                        if(movie.meterClass === "fresh" || movie.meterClass === "certified_fresh") fresh_certificate='fresh';
                        if(movie.meterClass === "rotten") fresh_certificate='rotten';
                        if(movie.meterScore !== "N/A" && movie.meterScore !== undefined) meterscore=movie.meterScore;
                        url=movie.url;
                      }
                      
                    }
                   if(url!==0) {resolve([url,meterscore,fresh_certificate]); return;} else{resolve("error"); return;}
                }
            });
        }); 
      
    }else if(content==="tv"){
      return new Promise(function (resolve, reject) {
            GM_xmlhttpRequest({
                method: 'GET',
                responseType: 'json',
                synchronous: false,
                url: 'https://www.rottentomatoes.com/api/private/v2.0/search/?limit=10&q='+ title +'&t=tvSeries',
                onload: (resp) => {
                  
                    let json = JSON.parse(resp.responseText);
                    console.log('RT search api: https://www.rottentomatoes.com/api/private/v2.0/search/?limit=10&q='+ title +'&t=tvSeries');
                  
                    if (json && json.Error) {
                      console.log("Error: " + json.Error);
                      resolve("error"); return;
                    }
                    
                    if(json.tvCount === 0){
                     console.log("Error: No series found in RT");
                      resolve("error"); return;
                    }
                  
                    let fresh_certificate=0, meterscore = 0, url=0;
                    for(let title of json.tvSeries){
                      if(parseInt(title.startYear) === parseInt(year)){ //fix rotten tomatoes errors
                        if(title.meterClass === "fresh" || title.meterClass === "certified_fresh") fresh_certificate='fresh';
                        if(title.meterClass === "rotten") fresh_certificate='rotten';
                        if(title.meterScore !== "N/A" && title.meterScore !== undefined) meterscore=title.meterScore;
                        url=title.url;
                      }
                    }
                   if(url!==0) {resolve([url,meterscore,fresh_certificate]); return;} else{resolve("error"); return;}
                }
            });
        });
    }
}

function JIKAN_search_api(title,year,content) {
    
    title=title.replaceAll(" ","%20"); // <---
    if (content==="movie"){
        return new Promise(function (resolve, reject) {
            GM_xmlhttpRequest({
                method: 'GET',
                responseType: 'json',
                synchronous: false,
                url: 'https://api.jikan.moe/v3/search/anime?q='+title+'&page=1',
                onload: (resp) => {
                    
                    let json = JSON.parse(resp.responseText);
                    console.log('MAL search api: https://api.jikan.moe/v3/search/anime?q='+title+'&page=1');
                    
                    if (json && json.Error) {
                      console.log("Error: " + json.Error);
                      resolve("error"); return; 
                    }
                    
                    let MAL_url=0, MAL_title_name=0, MAL_score=0, MAL_image_url=0, content_type=0, episodes_count=0, start_date=0;
                    for(let result of json.results){
                      if(result.type!==null && result.start_date!==null &&
                         (parseInt(result.start_date.slice(0,4))===parseInt(year) || parseInt(result.start_date.slice(0,4))===parseInt(year)-1 || parseInt(result.start_date.slice(0,4))===parseInt(year)-2) &&
                         (result.type === "Movie" /*TV*/ || result.type === "ONA" || result.type === "OVA")){
                        
                        if(result.url!== null) MAL_url = result.url;
                        if(result.score!== null) MAL_score = result.score;
                        if(result.image_url!== null) MAL_image_url = result.image_url;
                        if(result.episodes!== null) episodes_count = result.episodes;
                        if(result.start_date!== null) start_date = result.start_date.slice(0,4);
                        
                        resolve([MAL_url, MAL_score, episodes_count, start_date]); return;
                      }
                    }
                    
                    console.log("JIKAN [MAL]: Error, title not found");
                    resolve("error"); return; 
                    
                    
                }
            });
        }); 
      
    }else if(content==="tv"){
      return new Promise(function (resolve, reject) {
            GM_xmlhttpRequest({
                method: 'GET',
                responseType: 'json',
                synchronous: false,
                url: 'https://api.jikan.moe/v3/search/anime?q='+title+'&page=1',
                onload: (resp) => {
                  
                    let json = JSON.parse(resp.responseText);
                    console.log('MAL search api: https://api.jikan.moe/v3/search/anime?q='+title+'&page=1&limit=10');
                  
                    if (json && json.Error) {
                      console.log("Error: " + json.Error);
                      resolve("error"); return; 
                    }
                  
                    let MAL_url=0, MAL_score=0, episodes_count=0, start_date=0, end_date=0, date_range=0;
                    for(let result of json.results){
                      if(result.type!==null && result.start_date!==null &&
                         (parseInt(result.start_date.slice(0,4))===parseInt(year) || parseInt(result.start_date.slice(0,4))===parseInt(year)-1 || parseInt(result.start_date.slice(0,4))===parseInt(year)-2) &&
                         (result.type === "TV" || result.type === "ONA" || result.type === "OVA")){
                        
                        if(result.url!== null) MAL_url = result.url;
                        if(result.score!== null) MAL_score = result.score;
                        if(result.episodes!== null) episodes_count = result.episodes;
                        if(result.start_date!== null) start_date = result.start_date.slice(0,4);
                        if(result.end_date!== null) end_date = result.end_date.slice(2,4);
                        
                        if(start_date!== 0 && end_date!== 0) date_range = start_date + "-" + end_date
                        
                        resolve([MAL_url, MAL_score, episodes_count, date_range]); return;
                      }
                    }
                    
                    console.log("JIKAN [MAL]: Error, title not found");
                    resolve("error"); return; 
                   
                    
                }
            });
        });
    }
}


async function main(){
    let content=0;
    let TMDB_info=0, TMDB_id=0, TMDB_title=0, TMDB_original_title=0, TMDB_year=0, tv_year_range=0, seasons_count=0;
    let IMDB_info, IMDB_id=0, IMDB_score=0, IMDB_votes_number=0,IMDB_awards=0;
    let RT_info=0, RT_score=0, RT_url_delta=0, RT_certificate=0;
    let MAL_info=0, MAL_url=0, MAL_score=0, episodecount=0, MAL_year=0, anime_flag=0;  
    
    //Grab TMDB ID
    if(window.location.href.includes("https://www.themoviedb.org/movie/")){
      content="movie";
      TMDB_id = parseInt(window.location.href.split("https://www.themoviedb.org/movie/")[1].split("-")[0]);
    }else if(window.location.href.includes("https://www.themoviedb.org/tv/")){
      content="tv";
      TMDB_id = parseInt(window.location.href.split("https://www.themoviedb.org/tv/")[1].split("-")[0]);
    }else{return;}
  
    //Get TMDB title info
    TMDB_info = await TMDB_title_api(TMDB_id,content);
    if(content==="movie"){
      TMDB_title=TMDB_info[0];
      TMDB_original_title=TMDB_info[1];
      TMDB_year=TMDB_info[2];
      IMDB_id=TMDB_info[3];
      if(parseInt(TMDB_info[4])===1)  anime_flag="movie";
    }else if(content==="tv"){
      TMDB_title=TMDB_info[0];
      TMDB_original_title=TMDB_info[1];
      TMDB_year=TMDB_info[2];
      tv_year_range=TMDB_info[3];
      IMDB_id=TMDB_info[4];
      seasons_count=TMDB_info[5];
      if(parseInt(TMDB_info[6])===1)  anime_flag="tv";
    }
    
    //Get IMDB score
    if(IMDB_id!==0 && IMDB_id!=="error") IMDB_info = await ScrapeIMDB(IMDB_id);
    if(IMDB_info!=="error" && IMDB_info!==0){
      IMDB_score=IMDB_info[0];
      IMDB_votes_number=IMDB_info[1];
      IMDB_awards=IMDB_info[2];
    }
  
    //Get RT score
    if(TMDB_title!==0) RT_info = await RT_search_api(TMDB_title,TMDB_year,content);
    if(RT_info!=="error" && RT_info!==0){
      RT_url_delta=RT_info[0];
      RT_score=RT_info[1];
      RT_certificate=RT_info[2];
    }
  
    //Get MAL score
    if(TMDB_title!==0 && anime_flag!==0) MAL_info = await JIKAN_search_api(TMDB_title,TMDB_year,content);
    if(MAL_info!=="error" && MAL_info!==0 && anime_flag!==0){
      MAL_url=MAL_info[0];
      MAL_score=parseFloat(MAL_info[1]);
      if(Number.isInteger(MAL_score)){
        MAL_score = String(MAL_score)+".00"
      }else{
        let f_numbers = String(MAL_score).split(".")[1].length;
        if(f_numbers===1) MAL_score=MAL_score+"0";
      }
      episodecount=MAL_info[2];
      MAL_year=MAL_info[3];
    }
  
    //Build IMDB label
    let IMDB_image = document.createElement("img");
    let IMDB_image_div = document.createElement("div");
    let IMDB_link = document.createElement("a");
    let IMDB_link_div = document.createElement("div");
    let IMDB_label = document.createElement("label");
    let IMDB_div = document.createElement("div");
    
    if(IMDB_info!=="error" && IMDB_info!==0){
      IMDB_image.src="https://i.postimg.cc/Y2VnQwMb/245px-IMDB-Logo-2016-svg.png"; IMDB_image.style.width="60px"; 
      IMDB_image_div.append(IMDB_image);
      
      IMDB_link.href="https://www.imdb.com/title/"+IMDB_id; IMDB_link.innerText=IMDB_score; IMDB_link.style.color="gold"; IMDB_link.style.fontWeight = 'bold';  IMDB_link.style.marginLeft="auto";  IMDB_link.style.marginRight="auto";
      IMDB_label.innerText="("+IMDB_votes_number+")"; IMDB_label.style.fontSize="50%"; IMDB_label.style.color="gold"; IMDB_label.style.paddingLeft="5px";
      IMDB_link_div.append(IMDB_link,IMDB_label);

      IMDB_div.style.marginRight="15px"; IMDB_div.style.width="60px"
      IMDB_div.append(IMDB_image_div,IMDB_link_div);
    }
   
    //Build RT label
    let RT_image = document.createElement("img");
    let RT_image_certificate = document.createElement("img");
    let RT_image_div = document.createElement("div");
    let RT_link = document.createElement("a");
    let RT_link_div = document.createElement("div");
    let RT_div = document.createElement("div");
    
    if(RT_info!=="error" && RT_info!==0){
      RT_image.src="https://i.postimg.cc/0yxH2yjM/Rotten-Tomatoes-2018.png";
      RT_image.style.width="65px"; RT_image.style.marginRight="15px"; RT_image.style.marginLeft="5px";
      RT_image_div.append(RT_image); RT_image_div.style.paddingTop="6px";
      
      RT_image_certificate.style.width="12px"; RT_link.style.paddingRight="10px"; RT_link.style.paddingLeft="15px";
      if(RT_certificate===0) RT_image_certificate.src='https://i.postimg.cc/Kz5DWGGB/tomato.png';
      if(RT_certificate==="fresh") RT_image_certificate.src='https://i.postimg.cc/T1RcJQfC/fresh.png';
      if(RT_certificate==="rotten") RT_image_certificate.src='https://i.postimg.cc/fbq3rKc8/rotten.png';
      RT_link.href="https://www.rottentomatoes.com"+RT_url_delta;  RT_link.innerText= RT_score===0 ? "N/A" : RT_score ; RT_link.style.color="red"; RT_link.style.fontWeight="bold";
      RT_link_div.append(RT_link,RT_image_certificate); RT_link_div.style.paddingTop="6px";
      
      RT_div.append(RT_image_div,RT_link_div);
    }
  
    //Build MAL Label
    let MAL_image = document.createElement("img");
    let MAL_image_div = document.createElement("div");
    let MAL_link = document.createElement("a");
    let MAL_link_div = document.createElement("div");
    let MAL_div = document.createElement("div");

    if(MAL_info!==0 && MAL_info!=="error"){
      MAL_image.src="https://i.postimg.cc/bwPmk7d2/apple-touch-icon-256.png"; MAL_image.style.width="28px"; MAL_image.style.borderRadius = '3px'
      MAL_image_div.append(MAL_image); MAL_image_div.style.paddingLeft="5px";
      MAL_link.innerText=MAL_score; MAL_link.href=MAL_url; MAL_link.style.color="dodgerblue"; MAL_link.style.fontWeight="bold";
      MAL_link_div.append(MAL_link); MAL_link_div.style.paddingTop="2px";
      MAL_div.append(MAL_image_div,MAL_link_div); MAL_div.style.paddingLeft="5px"; MAL_div.style.paddingRight="19px";
    }
  
    //Build Oscars Label
    let AWARDS_image = document.createElement("img");
    let AWARDS_link = document.createElement("a");
    let AWARDS_div = document.createElement("div");

    if(IMDB_awards!==0){
      AWARDS_image.src="https://i.postimg.cc/vmmQ3SD0/Oscars-logo.png"; AWARDS_image.style.width="28px";
      AWARDS_link.innerText=IMDB_awards; AWARDS_link.href="https://www.imdb.com/title/"+IMDB_id+"/awards/"; AWARDS_link.style.fontSize="80%"; AWARDS_link.style.paddingLeft="5px";
      AWARDS_div.append(AWARDS_image,AWARDS_link); AWARDS_div.style.paddingBottom="25px";
    }
    
  
    //Append All
    let page_score_icon = document.getElementsByClassName("chart");
    if(anime_flag!==0) page_score_icon[0].after(IMDB_div,RT_div,MAL_div); else page_score_icon[0].after(IMDB_div,RT_div);
    let top_bar = document.getElementsByClassName("auto actions");
    if(IMDB_awards!==0) top_bar[0].after(AWARDS_div);
    
    
  
}

main();