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