Greasy Fork is available in English.
Shows the total amount of time you will take to watch all entries on your anime list.
当前为
// ==UserScript==
// @name Anime list total time - MAL
// @namespace http://greasyfork.icu/en/users/670188-hacker09?sort=daily_installs
// @version 3
// @description Shows the total amount of time you will take to watch all entries on your anime list.
// @author hacker09
// @match https://myanimelist.net/profile/*
// @icon https://t3.gstatic.com/faviconV2?client=SOCIAL&type=FAVICON&fallback_opts=TYPE,SIZE,URL&url=http://myanimelist.net&size=64
// @run-at document-end
// @grant none
// ==/UserScript==
(async function() {
'use strict';
document.head.insertAdjacentHTML('beforeend', '<style>.di-ib.fl-r.lh10 {cursor: pointer;}</style>'); //Make each status total entry number look clickable
document.querySelectorAll(".di-ib.fl-r.lh10").forEach(async function(el, i) { //ForEach status total entry number
el.onclick = async function() //When the user clicks on the status total entry number
{ //Starts the onclick event listener
var stats; //Set a global variable
var EntryIds = []; //Create a new array
var TotalHrMins = ['0']; //Create a new array
var nextpagenum = 0; //Create a variable to hold the page number
var Counter = 0; //Create a variable to hold the Total Entries Number
var increaseby = 300; //Create a variable to Increase the list page number
alert(`This process will take about ${(Math.floor(el.innerText.match(/\d+,?\d+/g)[0].replace(',','') * 2 / 60))}:${el.innerText.match(/\d+,?\d+/g)[0].replace(',','') * 2 % 60} minutes to complete\n\nPlease avoid opening any MAL links during that time!`); //Let the user know how log it will take
switch (i) { //Detect the user choice
case 0: //If the user clicked on Watching
stats = 1; //Change the variable value
document.querySelector("h5,.pt16.pb12").style.backgroundColor = '#2db039'; //Change the bg color to match the selected status
break; //Stop executing the switch statement
case 1: //If the user clicked on Completed
stats = 2; //Change the variable value
document.querySelector("h5,.pt16.pb12").style.backgroundColor = '#26448f'; //Change the bg color to match the selected status
break; //Stop executing the switch statement
case 2: //If the user clicked on On-Hold
stats = 3; //Change the variable value
document.querySelector("h5,.pt16.pb12").style.backgroundColor = '#f9d457'; //Change the bg color to match the selected status
break; //Stop executing the switch statement
case 3: //If the user clicked on Dropped
stats = 4; //Change the variable value
document.querySelector("h5,.pt16.pb12").style.backgroundColor = '#a12f31'; //Change the bg color to match the selected status
break; //Stop executing the switch statement
case 4: //If the user clicked on Plan to Watch
stats = 6; //Change the variable value
document.querySelector("h5,.pt16.pb12").style.backgroundColor = '#c3c3c3'; //Change the bg color to match the selected status
break; //Stop executing the switch statement
} //Finishes the switch statement
while (true) { //Starts the while condition to get the Total Number of Entries on the user list
const entries = await (await fetch(`https://myanimelist.net/animelist/${location.href.split('/')[4]}/load.json?status=${stats}&offset=${nextpagenum}`)).json(); //Fetches the user list
if (entries.errors !== undefined) //If the user has a private list
{ //Starts the if condition
document.querySelector("h5,.pt16.pb12").style.backgroundColor = '#fff'; //Change the bg color to match the selected status
alert(location.href.split('/')[4] + ' has a private anime list!') //Show a message to the user
return; //Stop the script
} //Finishes the if condition
nextpagenum += increaseby; //Increase the next page number
var TotalEntries = entries.length; //Save the Total Entries Number
Counter += TotalEntries; //Sum the Total Entries Number to TotalEntries
entries.forEach(el => EntryIds.push(el.anime_id)); //Save all entry ids
if (TotalEntries !== 300) //If the next page has less than 300 entries stop looping the while condition
{ //Starts the if condition
console.log('Finished Getting the Total Entries Number!'); //Shows a console message
EntryIds.forEach(async function(id, index) { //For each entry id
setTimeout(async function() { //Starts the settimeout
const response = await (await fetch("https://myanimelist.net/includes/ajax-no-auth.inc.php?t=6", { //Fetch
"headers": {
"content-type": "application/x-www-form-urlencoded; charset=UTF-8"
},
"body": `color=1&id=${id}&memId=${document.querySelector("input[name*=profileMemId]") !== null ? document.querySelector("input[name*=profileMemId]").value : document.querySelector(".mr0").href.match(/\d+/g)[0]}&type=anime&csrf_token=${document.querySelector("meta[name=csrf_token]").content}`,
"method": "POST",
"mode": "cors"
})).text(); //Get each entry individual episode duration times
const newDocument = new DOMParser().parseFromString(response, 'text/html'); //Parses the fetch response
const json = await (await fetch(`https://api.jikan.moe/v4/anime/${id}/full`)).json(); //Fetch to get the eps
if (newDocument.querySelector('td > div > a:nth-child(2) > small,td > div > strong > a > small') === null) //If an error occurs
{ //Starts the if condition
throw new Error('Failed getting total entry times for https://myanimelist.net/anime/' + id); //Shows an error message
} //Finishes the if condition
var TotalEpisodes = json.data.episodes; //Get total entry amount of eps
var TotalMins = TotalEpisodes * newDocument.querySelector('td > div > a:nth-child(2) > small,td > div > strong > a > small').childNodes[0].data.match(/\d+/g)[1]; //Multiply Extracted Eps By total entry Mins
var TotalHrs = TotalEpisodes * newDocument.querySelector('td > div > a:nth-child(2) > small,td > div > strong > a > small').childNodes[0].data.match(/\d+/g)[0] * 60; //Multiply Eps By total entry Hrs
TotalHrMins.push(TotalHrs, TotalMins); //Add Hrs And Mins To The Array
var TotalMinsResult = TotalHrMins.filter(Boolean).map(i => Number(i)).reduce((a, b) => a + b); //Sum Hrs in Mins + Total Mins
var days = Math.floor(TotalMinsResult / 1440); //Get total days amount
var hours = Math.floor((TotalMinsResult % 1440) / 60); //Get total hours amount
var minutes = (TotalMinsResult % 1440) % 60; //Get total minutes amount
document.querySelector("h5,.pt16.pb12").innerText = 'Anime Stats (' + days + ' Days ' + hours + ' Hours ' + minutes + ' Minutes)'; //Show the total time
if (EntryIds.length - 1 === index) //If it's the last loop
{ //Starts the if condition
document.querySelector("h5,.pt16.pb12").innerText += ' ✔️'; //Adds a checkmark after the total time
} //Finishes the if condition
}, index * 2000); //Finishes the settimeout function
}); //Finishes the for each condition
return; //Stop the script if fetched page has less than 300 entries and run the EntryIds.forEach loop
} //Finishes the if condition
} //Finishes the while condition
}; //Finishes the onclick event listener
}); //Finishes the foreach loop
})();