yoharnu / PTP Home Page - Custom "Latest" Tabs

// ==UserScript==
// @name         PTP Home Page - Custom "Latest" Tabs
// @namespace    http://tampermonkey.net/
// @version      0.4.1
// @description  Allow user to customize "latest" movies on PTP homepage
// @author       yoharnu
// @downloadURL https://openuserjs.org/install/yoharnu/PTP_Home_Page_-_Custom_Latest_Tabs.user.js
// @updateURL https://openuserjs.org/meta/yoharnu/PTP_Home_Page_-_Custom_Latest_Tabs.meta.js
// @icon         https://www.google.com/s2/favicons?domain=passthepopcorn.me
// @license      MIT
// @match        http*://*.passthepopcorn.me/torrents.php*
// @match        http*://*.passthepopcorn.me/index.php*
// @match        http*://*.passthepopcorn.me/user.php?action=edit*
// @grant        GM_xmlhttpRequest
// @grant        GM_setValue
// @grant        GM_getValue
// ==/UserScript==

var filters = [];
(function () {
  'use strict';

  filters = GM_getValue('filters');
  if (!filters)
    filters = [];

  if (window.location.pathname.includes('torrents.php') && !window.location.search.includes('?id=')) {
    let resultCount = document.querySelector('.search-form__footer');

    let addToHomeLink = document.createElement('a');
    addToHomeLink.innerHTML = 'Add Current Filters to Home Page';
    addToHomeLink.href = '#';
    addToHomeLink.onclick = () => addCurrentFilterToHome();

    resultCount.insertAdjacentElement('afterend', document.createElement('br'));
    resultCount.insertAdjacentElement('afterend', addToHomeLink);

    {
      let movies;
      const scripts = document.getElementsByTagName('script');
      for (var i = 0; i < scripts.length; i++) {
        var script = scripts[i].innerHTML;
        if (script.includes('PageData')) {
          script = JSON.parse('{' + script.split('PageData = {')[1].split('};')[0] + '}');
          movies = script["Movies"];
          break;
        }
      }

      let firstFiveMovies = [];
      if (movies) {
        for (let i = 0; i < movies.length && i < 5; i++) {
          firstFiveMovies.push(movies[i]);
        }
      }

      setWithExpiry('customTabs' + window.location.search, firstFiveMovies, 5 * 60 * 1000);
    }
  }
  else if (window.location.pathname.includes('index.php')) {
    for (let i = 0; i < filters.length; i++) {
      if (!filters[i].name) {
        filters.splice(i, 1);
        GM_setValue('filters', filters);
        window.location.reload();
      }
    }
    for (let customTab of filters) {
      addLink(customTab);
      addTable(customTab);
    }
    InitializeSimpleTabControl();
  }
  else if (window.location.pathname.includes('user.php') && window.location.search.includes('action=edit')) {
    let defaultSelection = document.querySelector('select[name="Home_LatestUploads"]');

    const defaultTabCurrent = GM_getValue('defaultTab');

    for (let customTab of filters) {
      let option = document.createElement('option');
      option.innerHTML = customTab.name;
      option.setAttribute('custom-tab-default', encodeFilterName(customTab.name));
      defaultSelection.appendChild(option);
      if (defaultTabCurrent === encodeFilterName(customTab.name))
        defaultSelection.selectedIndex = defaultSelection.options.length - 1;
    }

    let submitButton = document.querySelector('input[type="submit"]');
    submitButton.onclick = () => {
      let selection = defaultSelection.options[defaultSelection.selectedIndex].getAttribute('custom-tab-default');
      if (!selection)
        selection = null;
      GM_setValue('defaultTab', selection);
    };
  }
})();

function addLink(item) {
  const name = item.name;
  const url = item.searchurl;

  let linkList = document.querySelector('div#last5t div.panel__heading span.panel__heading__title');
  linkList.innerHTML = linkList.innerHTML + ' | ';

  let a = document.createElement('a');
  a.href = url;
  a.innerHTML = name;
  a.classList.add('simple-tabs__link');
  a.setAttribute('data-tab-target', '#last5custom' + encodeFilterName(item.name) + '_table');

  linkList.appendChild(a);
}

function InitializeSimpleTabControl() {
  for (let tab of document.querySelectorAll('#last5-tab-control .simple-tabs__link')) {
    let defaultTabID = GM_getValue('defaultTab');
    if (tab.getAttribute('data-tab-target') === '#last5custom' + defaultTabID + '_table') {
      SwitchToTab(tab);
    }

    tab.onclick = function (event) {
      event.preventDefault();
      SwitchToTab(this);
    };
  }
}

function SwitchToTab(tabBarLinkElement) {
  for (let tab of document.querySelectorAll('#last5-tab-control .simple-tabs__link')) {
    tab.classList.remove("simple-tabs__link--active");
  }
  tabBarLinkElement.classList.add("simple-tabs__link--active");

  for (let table of document.querySelectorAll('table.last5-movies__table')) {
    if (!table.classList.contains("hidden")) {
      table.classList.add("hidden");
    }
  }

  document.querySelector(tabBarLinkElement.getAttribute("data-tab-target")).classList.remove("hidden");
}

function addTable(item) {
  let tableList = document.querySelector('div#last5');
  let table = document.createElement('table');
  table.classList.add('last5-movies__table');
  table.classList.add('table--no-border');
  table.classList.add('hidden');
  table.id = 'last5custom' + encodeFilterName(item.name) + '_table';
  tableList.appendChild(table);
  let tbody = document.createElement('tbody');
  table.appendChild(tbody);

  getFirstFive(item.searchurl, (firstFiveData) => {
    // Add posters
    {
      let tr = document.createElement('tr');
      for (let movie of firstFiveData) {
        let td = document.createElement('td');
        td.classList.add('text--center');
        td.width = '20%';
        let a = document.createElement('a');
        a.style.backgroundImage = "url('" + movie.Cover + "')";

        if (movie.GroupTime) {
          a.href = 'torrents.php?id=' + movie.GroupId;
        }
        else {
          const latestTorrent = getLatestTorrent(movie);

          a.href = 'torrents.php?id=' + movie.GroupId + '&torrentid=' + latestTorrent.TorrentId;
        }

        a.classList.add('last5-movies__link');
        a.classList.add('js-movie-tooltip-triggerer');
        a.title = movie.Title + ' [' + movie.Year + ']';
        td.appendChild(a);
        tr.appendChild(td);
      }
      tbody.appendChild(tr);
    }

    // Add movie titles
    {
      let tr = document.createElement('tr');
      for (let movie of firstFiveData) {
        let td = document.createElement('td');
        td.classList.add('text--center');
        td.width = '20%';
        let a = document.createElement('a');
        a.classList.add('l_movie');
        a.style.fontWeight = 'bold';
        a.innerHTML = movie.Title;

        if (movie.GroupTime) {
          a.href = 'torrents.php?id=' + movie.GroupId;
          td.appendChild(a);
          td.appendChild(document.createElement('br'));
          td.innerHTML = td.innerHTML + movie.GroupTime;

        }
        else {
          const latestTorrent = getLatestTorrent(movie);

          a.href = 'torrents.php?id=' + movie.GroupId + '&torrentid=' + latestTorrent.TorrentId;
          td.appendChild(a);
          td.appendChild(document.createElement('br'));

          getUploader(latestTorrent.TorrentId, span => td.innerHTML = td.innerHTML + span);
        }

        tr.appendChild(td);
      }
      tbody.appendChild(tr);
    }

    // Add delete button and "show all" link
    {
      let tr = document.createElement('tr');
      tr.classList.add("last5-movies__show-all-row"); {
        let td = document.createElement('td');
        td.colSpan = '2';
        td.style.textAlign = 'left';
        let a = document.createElement('a');
        a.href = '#';
        a.style.color = 'red';
        a.innerHTML = 'Delete Custom Tab';
        a.setAttribute('custom-tab-name', item.name);
        a.classList.add("last5-movies__show-all-link");
        a.onclick = function (event) {
          event.preventDefault();
          deleteCustomTab(this.getAttribute('custom-tab-name'));
        };
        td.appendChild(a);
        tr.appendChild(td);
      }

      {
        let td = document.createElement('td');
        td.colSpan = '3';
        let a = document.createElement('a');
        a.href = item.searchurl;
        a.classList.add("last5-movies__show-all-link");
        a.innerHTML = 'Show All';

        td.appendChild(a);
        tr.appendChild(td);
      }
      tbody.appendChild(tr);
    }
  });
}

function getUploader(torrentID, callback) {
  let cache = getWithExpiry('customTabs?torrentId=' + torrentID);

  if (cache) {
    callback(cache);
    return;
  }

  GM_xmlhttpRequest({
    method: 'GET',
    url: window.location.origin + '/torrents.php?torrentid=' + torrentID,
    onload: function (xhr) {
      if (xhr.readyState === 4 && xhr.status === 200) {
        let newDoc = document.implementation.createHTMLDocument();
        newDoc.body.innerHTML = xhr.responseText;

        let timeSpan = newDoc.querySelector('#torrent_' + torrentID).querySelector('.movie-page__torrent__panel span span.time').outerHTML;

        let div = newDoc.querySelector('#torrent_' + torrentID + ' .torrent_info_first_block');
        let reseedImg = div.querySelector('img');
        if (reseedImg) {
          timeSpan = '<span class="time">' + reseedImg.title.split('Re-seeded ')[1] + '</span>';
          reseedImg = reseedImg.outerHTML + ' ';
        }

        let usernameArray = div.querySelectorAll('a.username');
        let username = '';
        for (let u of usernameArray)
          username = u.outerHTML;
        let returnHTML = timeSpan + '<br/>';
        if (reseedImg)
          returnHTML = returnHTML + reseedImg;
        returnHTML = returnHTML + username;

        setWithExpiry('customTabs?torrentId=' + torrentID, returnHTML, 1 * 60 * 1000);
        callback(returnHTML);
      }
      else if (xhr.readyState === 4) {
        console.log('Error: ' + xhr.status);
      }
    }
  });
}

function getLatestTorrent(movie) {
  let latestTorrent = null;
  for (let quality of movie.GroupingQualities) {
    for (let currTorrent of quality.Torrents) {
      if (!latestTorrent) {
        latestTorrent = currTorrent;
      }
      else
      if (currTorrent.TorrentId > latestTorrent.TorrentId) {
        latestTorrent = currTorrent;
      }
    }
  }
  return latestTorrent;
}

function deleteCustomTab(tabName) {
  if (confirm('Are you sure you want to delete the tab named "' + tabName + '"?')) {
    for (let i = 0; i < filters.length; i++) {
      if (filters[i].name === tabName || !filters[i].name) {
        filters.splice(i, 1);
      }
    }
    GM_setValue('filters', filters);
    window.location.reload();
  }
}

function setWithExpiry(key, value, ttl) {
  const now = new Date();

  // 'item' is an object which contains the original value
  // as well as the time when it's supposed to expire
  const item = {
    value: value,
    expiry: now.getTime() + ttl
  };
  localStorage.setItem(key, JSON.stringify(item));
}

function getWithExpiry(key) {
  const itemStr = localStorage.getItem(key);
  // if the item doesn't exist, return null
  if (!itemStr) {
    return null;
  }
  const item = JSON.parse(itemStr);
  const now = new Date();
  // compare the expiry time of the item with the current time
  if (now.getTime() > item.expiry) {
    // If the item is expired, delete the item from storage
    // and return null
    localStorage.removeItem(key);
    return null;
  }
  return item.value;
}

function getFirstFive(url, callback) {
  let cache = getWithExpiry('customTabs' + url.split('torrents.php')[1]);

  if (cache) {
    console.log(cache);
    callback(cache);
    return;
  }

  GM_xmlhttpRequest({
    method: 'GET',
    url: window.location.origin + '/' + url,
    onload: function (xhr) {
      if (xhr.readyState === 4 && xhr.status === 200) {
        let newDoc = document.implementation.createHTMLDocument();
        newDoc.body.innerHTML = xhr.responseText;
        let movies;
        const scripts = newDoc.getElementsByTagName('script');
        for (var i = 0; i < scripts.length; i++) {
          var script = scripts[i].innerHTML;
          if (script.includes('PageData')) {
            script = JSON.parse('{' + script.split('PageData = {')[1].split('};')[0] + '}');
            movies = script["Movies"];
            break;
          }
        }

        let firstFiveMovies = [];
        if (movies) {
          for (let i = 0; i < movies.length && i < 5; i++) {
            firstFiveMovies.push(movies[i]);
          }
        }

        setWithExpiry('customTabs' + url.split('torrents.php')[1], firstFiveMovies, 5 * 60 * 1000);
        callback(firstFiveMovies);
      }
      else if (xhr.readyState === 4) {
        console.log('Error: ' + xhr.status);
      }
    }
  });
}

function addCurrentFilterToHome() {
  const filterName = prompt("What do you want to name this filter?");
  if (validateFilterName(filterName)) {
    let exists = false;

    for (let tab of filters) {
      if (encodeFilterName(tab.name) === encodeFilterName(filterName)) {
        exists = true;
        if (confirm('There is already a filter named "' + filterName + '".\nWould you like to replace it with this new filter?')) {
          tab.name = filterName;
          tab.searchurl = getSearchURL(document.forms.filter);
        }
        else {
          return;
        }
      }
    }

    if (!exists)
      filters.push({
        'name': filterName,
        'searchurl': getSearchURL(document.forms.filter)
      });
    GM_setValue('filters', filters);
  }
}

function validateFilterName(filterName) {
  if (!filterName) {
    alert('You must enter a filter name');
    return false;
  }

  const letters = /^[0-9a-zA-Z\- '",()[\]]+$/;
  if (!letters.test(filterName)) {
    alert('"' + filterName + '" contains invalid characters');
    return false;
  }

  return true;
}

function encodeFilterName(filterName) {
  if (!filterName) {
    return filterName;
  }

  return filterName.toLowerCase().replaceAll(' ', '_').replaceAll('\'', '').replaceAll('"', '').replaceAll('(', '').replaceAll(')', '').replaceAll('[', '').replaceAll(']', '').replaceAll(',', '');
}

function getSearchURL(form) {
  let args = '';
  if (form.order_by) {
    if (form.order_by.value === 'creationtime' || form.order_by.value === 'gptime') {
      args = args + addToURL('order_by', form.order_by);
    }
  }
  args = args + addToURL('searchstr', form.searchstr);
  args = args + addToURL('year', form.year);
  args = args + addToURL('artistname', form.artistname);
  args = args + addToURL('inallakas', form.inallakas);
  args = args + addToURL('language', form.language);
  args = args + addToURL('subtitles', form.subtitles);
  args = args + addToURL('countrylist', form.countrylist);
  args = args + addToURL('country_type', form.country_type);
  args = args + addToURL('taglist', form.taglist);
  args = args + addToURL('tags_type', form.tags_type);
  args = args + addToURL('imdbrating', form.imdbrating);
  args = args + addToURL('imdbvotes', form.imdbvotes);
  args = args + addToURL('ptprating', form.ptprating);
  args = args + addToURL('ptpvotes', form.ptpvotes);
  args = args + addToURL('mcrating', form.mcrating);
  args = args + addToURL('rtrating', form.rtrating);
  args = args + addToURL('encoding', form.encoding);
  args = args + addToURL('format', form.format);
  args = args + addToURL('media', form.media);
  args = args + addToURL('resolution', form.resolution);
  args = args + addToURL('scene', form.scene);
  args = args + addToURL('freetorrent', form.freetorrent);
  args = args + addToURL('runtime', form.runtime);
  args = args + addToURL('remastertitle', form.remastertitle);
  args = args + addToURL('remasteryear', form.remasteryear);
  args = args + addToURL('filelist', form.filelist);
  args = args + addToURL('grouping', form.grouping);
  args = args + addToURL('filter_cat[1]', form["filter_cat[1]"]);
  args = args + addToURL('filter_cat[2]', form["filter_cat[2]"]);
  args = args + addToURL('filter_cat[3]', form["filter_cat[3]"]);
  args = args + addToURL('filter_cat[4]', form["filter_cat[4]"]);
  args = args + addToURL('filter_cat[5]', form["filter_cat[5]"]);
  args = args + addToURL('filter_cat[6]', form["filter_cat[6]"]);

  if (args[0] === '&') {
    args = args.substr(1);
  }

  args = encodeURI(args);

  return 'torrents.php?' + args;
}

function addToURL(name, item) {
  if (item) {
    if (item.type === 'checkbox') {
      if (item.checked) {
        return '&' + name + '=' + item.value;
      }
      else {
        return '';
      }
    }
    else if (item.value !== null && item.value !== "" && item.value) {
      return '&' + name + '=' + item.value;
    }
  }
  return '';
}