Generate a List With The Animes/Mangas Titles that were Re-Watched/Re-Read

This is a tool to easily and quickly generate a list with the titles of what animes/mangas you have ReWatched/ReRead and how many times.

目前為 2020-08-21 提交的版本,檢視 最新版本

// ==UserScript==
// @name         Generate a List With The Animes/Mangas Titles that were Re-Watched/Re-Read
// @namespace    MAL Automatic Anime/Manga List Generator
// @version      0.4
// @description  This is a tool to easily and quickly generate a list with the titles of what animes/mangas you have ReWatched/ReRead and how many times.
// @author       hacker09 & (Reddit user SapphireFeast)
// @match        https://myanimelist.net/animelist/*
// @match        https://myanimelist.net/mangalist/*
// @run-at       document-end
// @grant        none
// ==/UserScript==
(function() {
    'use strict';
var $ = window.jQuery; //Defines That The Symbol $ Is A jQuery
var rewatchedlistbtn = document.createElement("a"); // Creates an a element
var username = window.location.pathname.split('/')[2]; //Get the username on the url to use latter
var TotalCompletedAnimes, TotalCompletedMangas, TotalReWatchedAnimes, TotalReReadMangas, type, interval; //Make these variables global

async function getVariables() //Creates a function to get the needed Variables
{ //Starts the function
    const response = await fetch('https://myanimelist.net/profile/'+username); //Fetch
    const html = await response.text(); //Gets the fetch response
    const newDocument = new DOMParser().parseFromString(html, 'text/html'); //Parses the fetch response
    TotalCompletedAnimes = newDocument.querySelectorAll(".di-ib.fl-r.lh10")[1].textContent; //Creates a variable to hold the actual TotalCompletedAnimes value
    TotalCompletedMangas = newDocument.querySelectorAll(".di-ib.fl-r.lh10")[6].textContent; //Creates a variable to hold the actual TotalCompletedMangas value
    TotalReWatchedAnimes = newDocument.querySelectorAll("li.clearfix.mb12 span")[8].textContent; //Creates a variable to hold the actual TotalReWatchedAnimes value
    TotalReReadMangas = newDocument.querySelectorAll("li.clearfix.mb12 span")[19].textContent; //Creates a variable to hold the actual TotalReReadMangas value
} //Finishes the function
getVariables(); //Call the function getVariables

rewatchedlistbtn.setAttribute("id", "rewatchedlistbtn"); //Adds the id rewatchedlistbtn to the a element
rewatchedlistbtn.setAttribute("style", "cursor: pointer;"); //Set the css for the button
if (window.location.pathname.split('/')[1] === 'animelist') //Check If The URL Is https://myanimelist.net/animelist/  ,And If Yes Make A Button Called "Generate My ReWatched List"
{ //Starts the if condtion
  rewatchedlistbtn.innerHTML = "Generate ReWatched List"; //Define the text that should appear on the "Button"
} //Finishes the if condition
if (window.location.pathname.split('/')[1] === 'mangalist') //Check If The URL Is https://myanimelist.net/animelist/  ,And If Yes Make A Button Called "Generate My ReRead List"
{ //Starts the if condtion
  rewatchedlistbtn.innerHTML = "Generate ReRead List"; // The text that should appear on the "Button"
} //Finishes the if condition
if (document.querySelector("#advanced-options-button") === null) //Checks if the Filters button on the modern list style exists,if not then the user is using an old classic list style
{ //Starts the if condtion
  document.querySelector("a.table_headerLink").parentElement.appendChild(rewatchedlistbtn); //Defines that the 'Generate ReWatched/ReRead List' button should appear close to the 'Anime Title' or 'Manga Title' text on the old classic style list.
  rewatchedlistbtn.onclick = function() {
    loadingscreen(); //Start the loading screen function
    setTimeout(scrape, 500); //Start the scrape function
  }; //Shows a message in the console for dev purposes, and run the scrape function.Classic list styles doesn't need to be scrolled down.
} //Finishes the if condition
else //If the Filters button on the modern list style exists, then the user is using the modern list style
{ //Starts the else condtion
  document.querySelector("#advanced-options-button").parentElement.appendChild(rewatchedlistbtn); //Defines that the 'Generate ReWatched/ReRead List' button should appear close to the Filter button on the modern style list
  rewatchedlistbtn.onclick = function() // Detects the mouse click on the 'Generate ReWatched/ReRead List' button
  { //Starts the onclick function
    loadingscreen(); //Start the loading screen function
    setTimeout(RunInterval, 500); //Start the function RunInterval
  }; //Finishes the onclick function
} //Finishes the else condition

function loadingscreen() //Creates a loading screen function that also checks if the user is on the completed list or not
{ //Starts the loadingscreen function
  const loadingScreen = document.createElement("div"); //Creates and div element
  document.body.appendChild(loadingScreen); //Add the loading screen to the html body
  loadingScreen.setAttribute("id", "loadingScreen");
  loadingScreen.setAttribute("style", "position: fixed;width: 100%;height: 100%;background-color: black;top: 0;z-index: 1000;background-image: url(https://pa1.narvii.com/6258/61f5cd5c652efec508ff3c6e10798d26ccef6366_hq.gif);background-repeat: no-repeat;background-position: center;");

  // Before running, check if the completed section is opened or not
  if (window.location.href.split('/')[4] !== '' + username + '?status=2') //Checks if the user is on https://myanimelist.net/animelist/USERNAMEHERE?status=2 opened or not (the status 2 means that the user is on an completed list)
  { //Starts the if condition
    alert("Execute this on the 'Completed' page! \nRedirecting. \nTry again after the page loads."); //Show an error alert message to the user, if the user is not on an completed list
    window.location.replace(window.location.href.split('?')[0] + "?status=2"); //Redirects the user to the completed section of the list that the user was in
    throw new Error("Redirecting"); //Show an error alert message on the dev console of the user
  } //Finishes the if condition
   else if (window.location.pathname.split('/')[1] === 'animelist' && TotalReWatchedAnimes !== '0') //If the user is already on the completed page and if the user is on an animelist, and if the TotalReWatchedAnimes isn't = 0
      { //Starts the if condition
        type = "anime"; //If the user is on an animelist, then the type to be scrapped will be animes
      } //Finishes the if condition
      else if (window.location.pathname.split('/')[1] === 'mangalist' && TotalReReadMangas !== '0') //If the user is already on the completed page and if the user is on an mangalist, and if the TotalReReadMangas isn't = 0
      { //Starts the else condition
        type = "manga"; //The user is on an manga list, then the type to be scrapped will be mangas
      } //Finishes the else condition
      else //Detects if the user is not on an animelist/mangalist and if the list is = 0 total number ReWatched/ReRead
      { //Starts the else condition
        location.reload(); //Reload the page
        window.location.pathname.split('/')[1] === 'animelist' ? alert('The user '+username+' doesn\'t have any ReWatched Animes!\nThe page will be reloaded!') : alert('The user '+username+' doesn\'t have any ReRead Mangas!\nThe page will be reloaded!'); //Display a message
      } //Finishes the else condition
} //Finishes the loadingscreen function

function RunInterval() //Creates a function to run the interval
{ //Starts the function RunInterval
  console.log('Scrolling Down. Please Wait!'); //Shows a message in the console for dev purposes
  interval = setInterval(godown, 0); //Creates a variable named interval that will run the function godown every 0 secs
} //Finishes the function RunInterval

function godown() //Function that automatically "Press the keyboard key End"
{ //Starts the function godown
  if ((document.querySelectorAll("td.data.number").length !== parseFloat(TotalCompletedMangas.replace(/,/g,""))) && (document.querySelectorAll("td.data.number").length !== parseFloat(TotalCompletedAnimes.replace(/,/g,"")))) //If condition that detect if the whole list is loaded or not
  { //Starts the if condition
    window.scrollTo(0, document.body.scrollHeight); //Scrolls the website till the whole list is loaded
  } //Finishes the if condition
  else //When the whole list is loaded
  { //Starts the else condition
    console.log('Full List Loaded! Stopping Scrolling Down Now!'); //Shows a message in the console for dev purposes
    clearInterval(interval); //Breaks the timer that scrolls the page down every 0 secs
    scrape(); //Run the Scrapping Function
    return; //Get out of this function
  } //Finishes the else condition
} //Finishes the function godown

function scrape() //Function that will scrape the page for rewatched/reread values
{ //Starts the function scrape
  console.log('Starting To Scrape...Please Wait!'); //Shows a message in the console for dev purposes
  var titles = []; //Creates a blank node variable to use latter
  var rewatches = []; //Creates a blank node variable to use latter
  var resultArray = []; //Creates a blank node variable to use latter
  var moreLinks = document.querySelectorAll('a'); //Defines a variable named 'moreLinks' that will be used to click on all the more buttons on the completed page
  var titles_old = document.querySelectorAll('div table tbody tr a.animetitle span'); //Select only the anime title on the old style list
  var titles_new = document.querySelectorAll('tbody.list-item tr.list-table-data td.data.title a.link.sort'); //Select only the anime title on the Modern default style list
  var old_list = false; //Variable that can be changed latter to the value 'true' if the user used the script on an old classic style list.The value 'false' will be kept if the user used the script on the new modern list style.
  var result = 'data:text/html;charset=utf-8,<style>html,body{margin: 0;padding: 0;}</style><div style="max-width:650px;font-size: 18px;margin:0px auto;">'; //The HTML and CSS that will be added to the downloaded file when the script is done

  if (titles_old.length > titles_new.length) //Checks if the user list style is the old classic style or the new modern style
  { //Starts the if condition
    titles = titles_old; //If the user used the script on an old classic list style, the blank node created later named 'titles' will be changed to an variable named 'titles_old' that will posses the blank nodes value (In dev words  var titles_old = [];  )
    old_list = true; ////Variable old_list will be changed to the value 'true' if the user used the script on an old classic style list
  } //Finishes the if condition
  else //If the user used the script on a new modern list style
  { //Starts the else condition
    for (var i = 0; i < titles_new.length; i++) //This for condition is responsible for getting all the anime titles
    { //Starts the for condition
      titles[i] = titles_new[i].text; //Add all titles to an array
    } //Finishes the for condition
  } //Finishes the else condition

  if (type == "anime") result += "<h1> " + username + " ReWatched Anime List</h1>"; //If the type is anime then add 'Rewatched anime' to The HTML and CSS that will be added to the downloaded file when the script is done
  if (type == "anime") result += "<h3><em>List of Animes that " + username + " has watched and ReWatched:</em></h3>"; //If the type is anime then add 'How many times username has watched and ReWatched' to The HTML and CSS that will be added to the  downloaded file when the script is done
  if (type == "manga") result += "<h1> " + username + " ReRead Manga List</h1>"; //If the type is manga then add 'Rewatched manga' to The HTML and CSS that will be added to the downloaded file when the script is done
  if (type == "manga") result += "<h3><em>List of Mangas that " + username + " has read and ReRead:</em></h3>"; //If the type is manga then add ''How many times username has read and ReRead' to The HTML and CSS that will be added to the downloaded file when the script is done

  if (old_list) //If the script is working on an old classic list style
  { //Starts the if condition
    // The 12 lines below Fetches the rewatch count information bypassing the 'More' link on old classic list styles
    $("div.hide").each(function(index, value) {
      var series_id = $(value).attr('id').split('more')[1];
      $.post("/includes/ajax-no-auth.inc.php?t=6", {
        color: 1,
        id: series_id,
        memId: $('#listUserId').val(),
        type: $('#listType').val()
      }, function(data) {
        if (type == "anime") rewatches[index] = $(data.html).find('strong')[0].innerHTML; //If the type is anime start scrapping the anime rewatched values
        if (type == "manga") //If the type is anime start scrapping the manga 'Times Read' values
        { //Starts the if condition
          var moreSection = $(data.html).find('td').html(); //Opens the more button on old classic style list
          var timesReadIndex = moreSection.indexOf("Times Read"); //Detects how many times a manga was read
          rewatches[index] = moreSection.charAt(timesReadIndex + 12);
        } //Finishes the if condition
      }, "json"); //The scrapping isn't done using HTML,it's done by scrapping only the json file that's loaded when the user goes down (loads more animes/mangas) ('XHR Get' Method)
    });
  } //Finishes the if condition
  else //If the script was run on a new modern list style
  { //Starts the else condition
    console.log('Opening And Scraping All "More" Buttons.Please Wait!'); //Shows a message in the console for dev purposes
    // The 6 lines Below Will Click all links labeled 'More' to get the rewatch counts later on the page
    for (var i = moreLinks.length; i--;) {
      if (moreLinks[i].innerHTML == 'More') {
        moreLinks[i].click();
      } //Finishes the if condition
    } //Finishes the for condition
  } //Finishes the else condition

  document.querySelector("head").innerHTML = "<title>Generating List...</title>"; //Change the tab title

  wait(); // Repeats every 1 seconds until all More-sections are processed

  function wait() //Creates the wait function
  { //Starts the function wait
    setTimeout(function() //Creates the timeout function
      { //Starts the timeout function
        if (!old_list) rewatches = document.querySelectorAll('tbody.list-item tr.more-info strong'); //If the script was run on an new modern list style then use this command to set the variable rewatches
        if (rewatches.length != titles.length) // Check if All sections were or not opened
        { //Starts the if condition
          wait(); //If All sections were not opened check it again after 1 seconds
        } //Finishes the if condition
        else //If All sections were opened
        { //Starts the else condition
          if (old_list) //Check if the script was run in an old classic list style or not
          { //Starts the if condition
            for (var i = 0; i < titles.length; i++) {
              // Parse rewatched shows into an array of arrays with rewatch count as index and add them to the downloaded file when the script is done
              if (rewatches[i] > 0) {
                if (resultArray[rewatches[i]]) {
                  resultArray[rewatches[i]] = resultArray[rewatches[i]].concat("<li>" + titles[i].textContent + "</li>");
                } else { //Starts the else condition
                  resultArray[rewatches[i]] = "<b>" + (parseInt(rewatches[i]) + 1) + " times:</b>"; // +1 shows the total watched times number. -1 shows the total Re-Watched times only.
                  resultArray[rewatches[i]] = resultArray[rewatches[i]].concat("<ul>");
                  resultArray[rewatches[i]] = resultArray[rewatches[i]].concat("<li>" + titles[i].textContent + "</li>");
                } //Finishes the else condition
              } //Finishes the if condition
            } //Finishes the for condition
          } //Finishes the if condition
          else //If the script was run in on the new default modern list style
          { //Starts the else condition
            for (var i = 0; i < titles.length; i++) {
              // Parse rewatched shows into an array of arrays with rewatch count as index
              if (rewatches[i].innerHTML > 0) {
                if (resultArray[rewatches[i].innerHTML]) {
                  resultArray[rewatches[i].innerHTML] = resultArray[rewatches[i].innerHTML].concat("<li>" + titles[i].trim() + "</li>");
                } //Finishes the if condition
                 else
                { //Starts the else condition
                  resultArray[rewatches[i].innerHTML] = "<b>" + (parseInt(rewatches[i].innerHTML) + 1) + " times:</b>"; // +1 shows the Re-Watched/Re-Read and the watched/read total numbers. -1 shows only the total times an anime/manga was Re-Watched/Re-Read.
                  resultArray[rewatches[i].innerHTML] = resultArray[rewatches[i].innerHTML].concat("<ul>"); //Adds the divisories (div like html tags) between rewatched/reread numbers, and concatenates them
                  resultArray[rewatches[i].innerHTML] = resultArray[rewatches[i].innerHTML].concat("<li>" + titles[i].trim() + "</li>"); //Adds the rewatched/reread titles inside the tags <li> , and concatenates them
                } //Finishes the else condition
              } //Finishes the if condition
            } //Finishes the for condition
          } //Finishes the else condition

          resultArray.reverse(); //This command makes result on the downloaded file be organized by starting the list with the most rewatched/reread values, if this line is removed, the result on the downloaded file will start the list with animes rewatched once and the last animes on the list will be the most rewatched/reread one's.
          resultArray.forEach(function(value, index, array) {
            result += value.concat("</ul>");
          });
          document.querySelector("body").insertAdjacentHTML('beforebegin', "<a id='progress' style='position: absolute; left:0px;'></a>"); //Create an a element
          document.querySelector("#progress").textContent = "Total Entries Processed: " + rewatches.length + " X Total Entries: " + titles.length; //Add the total number of completed entries that were processed to the HTML 'a' element with the ID 'progress'

          document.querySelector("body").insertAdjacentHTML('beforebegin', "<a id='dwnldLnk' style='margin-left: 1200px;' download='"+username+" ReWatched_ReRead List!' title='"+username+" ReWatched_ReRead List!.html'>Download List</a>"); //Create and show the download button
          document.getElementById('dwnldLnk').href = result; //Adds the scrapped results as a link on the a element

          document.querySelector("body").insertAdjacentHTML('beforebegin', "<a id='returntoprofile' href='https://myanimelist.net/profile/"+username+"' style='margin-inline-start: -700px;'>Return To User Profile</a>"); //Creates and show an a element on the screen

          document.querySelector("head").innerHTML = "<title>Done! List Generated!</title>"; //Change the tab title
          console.log('Done! Showing The Results Page!'); //Shows a message in the console for dev purposes
          document.querySelector("body").innerHTML = result.replace('data:text/html;charset=utf-8,', '');
          window.scrollTo(0, 0); //Scroll page to top
        } //Finishes the else condition
      }, 1000); //Finishes the settimeout function.Wait 1 second
  } //Finishes the function wait
} // Finishes the scrape function
})(); // Finishes the tampermonkey for condition

QingJ © 2025

镜像随时可能失效,请加Q群300939539或关注我们的公众号极客氢云获取最新地址