Advertisement
Not a member of Pastebin yet?
Sign Up,
it unlocks many cool features!
- // ==UserScript==
- // @name MAL API Anime list total time - MAL
- // @namespace https://greasyfork.org/en/users/670188-hacker09?sort=daily_installs
- // @version 2
- // @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
- // @grant GM.xmlHttpRequest
- // @run-at document-end
- // ==/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 = 1000; //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 = 'watching'; //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 = 'completed'; //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 = 'on_hold'; //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 = 'dropped'; //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 = 'plan_to_watch'; //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
- var entries = await new Promise((resolve, reject) => GM.xmlHttpRequest({
- responseType: 'json',
- url: `https://api.myanimelist.net/v2/users/${location.href.split('/')[4]}/animelist?fields=list_status&status=${stats}&limit=${nextpagenum}`,
- headers: {
- "x-mal-client-id": "8ef0267fd86a187d479e6fcd7e1bb42a"
- },
- onload: r => resolve(r.response.data),
- onerror: function () {
- throw new Error(`Failed getting ${location.href.split('/')[4]} user list`); //Shows an error message
- }
- }));
- //console.log(response.response)
- /* if (entries.error !== 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 */
- //return response.response.data;
- //console.log( response.response.data.forEach(entry => console.log(entry.node.id)) );
- console.log(entries)
- 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 !== 1000) //If the next page has less than 1000 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 1000 entries and run the EntryIds.forEach loop
- } //Finishes the if condition
- } //Finishes the while condition
- }; //Finishes the onclick event listener
- }); //Finishes the foreach loop
- })();
Advertisement
Add Comment
Please, Sign In to add comment
Advertisement