Greasy Fork is available in English.

Export Your Anime/Manga XML List On Any Page + Wayback Machine Your Profile.

This script adds a button on any anime/manga page, click on this button to download your Anime/Manga XML list. There's a button that's added on your profile only and Backups Your Profile using the Wayback Machine services.

// ==UserScript==
// @name         Export Your Anime/Manga XML List On Any Page + Wayback Machine Your Profile.
// @namespace    http://tampermonkey.net/
// @version      25
// @description  This script adds a button on any anime/manga page, click on this button to download your Anime/Manga XML list. There's a button that's added on your profile only and Backups Your Profile using the Wayback Machine services.
// @author       hacker09
// @match        https://myanimelist.net/profile/*
// @exclude      https://myanimelist.net/profile/*/*
// @match        https://myanimelist.net/editprofile.php
// @match        https://myanimelist.net/panel.php?go=export
// @include      /^https:\/\/myanimelist\.net\/(anime|manga)(id=)?(\.php\?id=)?\/?\d+\/?(?!.*\/).*(\?q=.*&cat=anime|manga)?$/
// @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        window.close
// @grant        GM_setValue
// @grant        GM_getValue
// ==/UserScript==

(function() {
  'use strict';
  const $ = jQuery; //Defines That The Symbol $ Is A jQuery
  const username = document.querySelector('a.header-profile-link').innerText; //Save the user name to a variable

  if (location.href === 'https://myanimelist.net/panel.php?go=export') { //If the user is on the export MAL page
    document.querySelector("input.inputButton").defaultValue = "Export My List Now"; //Change the export button text
  }
  //*****************************************************************************************************************************************************
  if (location.href.match(/^https:\/\/myanimelist\.net\/anime\/[\d]+(\/.*)?/) || location.href.match(/^https:\/\/myanimelist\.net\/manga\/[\d]+(\/.*)?/)) { //If the user is on a manga/anime page
    var type, downtype; //Make these variables global
    const token = document.head.querySelector("[name='csrf_token']").content; //Save the user csrf_token to a variable

    location.pathname.split('/')[1] === 'anime' ? (type = 'anime', downtype = 'type=1') : (type = 'manga', downtype = 'type=2'); //Set the page and download types
    const XMLBackupBTN = document.createElement("a"); //Creates the backup button element
    type === 'anime' ? XMLBackupBTN.innerHTML = "Backup My AnimeList" : XMLBackupBTN.innerHTML = "Backup My MangaList"; //Add the correct text to the button
    document.querySelector("span.information.type").parentElement.appendChild(XMLBackupBTN); //Add the button to the page
    XMLBackupBTN.setAttribute("id", "XMLBackupBTN"); //Adds an id to the button
    XMLBackupBTN.setAttribute("style", "cursor: pointer;margin-left: 15px;font-size: 10px;"); //Sets the CSS style of the button
    document.querySelector("#XMLBackupBTN").addEventListener("click", function() { //Add a click advent listener to the button
      (async function() { //Starts the async function
        const response = await fetch("https://myanimelist.net/panel.php?go=export2", { //Fetch the export MAL page
          "headers": { //Adds the header to the request
            "content-type": "application/x-www-form-urlencoded" //Set the content type
          }, //Ends the fetch request headers
          "body": downtype + "&subexport=Export+My+List&csrf_token=" + token, //Define the download type
          "method": "POST" //Fetch as POST
        }); //Finishes the fetch request
        const filename = response.headers.get('Content-Disposition').split(';')[1].split('=')[1].split('"')[1]; //Store the file name
        const blob = await response.blob(); //Gets the fetch response //Store the file bytes
        const link = document.createElement("a"); //Creates a new link element
        link.href = URL.createObjectURL(blob); //Add the file bytes as a blob link in the link element
        link.download = filename; //Add the file name and download to the link element
        link.click(); //Click on the link element
      }()); //Finishes the async function
    }, false); //Finishes the advent listener
  } //Finishes the if condition
  //*****************************************************************************************************************************************************
  if (location.href === 'https://myanimelist.net/editprofile.php') { //If the user is on the edit profile page
    document.querySelectorAll("textarea")[1].parentNode.insertAdjacentHTML('beforeend', '<a style="cursor: pointer;" id="Import"> Import Previous Profile BBCodes</a>'); //Append the Import btn below the textarea
    document.querySelector("#Import").onclick = function() //Detect the mouse click on the import button
    { //Starts the onclick function
      document.querySelectorAll("textarea")[1].value = GM_getValue("ProfileBBCodes"); //When the import btn is clicked return the previous ProfileBBCodes
    }; //Finishes the onclick function
  } //Finishes the if condition
  //*****************************************************************************************************************************************************
  if (location.href.match('profile/' + username) !== null) { //If the user is on his profile page
    const BackupProfileBTN = document.createElement("a"); //Creates the backup profile button element
    BackupProfileBTN.innerHTML = "Backup My Profile"; //Adds a text to the button
    document.querySelector("a.header-right.mt4.mr0").parentElement.appendChild(BackupProfileBTN); //Add the button to the page
    BackupProfileBTN.setAttribute("id", "BackupProfileBTN"); //Set an id to the button
    BackupProfileBTN.setAttribute("style", "cursor: pointer;margin-left: 15px;font-size: 10px;"); //Set the button css style
    document.querySelector("#BackupProfileBTN").addEventListener("click", saveprofileonarchiveorg, false); //Add a click advent listener to the button

    function saveprofileonarchiveorg() { //Starts the function to backup the user profile
      function iFrameLoaded(id, src) { //Creates a function
        const deferred = $.Deferred(),
          iframe = $("<iframe id='iframe'></iframe>").attr({ //Creates the iframe
            "id": id, //Sets the iframe id
            "src": src //Sets the iframe source
          }); //Finishes the attrib

        iframe.load(deferred.resolve); //Load the page and wait to be fully loaded
        iframe.appendTo("body"); //Add the iframe to the actual page body

        deferred.done(function() { //When the iframe finished loading
          console.log("iframe loaded: " + id); //Show a message on the browser console for dev purposes
        }); //Finishes the function

        return deferred.promise();
      } //Finishes the IframeLoaded function
      $.when(iFrameLoaded("Update MALGraph", "https://anime.plus/" + username + "/queue-add"),
          iFrameLoaded("Update Badges", "https://www.mal-badges.net/users/" + username + "/update"),
          iFrameLoaded("Currently Watching", "https://web.archive.org/save/https://myanimelist.net/animelist/" + username + "?status=1"),
          iFrameLoaded("Completed", "https://web.archive.org/save/https://myanimelist.net/animelist/" + username + "?status=2"),
          iFrameLoaded("On Hold", "https://web.archive.org/save/https://myanimelist.net/animelist/" + username + "?status=3"),
          iFrameLoaded("Dropped", "https://web.archive.org/save/https://myanimelist.net/animelist/" + username + "?status=4"),
          iFrameLoaded("Plan to Watch", "https://web.archive.org/save/https://myanimelist.net/animelist/" + username + "?status=6"),
          iFrameLoaded("Topics in Forum Replied To", "https://web.archive.org/save/https://myanimelist.net/forum/search?u=" + username + "&q=&uloc=1&loc=-1"),
          iFrameLoaded("MAL History", "https://web.archive.org/save/https://myanimelist.net/history/" + username + "/anime"),
          iFrameLoaded("Profile texts/statistics/Favorites/Comments and 12 Friends", "https://web.archive.org/save/https://myanimelist.net/profile/" + username + "#statistics"),
          iFrameLoaded("Clubs", "https://web.archive.org/save/https://myanimelist.net/profile/" + username + "/clubs"),
          iFrameLoaded("Recommendations", "https://web.archive.org/save/https://myanimelist.net/profile/" + username + "/recommendations"),
          iFrameLoaded("Reviews", "https://web.archive.org/save/https://myanimelist.net/profile/" + username + "/reviews"))
        .then(function() { //After all iframes finished loading

          (async () => { //Creates a function to get the ProfileBBCpdes and Starts the function
            const response = await (await fetch('https://myanimelist.net/editprofile.php')).text(); //Fetch
            const newDocument = new DOMParser().parseFromString(response, 'text/html'); //Parses the fetch response
            GM_setValue("ProfileBBCodes", newDocument.querySelectorAll("textarea")[1].value); //Store the ProfileBBCodes
            close(); //Close the actual tab
          })(); //Finishes the async function
        }); //Finishes the "then" function
    } //Finishes the saveprofileonarchiveorg function
  } //Finishes the if condition
})();