// ==UserScript== // @name Anisongs // @namespace Morimasa // @author Morimasa // @description Adds Anisongs to anime entries on AniList // @match https://anilist.co/* // @version 1.00 // @grant GM_xmlhttpRequest // @downloadURL none // ==/UserScript== const options = { cacheName: 'anison' } let last = {id:0} let target; const insert = (list, parent) => { if (list===undefined || list.length===0){ console.info("OP/ED is empty"); return; } list.forEach((title, i)=>{ let node = document.createElement('p'); node.innerText = `${i+1}. ${title}`; node.setAttribute('data-v-4e418c9e',''); node.classList = "tag"; parent.appendChild(node); }) } const createTargetDiv = (text, target, pos) => { let el = document.createElement('div'); el.appendChild(document.createElement('h2')); el.children[0].innerText = text; target.insertBefore(el, target.children[pos]); return el; } const placeData = data => { let op = createTargetDiv('Openings', target, 2) let ed = createTargetDiv('Endings', target, 3) insert(data.opening_themes, op); insert(data.ending_themes, ed); } const handleData = data => { let resp = JSON.parse(data.responseText); placeData(resp) addCache(last.id, {opening_themes: resp.opening_themes, ending_themes: resp.ending_themes, time: +new Date()}) } const getMal = id => { if (id===null) return console.info("No MAL id in API") GM_xmlhttpRequest({ method: "GET", url: `https://api.jikan.moe/v3/anime/${id}/`, headers: { "Accept": "application/json" }, onload: handleData }) } const getMalId = () => { const query = `query($id:Int){Media(id:$id){idMal}}` let vars = {id: parseInt(window.location.pathname.split("/")[2])}; const options = { method: 'POST', body: JSON.stringify({query: query, variables: vars}), headers: new Headers({ 'Content-Type': 'application/json' }) }; return fetch('https://graphql.anilist.co/', options) .then(res => res.json()) .then(res => getMal(res.data.Media.idMal)) .catch(error => console.error(`Error: ${error}`)); } const addCache = (id, data) => { //localStorage.setItem(id, JSON.stringify(object)); let cache = JSON.parse(localStorage.getItem(options.cacheName)) || {}; cache[id] = data localStorage.setItem(options.cacheName, JSON.stringify(cache)); } const getCache = id => { //return JSON.parse(localStorage.getItem(id)) let cache = localStorage.getItem(options.cacheName); if (cache==null) return {time:0} else return JSON.parse(cache)[id] || {time:0}; } var observer = new MutationObserver(() => { if (window.location.href.includes('/anime/', 18)) { let currentid = window.location.href.split("/")[4]; let location = window.location.pathname.split("/").pop(); if (location!=='') last.id=0; target = document.querySelectorAll('.grid-section-wrap')[1]; if(last.id!==currentid && location=='' && target!==undefined){ last.id = currentid; let cache = getCache(currentid); let daypassed = (cache.time + 86400000)<+new Date(); if (daypassed){ getMalId(); console.info("OP/ED loaded from API"); } else{ placeData(cache); console.info("OP/ED loaded from Cache"); } } } }); observer.observe(document.getElementById('app'), {childList: true, subtree: true});