NOTICE: By continued use of this site you understand and agree to the binding Terms of Service and Privacy Policy.
// ==UserScript==
// @name Shiki Elite Rating
// @author Chortowod (https://openuserjs.org/users/Chortowod)
// @description Рейтинг илитарности (больше старых тайтлов просмотрено = больше рейтинг)
// @namespace http://shikimori.me/
// @version 1.2.2
// @match *://shikimori.org/*
// @match *://shikimori.one/*
// @match *://shikimori.me/*
// @match *://shiki.one/*
// @match *://shikimori.io/*
// @icon https://www.google.com/s2/favicons?domain=shikimori.me
// @license MIT
// @updateURL https://openuserjs.org/meta/Chortowod/Shiki_Elite_Rating.meta.js
// @downloadURL https://openuserjs.org/install/Chortowod/Shiki_Elite_Rating.user.js
// @require https://gist.githubusercontent.com/Chortowod/814b010c68fc97e5f900df47bf79059c/raw/chtw_settings.js?v1
// @copyright 2026, Chortowod (https://openuserjs.org/users/Chortowod)
// ==/UserScript==
let settings = new ChtwSettings('chtwEliteRating', '<a target="_blank" href="https://openuserjs.org/scripts/Chortowod/Shiki_Elite_Rating">Илитарность</a>');
let debug;
function initSettings() {
settings.createOption('isLeft', 'Расположить слева', false);
settings.createOption('isDebug', 'Режим отладки', false);
settings.createOption('top', 'Отступ сверху (в %)', 15, 'number');
debug = settings.getOption('isDebug');
}
let style = `
.chtw-elite-rating-wrap:hover { width: 220px; }
.chtw-elite-rating-wrap {
display: flex;
color: initial;
overflow: hidden;
width: 50px;
height: 50px;
position: absolute;
padding: 5px;
${settings.getOption('isLeft') ? 'left' : 'right'}: 0;
${settings.getOption('isLeft') ? 'transform: scale(-1, 1);' : ''};
top: ${settings.getOption('top')}%;
border-radius: 10px 0px 0px 10px;
background: #000000ad;
transition: 0.5s;
align-items: center;
z-index: 9;
}
.chtw-elite-rating-info {
display: flex;
height: 100%;
width: 50px;
min-width: 45px;
font-size: 34px;
align-items: center;
justify-content: center;
color: #ffbd70;
}
.chtw-elite-rating-data {
min-width: 170px;
color: #dbfdff;
font-weight: bold;
${settings.getOption('isLeft') ? 'transform: scale(-1, 1);' : ''};
display: flex;
flex-direction: column;
align-items: center;
}
.chtwERTitle {
cursor: help;
}
`;
let skippedAnime = {'skipped_type': 'аниме', 'no_year': [], 'no_episodes': [], 'ongoing': []};
let skippedManga = {'skipped_type': 'манга', 'no_year': [], 'no_chapters': [], 'ongoing': []};
let siteURL = document.location.origin;
function log (message) { debug&&console.log(message) }
function getTitle(score) {
switch (true) {
case score < 0.5 : return 'Average Hype Fan';
case score < 1 : return 'Average Hype Enjoyer';
case score < 3 : return 'Улитка';
case score < 5 : return 'Илита-кохай';
case score < 10 : return 'Илитнячок';
case score < 15 : return 'Илита';
case score < 30 : return 'Илита-сенсей';
case score < 50 : return 'Батя';
case score < 100 : return 'Илитный сверхразум';
case score >= 100 : return 'Дед-хранитель';
default: return false;
}
}
function createDiv(type = 'title') {
if ($('#chtwEliteRating').length > 0) return;
let ratingWrap = document.createElement('div');
ratingWrap.id = 'chtwEliteRating';
ratingWrap.classList.add('chtw-elite-rating-wrap');
let ratingInfo = document.createElement('div');
ratingInfo.classList.add('chtw-elite-rating-info');
ratingInfo.innerHTML = '🛈';
ratingWrap.append(ratingInfo);
let ratingData = document.createElement('div');
ratingData.id = 'chtwEliteRatingData';
ratingData.classList.add('chtw-elite-rating-data');
if (type === 'profile') {
let ratingAnime = document.createElement('div');
ratingAnime.innerHTML = '<span id="chtwERanimeTitle" class="chtwERTitle">Аниме: </span><span id="chtwERanime"><span style="cursor: pointer;">посчитать</span></span>';
ratingData.append(ratingAnime);
let ratingManga = document.createElement('div');
ratingManga.innerHTML = '<span id="chtwERmangaTitle" class="chtwERTitle">Манга: </span><span id="chtwERmanga"><span style="cursor: pointer;">посчитать</span></span>';
ratingData.append(ratingManga);
}
if (type === 'title') {
ratingData.innerHTML = '<span style="cursor: pointer;">Посчитать</span></span>';
}
ratingWrap.append(ratingData);
document.body.append(ratingWrap);
if (type === 'profile') {
$('#chtwERanime').on('click', function () {
$(this).html('~загрузка');
calculateAll('anime', 0, 1);
});
$('#chtwERmanga').on('click', function () {
$(this).html('~загрузка');
calculateAll('manga', 0, 1);
});
}
if (type === 'title') {
$('#chtwEliteRatingData').on('click', function () {
$(this).html('~загрузка');
showTitleRating();
});
}
settings.addStyle(style);
}
function showTitleRating() {
let id = $('.b-db_entry .b-user_rate').data('target_id');
let type = location.href.includes("/animes/") ? 'animes' : 'mangas';
$.ajax({
url: siteURL+'/api/'+type+'/'+id,
success: function(data) {
if (data.length === 0) {
document.getElementById('chtwEliteRatingData').innerHTML = 'Нет данных.';
}
else {
if (type === 'animes') {
let titleEp = data.episodes || data.episodes_aired;
let titleData = data.aired_on;
let titleKind = data.kind;
let titleStatus = data.status;
if (!titleData) { document.getElementById('chtwEliteRatingData').innerHTML = 'Нет года.' }
else if (!titleEp) { document.getElementById('chtwEliteRatingData').innerHTML = 'Нет эпизодов.' }
else if (titleStatus === 'ongoing') { document.getElementById('chtwEliteRatingData').innerHTML = 'Онгоинг.' }
else { document.getElementById('chtwEliteRatingData').innerHTML = 'Стоимость: ' + parseFloat(calculateOne(titleData.substring(0, 4), 'anime', titleEp, titleKind).toFixed(4)); }
}
else {
let titleData = data.aired_on;
let titleChap = data.chapters;
let titleKind = data.kind;
if (!titleData) { document.getElementById('chtwEliteRatingData').innerHTML = 'Нет года.' }
else if (!titleChap) { document.getElementById('chtwEliteRatingData').innerHTML = 'Нет эпизодов.' }
else { document.getElementById('chtwEliteRatingData').innerHTML = 'Стоимость: ' + parseFloat(calculateOne(titleData.substring(0, 4), 'anime', titleChap, titleKind).toFixed(4)); }
}
}
},
error: function(XMLHttpRequest, textStatus, errorThrown) {
log('Произошла ошибка при загрузке. Обновите страницу или посмотрите причину ошибки в консоли разработчика.');
log(XMLHttpRequest);
log("Status: " + textStatus + " | Error: " + errorThrown);
},
complete: function() {
}
});
}
function calculateOne(year, type, episodes, kind = 'tv') {
let currentYear = new Date().getFullYear();
if (year >= currentYear) return 0;
if (year < 1970) year = 1970;
if (episodes > 120) episodes = 120;
let coef = (parseInt(year) > 1999) ? 2 : 3;
let result;
if (type === 'anime') {
if (kind === 'movie')
result = (Math.pow(currentYear - year, coef))/(Math.pow(currentYear - 2000, coef) * 200);
else
result = (Math.pow(currentYear - year, coef) * episodes)/(Math.pow(currentYear - 2000, coef) * 1200);
}
else {
if (kind === 'light_novel' || kind === 'novel')
result = (Math.pow(currentYear - year, coef) * episodes)/(Math.pow(currentYear - 2000, coef) * 2500);
else
result = (Math.pow(currentYear - year, coef) * episodes)/(Math.pow(currentYear - 2000, coef) * 5000);
}
log(episodes);
log(Math.pow(currentYear - year, coef) * episodes);
log(Math.pow(currentYear - 2000, coef) * 1200);
log(result)
return result;
}
function initialize() {
if ($('.p-profiles.p-profiles-show').length !== 0) {
createDiv('profile');
}
else if (!location.href.includes("/animes/") && !location.href.includes("/mangas/") && !location.href.includes("/ranobe/")) return false;
else if ($('.b-db_entry .b-user_rate').data('target_id')) {
createDiv('title');
}
}
function calculateAll(type, result, page) {
let id = $('.profile-head').data('user-id');
if (!id) return;
$.ajax({
url: siteURL+'/api/users/'+id+'/'+type+'_rates?limit=5000&status=completed&page='+page,
success: function(data) {
if (data === null) {
log((type === 'anime') ? skippedAnime : skippedManga);
document.getElementById('chtwER'+type+'Title').title = getTitle(result);
document.getElementById('chtwER'+type).innerHTML = result ? result.toFixed(3) : 'мало данных.';
}
else if (data.length === 0) {
document.getElementById('chtwER'+type).innerHTML = 'нет данных.';
}
else {
data.forEach(function (item) {
if (type === 'anime') {
let titleEp = item[type].episodes;
let titleData = item[type].aired_on;
let titleKind = item[type].kind;
let titleStatus = item[type].status;
let titleRewatches = (item.rewatches) ? item.rewatches + 1 : 1;
if (!titleData) { skippedAnime.no_year.push(siteURL+'/animes/' + item[type].id) }
else if (!titleEp) { skippedAnime.no_episodes.push(siteURL+'/animes/' + item[type].id) }
else if (titleStatus === 'ongoing') { skippedAnime.ongoing.push(siteURL+'/animes/' + item[type].id) }
else { result += calculateOne(titleData.substring(0, 4), type, titleEp, titleKind) * titleRewatches; }
}
else {
let titleData = item[type].aired_on;
let titleChap = item[type].chapters;
let titleKind = item[type].kind;
let titleStatus = item[type].status;
let titleRewatches = (item.rewatches) ? item.rewatches + 1 : 1;
if (!titleData) { skippedManga.no_year.push(siteURL+'/mangas/' + item[type].id) }
else if (!titleChap) { skippedManga.no_chapters.push(siteURL+'/mangas/' + item[type].id) }
else if (titleStatus === 'ongoing') { skippedManga.ongoing.push(siteURL+'/mangas/' + item[type].id) }
else { result += calculateOne(titleData.substring(0, 4), type, titleChap, titleKind) * (titleRewatches > 5 ? 5 : titleRewatches); }
}
});
setTimeout(() => { calculateAll(type, result, page+1); }, 250);
}
},
error: function(XMLHttpRequest, textStatus, errorThrown) {
if (XMLHttpRequest.responseJSON && XMLHttpRequest.responseJSON.message === 'You are not authorized to access this page.') {
log('Пользователь закрыл доступ к своей статистике.');
document.getElementById('chtwER'+type).innerHTML = 'нет доступа.';
}
else {
log('Произошла ошибка при загрузке. Обновите страницу или посмотрите причину ошибки в консоли разработчика.');
document.getElementById('chtwER'+type).innerHTML = 'ошибка.';
log(XMLHttpRequest);
log("Status: " + textStatus + " | Error: " + errorThrown);
}
},
complete: function() {
}
});
}
function ready(fn) {
document.addEventListener('page:load', fn);
document.addEventListener('turbolinks:load', fn);
if (document.attachEvent ? document.readyState === "complete" : document.readyState !== "loading") fn();
else document.addEventListener('DOMContentLoaded', fn);
}
ready(initSettings);
ready(initialize);