MAL Images Backup

Backups all images on forum topics, blogs and all images on anime/manga lists CSS styles.

目前為 2023-05-07 提交的版本,檢視 最新版本

您需要先安裝使用者腳本管理器擴展,如 TampermonkeyGreasemonkeyViolentmonkey 之後才能安裝該腳本。

You will need to install an extension such as Tampermonkey to install this script.

您需要先安裝使用者腳本管理器擴充功能,如 TampermonkeyViolentmonkey 後才能安裝該腳本。

您需要先安裝使用者腳本管理器擴充功能,如 TampermonkeyUserscripts 後才能安裝該腳本。

你需要先安裝一款使用者腳本管理器擴展,比如 Tampermonkey,才能安裝此腳本

您需要先安裝使用者腳本管理器擴充功能後才能安裝該腳本。

(我已經安裝了使用者腳本管理器,讓我安裝!)

你需要先安裝一款使用者樣式管理器擴展,比如 Stylus,才能安裝此樣式

你需要先安裝一款使用者樣式管理器擴展,比如 Stylus,才能安裝此樣式

你需要先安裝一款使用者樣式管理器擴展,比如 Stylus,才能安裝此樣式

你需要先安裝一款使用者樣式管理器擴展後才能安裝此樣式

你需要先安裝一款使用者樣式管理器擴展後才能安裝此樣式

你需要先安裝一款使用者樣式管理器擴展後才能安裝此樣式

(我已經安裝了使用者樣式管理器,讓我安裝!)

// ==UserScript==
// @name      MAL Images Backup
// @namespace MALImgsBackup
// @description Backups all images on forum topics, blogs and all images on anime/manga lists CSS styles.
// @version  3
// @match    https://myanimelist.net/animelist/*
// @match    https://myanimelist.net/mangalist/*
// @match    https://myanimelist.net/blog/*&cat=*
// @match    https://myanimelist.net/forum/?topicid=*
// @icon     https://t3.gstatic.com/faviconV2?client=SOCIAL&type=FAVICON&fallback_opts=TYPE,SIZE,URL&url=http://myanimelist.net&size=64
// @connect  i.imgur.com
// @connect  cdn.myanimelist.net
// @connect  image.myanimelist.net
// @grant    GM_registerMenuCommand
// @grant    GM.xmlHttpRequest
// @run-at   document-end
// ==/UserScript==

GM_registerMenuCommand("Backup HTML/CSS", Backup); //Adds an option to the menu
async function Backup() { //Creates a new Backup function
  const imagePromises = []; //Creates a new array
  if (location.pathname.match('list') !== null) //If the user is on a manga/anime list
  { //Starts the if condition
    document.querySelector("style:nth-child(2), #custom-css").innerText.match(/http.+?(?=(?:"|'|`)?\))/gm).forEach((URL) => { //For each image URL in the CSS code
      const promise = new Promise((resolve) => { //Convert URL to DataURI using a Promise
        GM.xmlHttpRequest({ //Starts the xmlHttpRequest
          method: "GET",
          url: URL,
          responseType: "blob",
          onload: async (response) => {
            const reader = new FileReader();
            reader.onload = () => resolve(reader.result);
            reader.readAsDataURL(response.response);
          } //Finishes the onload
        }); //Finishes the xmlHttpRequest
      }); //Finishes the promise const
      imagePromises.push(promise); //Add the promise to the array
      promise.then((dataURI) => { //After the promise resolves, replace URL with DataURI in the CSS code
        document.querySelector("style:nth-child(2), #custom-css").innerText = document.querySelector("style:nth-child(2), #custom-css").innerText.replace(URL, dataURI);
      }); //Finishes the dataURI const
    }); //Finishes the forEach loop
    await Promise.all(imagePromises); //Wait for all image URLs to be fetched and their corresponding data URIs to be generated

    if (document.querySelector("#advanced-options") !== null && document.querySelector("#custom-css").innerText !== '\n               \n      ') //If the user is on a modern list style and has a custom css
    { //Starts the if condition
      document.body.insertAdjacentHTML('afterbegin', `<a id='dwnldLnk' download="${location.pathname.split('/')[2] + ' Modern Custom Style'}.css" href="data:text/css;charset=utf-8,${encodeURIComponent(document.querySelector("#custom-css").innerText)}"></a>`); //Generate the download button
    } //Finishes the if condition

    if (document.querySelector("#advanced-options") !== null) //If the user is on a modern list style and has no custom css
    { //Starts the if condition
      document.body.insertAdjacentHTML('afterbegin', `<a id='dwnldLnk' download="${location.pathname.split('/')[2] + ' Modern Style'}.css" href="data:text/css;charset=utf-8,${encodeURIComponent(document.querySelector("style:nth-child(2)").innerText)}"></a>`); //Generate the download button
      document.getElementById('dwnldLnk').click(); //Download the css
    } //Finishes the if condition
    else //If the user is on a classic list style
    { //Starts the else condition
      document.body.insertAdjacentHTML('afterbegin', `<a id='dwnldLnk' download="${location.pathname.split('/')[2] + ' Classic Style'}.css" href="data:text/css;charset=utf-8,${encodeURIComponent(document.querySelector("style:nth-child(2)").innerText)}"></a>`); //Generate the download button
      document.getElementById('dwnldLnk').click(); //Download the css
    } //Finishes the else condition
  } //Finishes the if condition
  else //If the user is on a forum or blog page
  { //Starts the else condition
    document.querySelectorAll(".message-text > img, .userimg").forEach(function(URL) { //ForEach image URL on the page
      const imagePromise = new Promise((resolve) => GM.xmlHttpRequest({ //Starts the xmlHttpRequest
        method: "GET",
        url: URL.src,
        responseType: "blob",
        onload: async (response) => {
          const dataURI = await new Promise((resolve) => {
            const reader = new FileReader();
            reader.onload = () => resolve(reader.result);
            reader.readAsDataURL(response.response);
          });
          dataURI !== 'data:' ? URL.src = dataURI : ''; //Change the url link with the data URI
          resolve(); //Resolve the promise once the data URI is generated
        } //Finishes the onload
      })); //Finishes the xmlHttpRequest
      imagePromises.push(imagePromise); //Add the promise to the array
    }); //Finishes the forEach loop
    await Promise.all(imagePromises); //Wait for all image URLs to be fetched and their corresponding data URIs to be generated
    document.body.insertAdjacentHTML('afterbegin', `<a id='dwnldLnk' download="https myanimelist.net ${location.href.split(/t\//)[1].replaceAll(/[/?]/gm, ' ').replaceAll(/  /gm, ' ')}.html" href="data:text/html;charset=utf-8,${encodeURIComponent(document.documentElement.outerHTML)}"></a>`); //Generate the download button
    document.getElementById('dwnldLnk').click(); //Download the website html
  } //Finishes the else condition
}; //Finishes the Backup function