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);