skip / WatchOnlineMenu

// ==UserScript==
// @name         WatchOnlineMenu
// @version      4.1.9.1
// @namespace    https://openuserjs.org/users/skip
// @description  [shikimori.org] Добавляет ссылки на сайты просмотра аниме
// @author       Pasha13666
// @match        http://shikimori.one/*
// @match        https://shikimori.one/*
// @match        http://shikimori.org/*
// @match        https://shikimori.org/*
// @match        https://plashiki.su/*
// @match        https://*.shikimorilive.top/*
// @updateURL    https://openuserjs.org/meta/skip/WatchOnlineMenu.meta.js
// @homepageURL  https://github.com/GlitchSkip/AltWatcher4
// @run-at       document-body
// @license      MIT
// @grant        GM_addStyle
// @grant        GM_getValue
// @grant        GM_setValue
// @grant        GM_log
// @grant        GM_xmlhttpRequest
// @connect      raw.githubusercontent.com
// @copyright    2019, Pasha13666 (https://openuserjs.org/users/Pasha13666)
// ==/UserScript==

/* div - $ph
 *   div - $wo
 *     a.aw4-dark-button.aw4-link - $link
 *     a.aw4-dark-button.aw4-hider - $hider
 *     div.clearfix - $clearfix
 *
 *   div - $bar
 *     a.aw4-dark-button.watch-online
 *     ...
 *     div.aw4-langs - $langs
 *       a.aw4-dark-button.aw4-lang - $ru
 *       a.aw4-dark-button.aw4-lang - $en
 */
function WatchOnlineMenu(services) {
  this.services = services;

  this.$ph = document.getElementsByClassName('watch-online')[0];
  this.$rb = document.getElementsByClassName("c-info-right")[0];
  this.$wo = document.createElement('div');
  this.$link = document.createElement('a');
  this.$hider = document.createElement('a');
  this.$clearfix = document.createElement('div');
  this.$bar = document.createElement('div');
  this.$langs = document.createElement('div');
  this.$ru = document.createElement('a');
  this.$en = document.createElement('a');

  this.$link.target = "_blank";
  this.$ru.title = 'Искать по русскому названию';
  this.$en.title = 'Искать по английскому названию';

  this.$hider.innerText = "▼";
  this.$ru.innerText = 'ru';
  this.$en.innerText = 'en';

  this.$link.classList = "aw4-dark-button aw4-link"
  this.$hider.classList = "aw4-dark-button aw4-hider";
  this.$clearfix.classList = "clearfix";

  this.$bar.classList = "";
  this.$ru.classList = "aw4-dark-button aw4-lang";
  this.$en.classList = "aw4-dark-button aw4-lang";
  this.$langs.classList = "aw4-langs";

  if (GM_getValue("searchLang", 'ru') === 'ru') this.$ru.classList.add('aw4-selected');
  else this.$en.classList.add('aw4-selected');

  this.isHentai = document.querySelector('a.b-tag[href*="genre/12"]') != null;

  if (this.$ph !== undefined) {
    this.$rb.removeChild(this.$ph);
  }

  this.$ph = document.createElement('div');
  this.$rb.appendChild(this.$ph);

  for (var i = 0; i < this.services.length; i++) {
    var v = this.services[i];
    if (this.isHentai ? v.forRx : v.forNotRx)
      this.$bar.appendChild(this.createPlayerButton(v, i));
  }

  this.redrawButton();

  this.$ru.addEventListener('click', () => {
    this.$ru.classList.add('aw4-selected');
    this.$en.classList.remove('aw4-selected');
    GM_setValue("searchLang", 'ru');
    this.redrawButton();
  });

  this.$en.addEventListener('click', () => {
    this.$en.classList.add('aw4-selected');
    this.$ru.classList.remove('aw4-selected');
    GM_setValue("searchLang", 'en');
    this.redrawButton();
  });

  this.$hider.addEventListener('click', () => {
    this.$bar.style.display = this.$bar.style.display === 'none' ? '' : 'none';
  });

  this.$langs.appendChild(this.$ru);
  this.$langs.appendChild(this.$en);
  this.$bar.appendChild(this.$langs);
  this.$wo.appendChild(this.$link);
  this.$wo.appendChild(this.$hider);
  this.$wo.appendChild(this.$clearfix);
  this.$ph.appendChild(this.$wo);
  this.$ph.appendChild(this.$bar);
}

WatchOnlineMenu.prototype.createPlayerButton = function (service, id) {
  var a = document.createElement('a');
  a.classList = "aw4-dark-button";
  a.innerText = service.description || service.name;
  a.addEventListener('click', (ev) => {
    GM_setValue(this.isHentai ? "currentRxServiceId" : "currentServiceId", id);
    this.redrawButton();
  });
  a.addEventListener('mousedown', (ev) => {
    if (ev.which == 2 || ev.button == 4) {
      ev.preventDefault();
      window.open(this.createServiceUrl(service), '_blank');
      return;
    }
  });
  return a;
}

WatchOnlineMenu.prototype.redrawButton = function () {
  var service = this.services[GM_getValue(this.isHentai ? "currentRxServiceId" : "currentServiceId", 0)];
  this.$link.innerText = 'Смотреть на ' + service.name;
  this.$link.href = this.createServiceUrl(service);
  this.$bar.style.display = 'none';
}

WatchOnlineMenu.prototype.createServiceUrl = function (service) {
  //Поменять местами чтобы открывалась первая серия если крайняя еще не вышла
  //const epTotal = parseInt(this.$ph.dataset.episodes_aired);
  const epTotal = parseInt(this.$ph.dataset.total_episodes);
  const v = document.getElementsByClassName('current-episodes')[0];
  const epWatched = (v ? parseInt(v.innerText) : 0) || 0;
  const epNext = epWatched === epTotal ? 1 : (epWatched + 1);
  const animeName = document.querySelector("#animes_show > section > div > header > h1").innerText.split(" / ");
  const isEnglish = GM_getValue("searchLang", 'ru') == 'en';

  const data = {
    id: location.pathname.replace(/^\/animes\/[a-z]*(\d+)-.*$/, "$1"),
    link: location.href,
    nextEpisode: epNext,
    englishName: animeName[1],
    russianName: animeName[0],
    localezedName: animeName[+isEnglish],
    localizedEpisode: isEnglish ? 'episode' : 'серия'
  };

  return location.protocol + "//" + service.url.replace(/\{([a-zA-Z_][a-zA-Z0-9_]*)\}/g, (match, name) => encodeURIComponent(data[name]));
}

function checkUpdates() {
  const servicesCache = GM_getValue("servicesCache", null);
  if (servicesCache && servicesCache.date > new Date()) return Promise.resolve(servicesCache.services);

  GM_log("[WatchOnlineMenu] Updating services list...");
  return new Promise(function (res, rej) {
        GM_xmlhttpRequest({
        "method": "GET",
        "url": "https://raw.githubusercontent.com/GlitchSkip/AltWatcher4/master/services.json",
        "responseType": "json",
        "fetch": true,
        "onerror": function (){
        if (servicesCache) res(servicesCache.services);
        else GM_log("[WatchOnlineMenu] Not starting WatchOnlineMenu due to network error.");
      },
      "onload": function (obj) {
        if (obj.status !== 200 || !obj.response) {
          if (servicesCache) res(servicesCache.services);
          else GM_log("[WatchOnlineMenu] Not starting WatchOnlineMenu due to network error.");
        }
        else {
          GM_setValue("servicesCache", {
            services: obj.response,
            date: +new Date() + 1000 * 60 * 60 * 24
          });
          res(obj.response);
        }
      }
    });
  });
}

document.head.appendChild(GM_addStyle(
  ".aw4-dark-button { background-color: #456; border: 1px solid #3e4d5d; color: #fff; display: block; text-align: center; cursor: pointer; padding: 4px 0; font-size: 15px; font-weight: 600; }" +
  ".aw4-link  {float: left; width: calc(100% - 32px); margin-bottom: 15px; }\n" +
  ".aw4-hider {width: 32px; float: right; }\n" +
  ".aw4-lang { width: 50%; float: left; }\n" +
  ".aw4-langs { margin-top: 5px; }\n" +
  ".aw4-selected { border: 5px solid #00c12a; padding: 4px 0; }\n"
));

if (location.host === 'plashiki.su') {
  unsafeWindow.corsAjax = function () {
    GM_log('[WatchOnlineMenu] PlaShiki xhr:', Array.prototype.slice.call(arguments));
    return GM_xmlhttpRequest.apply(this, arguments);
  }
  const us = unsafeWindow.USERSCRIPT = {
    name: GM_info.script.name,
    author: GM_info.script.author,
    version: "1.0.1",
    realVersion: GM_info.script.version
  }
  unsafeWindow.USERSCRIPT_VERSION = us.version + ' | Режим совместимости | ' + us.name + ' v' + us.realVersion;
  unsafeWindow.toggleGalo4ki = function (e) {};
  unsafeWindow.galo4kiEnabled = function () {
    return Promise.resolve(function (e) {
      return false;
    })
  };

}
else if (location.host.substr(location.host.length - 17) === 'shikimorilive.top') {
  unsafeWindow.SLiveVersion = '1.5';

}
else if (location.host === 'shikimori.one' || location.host === 'shikimori.org') {
  checkUpdates()
    .then(function (services) {
      GM_log("[WatchOnlineMenu] Starting...");
      let start = function () {
        if (document.body && document.body.classList.contains("p-animes") && !document.getElementsByClassName('aw4-link').length) {
          new WatchOnlineMenu(services);
        }
      }
      document.addEventListener('ready', start);
      document.addEventListener('page:load', start);
      document.addEventListener('turbolinks:load', start);
      start();
    })
}