Greasy Fork

BetterFollowingList

Tweaks to following lists on media pages

目前为 2018-12-17 提交的版本。查看 最新版本

// ==UserScript==
// @name BetterFollowingList
// @namespace Morimasa
// @author Morimasa
// @description Tweaks to following lists on media pages
// @match https://anilist.co/*
// @grant none
// @version 0.02
// ==/UserScript==
let apiCalls = 0;
const stats = {
  element: null,
  count:0, 
}

const scoreColors = e => {
  let el = e.querySelector('span') || e.querySelector('svg');
  let light = document.body.classList[0]==='site-theme-dark'?45:38;
  if (el===null) return;
  else if (el.nodeName==='svg'){
    // smiley
    const scoremap = {'smile': 90, 'meh': 60, 'frown': 30}
    el.childNodes[0].setAttribute('fill', `hsl(${scoremap[el.dataset.icon]}, 100%, ${light}%)`)
  }
  else if (el.nodeName==='SPAN'){
    let score = el.innerText.split('/');
    score = score.length==1?parseInt(score)*20-10:parseInt(score[1])==10?parseFloat(score[0])*10:parseInt(score[0]); // convert stars, 10 point and 10 point decimal to 100 point
    el.style.color = `hsl(${score}, 100%, ${light}%)`;
    if (score>100) console.log('why score is bigger than 100?', el);
  }
}

const handler = (data, target, idMap) => {
  if (target===undefined) return;
  data.forEach(e=>{
    target[idMap[e.user.id]].style.gridTemplateColumns='30px 1.3fr .7fr 1fr .5fr';
    const progress = document.createElement('DIV');
    progress.innerText = `${e.progress}/${e.media.chapters||e.media.episodes||'?'}`;
    target[idMap[e.user.id]].insertBefore(progress, target[idMap[e.user.id]].children[2])
    
  })
}

const getAPI = (target, elMap) => {
    let user = [];
    for (let u in elMap) user.push(u);
    if (user.length===0) return;
    console.log(`BetterFollowingList: quering ${user.length} users | ${++apiCalls} api calls since reload`)
    const mediaID = window.location.pathname.split("/")[2];
    const query = 'query($u:[Int],$media:Int){Page {mediaList(userId_in:$u,mediaId:$media){mediaId progress user{id name}media{chapters episodes}}}}'
    const vars = {u: user, media: mediaID};
	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 => handler(res.data.Page.mediaList, target, elMap))
	.catch(error => console.error(`Error: ${error}`));
}

const createStat = (text, number) => {
  let el = document.createElement('span');
  el.innerText = text;
  el.appendChild(document.createElement('span'))
  el.children[0].innerText = number
  return el
}

const MakeStats = () => {
  if(stats.element) return; // element already injected
  let main = document.createElement('h2');
  let count = createStat('Users: ', stats.count);
  main.append(count);
  
  const parent = document.querySelector('.following');
  parent.prepend(main);
  stats.element = main;
}

let observer = new MutationObserver(() => {
  if (window.location.pathname.match(/\/(anime|manga)\/\d+\/.+\/social/)){
    MakeStats();
    const follows = document.querySelectorAll('.follow');
    let idmap = {};
    follows.forEach((e, i)=>{
    if (e.childNodes.length==7 && !e.dataset.changed){
      const avatarURL = e.querySelector('.avatar').dataset.src;
      if (!avatarURL) return
      const id = avatarURL.split('/').pop().match(/\d+/g)[0];
      idmap[id] = i;
      // score collors
      scoreColors(e);
      // add count
      ++stats.count;
      // set state
      e.dataset.changed=true;
      }
    })
   if (Object.keys(idmap).length>0){
     getAPI(follows, idmap);
     
     let statsElements = stats.element.querySelectorAll('span>span');
     statsElements[0].innerText = stats.count
   }
  }
  else {
    stats.element=null;
    stats.count=0;
  }
});
observer.observe(document.getElementById('app'), {childList: true, subtree: true});