NOTICE: By continued use of this site you understand and agree to the binding Terms of Service and Privacy Policy.
// ==UserScript==
// @name Shikiposter
// @namespace https://shikimori.me/
// @downloadURL https://openuserjs.org/install/flxemt/Shikiposter.user.js
// @updateURL https://openuserjs.org/meta/flxemt/Shikiposter.meta.js
// @version 1.0.6
// @description Better posters quality for anime and manga
// @author FLX
// @match https://shikimori.me/*
// @match https://shikimori.one/*
// @license MIT
// @grant GM_setValue
// @grant GM_getValue
// @grant GM_deleteValue
// @grant GM_listValues
// @license MIT
// ==/UserScript==
const debug = false;
const enableCache = true; // if use false, posters cache also will be cleared when you refresh the page
function log(message) {
if (debug) console.log(message);
}
function removeDefaultImage(el) {
el.previousElementSibling.remove();
}
function replacePoster() {
if (!enableCache) clearCachedPosters();
else log(GM_listValues());
if (location.pathname == '/' || location.pathname.includes('/collections/') || location.pathname.includes('/contests/') || location.pathname.includes('/achievements/franchise/') || location.pathname.includes('/animes') || location.pathname.includes('/mangas')) {
document.querySelectorAll((document.querySelector('.c-poster img') != null) ? '.cc-similar article.b-catalog_entry' : 'article.b-catalog_entry').forEach((item, index) => {
let posterLink = item.querySelector('a');
if(!posterLink.href.includes('/animes/') && !posterLink.href.includes('/mangas/')) return;
let posterElement = item.querySelector('img');
removeDefaultImage(posterElement);
if (GM_getValue(posterLink.href.slice(21)) != undefined && enableCache) {
posterElement.src = GM_getValue(posterLink.href.slice(21));
log('Loaded cached poster');
return;
}
else {
if ((location.pathname.includes('/collections/') || location.pathname.includes('/studio/') || location.pathname.includes('/achievements/franchise/') || location.pathname.includes('/animes/page/') || location.pathname.includes('/mangas/page/') ||
location.pathname.endsWith('/animes') || location.pathname.endsWith('/mangas')) && document.querySelectorAll('article.b-catalog_entry').length > 15) return;
api.loadAniListPoster(posterElement, posterLink.href.slice(21), item.getAttribute('id'), posterLink.href.match(/anime|manga/)[0].toUpperCase());
}
});
}
if(location.pathname.includes('/animes/') || location.pathname.includes('/mangas/')) {
if (document.querySelector('.c-poster img') != null) { // Main poster
const posterElement = document.querySelector('.c-poster img');
removeDefaultImage(posterElement);
posterElement.style.width = '225px';
log(`Found: ${location.pathname.match(/\d{1,}/)[0]}`);
if (GM_getValue(location.pathname) != undefined && enableCache) {
posterElement.src = GM_getValue(location.pathname);
log('Loaded cached poster');
addRefreshBtn();
}
else {
const defaultPoster = posterElement.src;
api.loadAniListPoster(posterElement, location.pathname, location.pathname.match(/\d{1,}/)[0], location.pathname.match(/anime|manga/)[0].toUpperCase());
}
}
}
}
const api = {
async loadAniListPoster(el, cachePath, malId, type) {
const { src: defaultPoster } = el;
el.src = 'https://i.gifer.com/HHAm.gif';
const query = `query ($id: Int, $type: MediaType) {
Media (idMal: $id, type: $type) {
id
idMal
title {
romaji
}
coverImage {
extraLarge
}
}
}`;
const variables = {
id: malId,
type
};
const baseURL = 'https://graphql.anilist.co';
const options = {
method: 'POST',
headers: {
'Content-Type': 'application/json',
'Accept': 'application/json',
},
body: JSON.stringify({
query,
variables
})
};
fetch(baseURL, options).then(res => {
return res.json().then(json => {
return res.ok ? json : Promise.reject(json);
});
})
.then(data => {
log(data.data.Media.title.romaji);
el.src = data.data.Media.coverImage.extraLarge;
if (enableCache) {
GM_setValue(cachePath, el.src);
log('Added to cache');
addRefreshBtn();
}
})
.catch(error => {
log(`Can't load poster from AniList. ${error}. Returned default`);
el.src = defaultPoster;
return null;
});
}
};
function addRefreshBtn() {
if(document.querySelector('.b-subposter-actions .refresh') == null) {
let customCSS = document.createElement('style');
document.head.appendChild(customCSS);
const iconText = document.querySelector('#custom_css').innerHTML.includes('shiki-theme.web.app') ? 'refresh' : '\\e825';
customCSS.appendChild(document.createTextNode(`.refresh:before { content: '${iconText}'; }`));
let refreshBtn = document.createElement('a');
document.querySelector('.b-subposter-actions').appendChild(refreshBtn);
refreshBtn.classList = 'b-subposter-action refresh b-tooltipped';
refreshBtn.href = 'javascript:void(0)';
refreshBtn.setAttribute('title', (document.querySelector('body').getAttribute('data-locale') == 'ru') ? 'Обновить постер' : 'Reload poster');
refreshBtn.onclick = () => {
GM_deleteValue(location.pathname);
window.location.reload();
}
}
}
function clearCachedPosters() {
for (let i of GM_listValues()) GM_deleteValue(i);
}
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(() => {
let $ = unsafeWindow.jQuery;
$(".l-page").on("postloader:success", () => replacePoster());
replacePoster();
});