yoharnu / PTP Synopsis Swapper

// ==UserScript==
// @name         PTP Synopsis Swapper
// @namespace    http://tampermonkey.net/
// @version      0.5.2
// @description  Give options for which synopsis to display
// @author       yoharnu
// @match        http*://*.passthepopcorn.me/torrents.php?id=*
// @icon         https://www.google.com/s2/favicons?domain=passthepopcorn.me
// @downloadURL  https://openuserjs.org/install/yoharnu/PTP_Synopsis_Swapper.user.js
// @updateURL    https://openuserjs.org/meta/yoharnu/PTP_Synopsis_Swapper.meta.js
// @license      MIT
// @require      https://openuserjs.org/src/libs/sizzle/GM_config.js
// @grant        GM_xmlhttpRequest
// @grant        GM_getValue
// @grant        GM_setValue
// @connect      imdb.com
// @connect      metacritic.com
// @connect      rottentomatoes.com
// @connect      themoviedb.org
// ==/UserScript==

var IMDBsynopsis = [];
var MCsynopsis = '';
var RTsynopsis = '';
var TMDBsynopsis = '';
var PTPsynopsis = '';

(function () {
  'use strict';

  let synopsisDiv = document.getElementById('synopsis');
  PTPsynopsis = synopsisDiv.innerHTML.trim().replace(/\((.+?)\)/g, function (a, b) {
    return "(<a href='artist.php?artistname=" + b + "'>" + b + "</a>)"
  });
  synopsisDiv.innerHTML = '';

  let shortest = PTPsynopsis;
  let longest = PTPsynopsis;

  GM_config.init({
    'id': 'synopsis_config',
    'title': 'Synopsis Swapper Settings',
    'fields': {
      'preferred': {
        'label': 'Preferred Synopsis',
        'type': 'select',
        'options': ['Shortest', 'By Rank', 'Longest'],
        'default': 'By Rank'
      },
      'ptprank': {
        'label': 'PTP Rank [1-5]',
        'type': 'int',
        'min': 1,
        'max': 5,
        'default': 1,
        'size': 1
      },
      'tmdbrank': {
        'label': 'TMDb Rank [1-5]',
        'type': 'int',
        'min': 1,
        'max': 5,
        'default': 2,
        'size': 1
      },
      'rtrank': {
        'label': 'Rotten Tomatoes Rank [1-5]',
        'type': 'int',
        'min': 1,
        'max': 5,
        'default': 3,
        'size': 1
      },
      'mcrank': {
        'label': 'Metacritic Rank [1-5]',
        'type': 'int',
        'min': 1,
        'max': 5,
        'default': 4,
        'size': 1
      },
      'imdbrank': {
        'label': 'IMDb Rank [1-5]',
        'type': 'int',
        'min': 1,
        'max': 5,
        'default': 5,
        'size': 1
      },
      'allowspoilers': {
        'label': 'Allow Spoilers',
        'type': 'checkbox',
        'default': false
      },
      'abbreviate': {
        'label': 'Abbreviate Site Names',
        'type': 'checkbox',
        'default': true
      },
      'showauthor': {
        'label': 'Display Author (when available)',
        'type': 'checkbox',
        'default': true
      },
      'displaylength': {
        'label': 'Display Synopsis Length',
        'type': 'checkbox',
        'default': false
      }
    },
    'css': 'div#synopsis_config_wrapper{max-width:400px;margin-left:auto;margin-right:auto;}'
  });

  let configLink = document.createElement('a');
  configLink.href = '#';
  configLink.innerHTML = '[Settings]';
  configLink.style = 'float:right';
  configLink.onclick = () => GM_config.open();

  synopsisDiv.appendChild(configLink);

  let bestRank = GM_config.get('ptprank');

  let dropdownList = document.createElement('select');
  dropdownList.id = 'synopsisSelect';

  let option = document.createElement('option');
  option.value = 'ptp';
  option.selected = true;
  if (GM_config.get('abbreviate')) {
    option.innerHTML = 'PTP';
  }
  else {
    option.innerHTML = 'PassThePopcorn';
  }

  if (GM_config.get('displaylength')) {
    option.innerHTML = option.innerHTML + ' [' + PTPsynopsis.length + ' chars]';
  }

  dropdownList.appendChild(option);

  let label = document.createElement('label');
  label.innerHTML = 'Source: ';
  synopsisDiv.appendChild(label);

  synopsisDiv.appendChild(dropdownList);

  let synopsis = document.createElement('p');
  synopsis.id = 'synopsis-custom';
  synopsis.innerHTML = PTPsynopsis;

  synopsisDiv.appendChild(synopsis);

  dropdownList.onchange = () => updateSynopsis();

  let imdbID = document.getElementById('imdb-title-link');
  if (imdbID) {
    imdbID = imdbID.href.split('/title/tt')[1].split('/')[0];
    getIMDBsynopsis(imdbID, (synopsisArray) => {
      IMDBsynopsis = synopsisArray;
      let dropdownList = document.getElementById('synopsisSelect');
      if (dropdownList) {
        for (let i = 0; i < synopsisArray.length; i++) {
          let option = document.createElement('option');
          option.value = 'imdb_' + i;
          if (synopsisArray[i].type === 'synopsis') {
            if (GM_config.get('allowspoilers')) {
              if (GM_config.get('abbreviate')) {
                option.innerHTML = 'IMDb *SPOILERS*';
              }
              else {
                option.innerHTML = 'Internet Movie Database *SPOILERS*';
              }
            }
            else {
              continue;
            }
          }
          else {
            if (GM_config.get('abbreviate')) {
              if (GM_config.get('showauthor')) {
                option.innerHTML = 'IMDb (' + synopsisArray[i].author + ')';
              }
              else if (synopsisArray.length > 2) {
                option.innerHTML = 'IMDb (' + (i + 1) + ')';
              }
              else {
                option.innerHTML = 'IMDb';
              }
            }
            else {
              if (GM_config.get('showauthor')) {
                option.innerHTML = 'Internet Movie Database (' + synopsisArray[i].author + ')';
              }
              else if (synopsisArray.length > 1) {
                option.innerHTML = 'Internet Movie Database (' + (i + 1) + ')';
              }
              else {
                option.innerHTML = 'Internet Movie Database';
              }
            }
          }
          if (GM_config.get('displaylength') && synopsisArray[i].synopsis) {
            option.innerHTML = option.innerHTML + ' [' + synopsisArray[i].synopsis.replace(/<.+?>/g, "").length + ' chars]';
          }
          dropdownList.appendChild(option);

          if (GM_config.get('preferred') === 'Shortest')
            console.log('shortest: ' + shortest.length + '    imdb_' + i + ': ' + synopsisArray[i].synopsis.innerHTML.length);
          else if (GM_config.get('preferred') === 'Longest')
            console.log('longest: ' + longest.length + '    imdb_' + i + ': ' + synopsisArray[i].synopsis.innerHTML.length);

          if (i === 0 && GM_config.get('preferred') === 'By Rank' && GM_config.get('imdbrank') < bestRank) {
            bestRank = GM_config.get('imdbrank');
            option.selected = true;
            updateSynopsis();
          }
          else if (GM_config.get('preferred') === 'Shortest' && synopsisArray[i].synopsis.innerHTML.length < shortest.length) {
            shortest = synopsisArray[i].synopsis.innerHTML;
            option.selected = true;
            updateSynopsis();
          }
          else if (GM_config.get('preferred') === 'Longest' && synopsisArray[i].synopsis.innerHTML.length > longest.length) {
            longest = synopsisArray[i].synopsis.innerHTML;
            option.selected = true;
            updateSynopsis();
          }
        }
      }
    });
    getTMDBsynopsis(imdbID, (synopsis) => {
      TMDBsynopsis = synopsis.trim();
      TMDBsynopsis = TMDBsynopsis.replace(/\((.+?)\)/g, function (a, b) {
        return "(<a href='artist.php?artistname=" + b + "'>" + b + "</a>)"
      });
      let dropdownList = document.getElementById('synopsisSelect');
      if (dropdownList) {
        let option = document.createElement('option');
        option.value = 'tmdb';
        if (GM_config.get('abbreviate')) {
          option.innerHTML = 'TMDB';
        }
        else {
          option.innerHTML = 'The Movie Database';
        }

        if (GM_config.get('displaylength')) {
          option.innerHTML = option.innerHTML + ' [' + TMDBsynopsis.replace(/<.+?>/g, "").length + ' chars]';
        }
        dropdownList.appendChild(option);

        if (GM_config.get('preferred') === 'Shortest')
          console.log('shortest: ' + shortest.length + '    tmdb: ' + synopsis.length);
        else if (GM_config.get('preferred') === 'Longest')
          console.log('longest: ' + longest.length + '    tmdb: ' + synopsis.length);

        if (GM_config.get('preferred') === 'By Rank' && GM_config.get('tmdbrank') < bestRank) {
          bestRank = GM_config.get('tmdbrank');
          option.selected = true;
          updateSynopsis();
        }
        else if (GM_config.get('preferred') === 'Shortest' && synopsis.length < shortest.length) {
          shortest = synopsis;
          option.selected = true;
          updateSynopsis();
        }
        else if (GM_config.get('preferred') === 'Longest' && synopsis.length > longest.length) {
          longest = synopsis;
          option.selected = true;
          updateSynopsis();
        }
      }
    });
  }

  let ratingsTable = document.getElementById('movie-ratings-table');
  let ratings = ratingsTable.children[0].children[0].children;
  for (let ratingObject of ratings) {
    if (ratingObject.children[0]) {
      if (ratingObject.children[0].children[0]) {
        var rating = ratingObject.children[0].children[0];
        if (rating.href) {
          if (rating.href.includes('metacritic.com')) {
            getMCsynopsis(rating.href.split('?')[0], (synopsis) => {
              MCsynopsis = synopsis.trim();
              MCsynopsis = MCsynopsis.split("").reverse().join("").replace(/^((\).+?\()|(\].+?\[))/, '').split("").reverse().join("").trim();
              MCsynopsis = MCsynopsis.replace(/\((.+?)\)/g, function (a, b) {
                return "(<a href='artist.php?artistname=" + b + "'>" + b + "</a>)"
              });

              let dropdownList = document.getElementById('synopsisSelect');
              if (dropdownList) {
                let option = document.createElement('option');
                option.value = 'mc';
                option.innerHTML = 'Metacritic';
                if (GM_config.get('displaylength')) {
                  option.innerHTML = option.innerHTML + ' [' + MCsynopsis.length + ' chars]';
                }
                dropdownList.appendChild(option);

                if (GM_config.get('preferred') === 'Shortest')
                  console.log('shortest: ' + shortest.length + '    mc: ' + synopsis.length);
                else if (GM_config.get('preferred') === 'Longest')
                  console.log('longest: ' + longest.length + '    mc: ' + synopsis.length);

                if (GM_config.get('preferred') === 'By Rank' && GM_config.get('mcrank') < bestRank) {
                  bestRank = GM_config.get('mcrank');
                  option.selected = true;
                  updateSynopsis();
                }
                else if (GM_config.get('preferred') === 'Shortest' && synopsis.length < shortest.length) {
                  shortest = synopsis;
                  option.selected = true;
                  updateSynopsis();
                }
                else if (GM_config.get('preferred') === 'Longest' && synopsis.length > longest.length) {
                  longest = synopsis;
                  option.selected = true;
                  updateSynopsis();
                }
              }
            });
          }
          else if (rating.href.includes('rottentomatoes.com')) {
            getRTsynopsis(rating.href.split('?')[0], (synopsis) => {
              RTsynopsis = synopsis.trim();
              RTsynopsis = RTsynopsis.replace(/\((.+?)\)/g, function (a, b) {
                return "(<a href='artist.php?artistname=" + b + "'>" + b + "</a>)"
              });

              let dropdownList = document.getElementById('synopsisSelect');
              if (dropdownList) {
                let option = document.createElement('option');
                option.value = 'rt';
                option.innerHTML = 'Rotten Tomatoes';
                if (GM_config.get('displaylength')) {
                  option.innerHTML = option.innerHTML + ' [' + RTsynopsis.length + ' chars]';
                }
                dropdownList.appendChild(option);

                if (GM_config.get('preferred') === 'Shortest')
                  console.log('shortest: ' + shortest.length + '    rt: ' + synopsis.length);
                else if (GM_config.get('preferred') === 'Longest')
                  console.log('longest: ' + longest.length + '    rt: ' + synopsis.length);

                if (GM_config.get('preferred') === 'By Rank' && GM_config.get('rtrank') < bestRank) {
                  bestRank = GM_config.get('rtrank');
                  option.selected = true;
                  updateSynopsis();
                }
                else if (GM_config.get('preferred') === 'Shortest' && synopsis.length < shortest.length) {
                  shortest = synopsis;
                  option.selected = true;
                  updateSynopsis();
                }
                else if (GM_config.get('preferred') === 'Longest' && synopsis.length > longest.length) {
                  longest = synopsis;
                  option.selected = true;
                  updateSynopsis();
                }
              }
            });
          }
        }
      }
    }
  }

})();

function updateSynopsis() {
  const dropdownList = document.getElementById('synopsisSelect');
  const choice = dropdownList.value;
  let synopsisElement = document.getElementById('synopsis-custom');

  if (choice === 'ptp') {
    console.log('Switching to PTP Synopsis');
    synopsisElement.innerHTML = PTPsynopsis;
  }
  else if (choice.substr(0, 4) === 'imdb') {
    console.log('Switching to IMDb Synopsis ' + choice.substr(5));
    synopsisElement.innerHTML = IMDBsynopsis[choice.substr(5)].synopsis;
  }
  else if (choice === 'mc') {
    console.log('Switching to MC Synopsis');
    synopsisElement.innerHTML = MCsynopsis;
  }
  else if (choice === 'rt') {
    console.log('Switching to RT Synopsis');
    if (GM_config.get('allowspoilers')) {
      synopsisElement.innerHTML = RTsynopsis;
    }
    else {
      synopsisElement.innerHTML = '<p style="color:red"><span style="font-weight:bold">SPOILER WARNING:</span> Rotten Tomatoes is known to sometimes have spoilers in their descriptions. Continue reading at your own risk.</p><p>' + RTsynopsis + '</p>';
    }
  }
  else if (choice === 'tmdb') {
    console.log('Switching to TMDB Synopsis');
    synopsisElement.innerHTML = TMDBsynopsis;
  }
  else {
    console.log('Defaulting to PTP Synopsis');
    synopsisElement.innerHTML = PTPsynopsis;
  }
}

function getIMDBsynopsis(imdbID, callback) {
  GM_xmlhttpRequest({
    method: 'GET',
    url: 'https://www.imdb.com/title/tt' + imdbID + '/plotsummary',
    onload: function (xhr) {
      if (xhr.readyState === 4 && xhr.status === 200) {
        // get synopsis
        let synopsis = [];

        let newDoc = document.implementation.createHTMLDocument();
        newDoc.body.innerHTML = xhr.responseText;

        const summaryUL = newDoc.getElementById('plot-summaries-content');
        for (let summaryLI of summaryUL.children) {
          if (summaryLI.id === 'no-summary-content')
            break;
          let author = 'unknown';
          if (summaryLI.children[1]) {
            if (summaryLI.children[1].children[0]) {
              if (summaryLI.children[1].children[0].children[0]) {
                author = summaryLI.children[1].children[0].children[0].innerHTML;
              }
            }
          }
          synopsis.push({
            'synopsis': summaryLI.children[0].innerHTML.replaceAll(/<\/?a.*?>/gi, '').trim().replace(/\((.+?)\)/g, function (a, b) {
              return "(<a href='artist.php?artistname=" + b + "'>" + b + "</a>)"
            }),
            'author': author,
            'type': 'summary'
          });
        }

        // get synopsis (which probably has spoilers)
        const synopsisUL = newDoc.getElementById('plot-synopsis-content');
        for (let synopsisLI of synopsisUL.children) {
          if (synopsisLI.id === 'no-synopsis-content')
            break;
          let author = 'unknown';
          synopsis.push({
            'synopsis': synopsisLI.innerHTML.replaceAll(/<\/?a.*?>/gi, '').trim().replace(/\((.+?)\)/g, function (a, b) {
              return "(<a href='artist.php?artistname=" + b + "'>" + b + "</a>)"
            }),
            'author': author,
            'type': 'synopsis'
          });
        }

        // callback with synopsis
        callback(synopsis);
      }
    }
  });
}

function getMCsynopsis(MCurl, callback) {
  GM_xmlhttpRequest({
    method: 'GET',
    url: MCurl + '/details',
    onload: function (xhr) {
      if (xhr.readyState === 4 && xhr.status === 200) {
        let newDoc = document.implementation.createHTMLDocument();
        newDoc.body.innerHTML = xhr.responseText;

        let summaryWrapper = newDoc.getElementsByClassName('summary')[0];
        if (summaryWrapper) {
          let synopsis = summaryWrapper.children[1].innerHTML;
          if (synopsis) {
            callback(synopsis);
          }
        }
      }
    }
  });
}

function getRTsynopsis(RTurl, callback) {
  GM_xmlhttpRequest({
    method: 'GET',
    url: RTurl,
    onload: function (xhr) {
      if (xhr.readyState === 4 && xhr.status === 200) {
        let newDoc = document.implementation.createHTMLDocument();
        newDoc.body.innerHTML = xhr.responseText;

        let summaryWrapper = newDoc.getElementById('movieSynopsis');
        if (summaryWrapper) {
          let synopsis = summaryWrapper.innerHTML;
          if (synopsis) {
            callback(synopsis);
          }
        }
      }
    }
  });
}

function getTMDBsynopsis(imdb_id, callback) {
  GM_xmlhttpRequest({
    method: 'GET',
    url: 'https://www.themoviedb.org/redirect?external_source=imdb_id&external_id=tt' + imdb_id,
    onload: function (xhr) {
      if (xhr.readyState === 4 && xhr.status === 200) {
        let newDoc = document.implementation.createHTMLDocument();
        newDoc.body.innerHTML = xhr.responseText;

        let summaryWrapper = newDoc.getElementsByClassName('overview')[0];
        if (summaryWrapper) {
          let synopsis = summaryWrapper.innerHTML;
          if (synopsis) {
            if (synopsis.includes('We don\'t have an overview translated')) {
              return;
            }
            else {
              callback(synopsis);
            }
          }
        }
      }
    }
  });
}