JD99 / shiki

// ==UserScript==
// @name         shiki
// @namespace    https://randart.ru
// @version      0.1
// @description  [shikimori.org] Добавляет метку о пропущеных эпизодах ###
// @author       JD99
// @match https://shikimori.one/animes/*
// @require      https://code.jquery.com/jquery-3.3.1.slim.min.js
// @grant        none
// @license      MIT
// @copyright    2023, JD99
// ==/UserScript==

var $ = jQuery.noConflict(true);
const APPLICATION_NAME = "RandArt.ru"
const ACCESS_TOKEN = "yQcS7ND8MW7eonqPM28oWxf5b2JCJWNiIEXw9dyDnXw"
const CNT_ANIME_ACTUAL = 3;
const TIMEOUT_API = 500;
var DATA_RATE = [];
const $cont = $("body");

async function start() {
  $('<style type="text/css">.pora-smotret::before { background: green!important;} .action-visible {opacity: 0.25!important;} .cnt-action {position: absolute;top: 0px;color: white;left: 5px;font-size: 21px;font-weight: bold;-webkit-text-stroke: 0.7px black;}</style>').prependTo("body");
  //$("body").append('<button id="run-action" type="button" style="position:absolute;top 50px;left:50px;top: 50px;z-index: 10000000;background: red;">RUN</button>');
  $("#run-action").on('click', function () {
    fast_version()
    //first_version()
  });
  fast_version()

}

function fast_version() {
  whoami().then(res => {
    anime_rates(res.id, {
      status: "watching",
      limit: 1000
    }).then(res => {
      DATA_RATE = res;
      action_elem()
    });
  });
  $(window).scroll(function () {
    let time = $cont.data("timer-id");
    if (time) clearTimeout(time);
    var new_time = setTimeout(function () {
      action_elem()
    }, 1000);
    $cont.data("timer-id", new_time);
  });
}

function action_elem() {
  $("article.watching:not(.scr-checked)").each(async function (i) {
    let el = $(this)
    let ident = el.attr("id")
    let anim = DATA_RATE.find(x => x.anime.id == ident)
    if (!anim) return;
    let eps_target = anim.anime.episodes_aired
    if (anim.anime.status == "released") eps_target = anim.anime.episodes;
    let eps_rate = anim.episodes;
    el.addClass("scr-checked")
    let cnt = eps_target - eps_rate
    el.append(`<div class="cnt-action">${cnt}</div>`)
    if (cnt <= CNT_ANIME_ACTUAL) {
      if (anim.anime.status == "released") {
        el.removeClass("action-visible")
      }
      else {
        el.addClass("action-visible")
      }
    }
    else {
      el.removeClass("action-visible")
    }
  })
}

function slow_version() {
  $("article.watching:not(.scr-checked)").each(async function (i) {
    let el = $(this)
    let ident = el.attr("id")
    setTimeout(() => {
      animes_id(ident).then(res => {
        let eps_target = res.episodes_aired;
        let eps_rate = res.user_rate.episodes;
        if (eps_target - eps_rate >= CNT_ANIME_ACTUAL) {
          el.find(".image-decor").addClass("pora-smotret")
          el.addClass("scr-checked")
        }
      });
    }, i * TIMEOUT_API);
  })
}

async function anime_rates(id, param) {
  let dt = ""
  if (param) dt = "?" + new URLSearchParams(param)
  return await api(`/api/users/${id}/anime_rates` + dt)
}
async function whoami() {
  return await api(`/api/users/whoami`)
}
async function user_rates(param) {
  let dt = ""
  if (param) dt = "?" + new URLSearchParams(param)
  return await api(`/api/v2/user_rates` + dt)
}
async function animes_id(id, param) {
  let dt = ""
  if (param) dt = "?" + new URLSearchParams(param)
  return await api(`/api/animes/${id}` + dt)
}
async function api(url) {
  var obj = {
    method: 'GET',
    headers: {
      'Accept': 'application/json',
      'Content-Type': 'application/json',
      'User-Agent': APPLICATION_NAME,
      'Authorization': `Bearer ${ACCESS_TOKEN}`
    }
  }
  const response = await fetch(url, obj);
  return response.json();
}

$(document).ready(start);
$(document).on('page:load', start);
$(document).on('turbolinks:load', start);