NOTICE: By continued use of this site you understand and agree to the binding Terms of Service and Privacy Policy.
// ==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);