MAL Images Backup

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

当前为 2023-05-07 提交的版本,查看 最新版本

您需要先安装一款用户脚本管理器扩展,例如 Tampermonkey 篡改猴Greasemonkey 油猴子Violentmonkey 暴力猴,才能安装此脚本。

您需要先安装一款用户脚本管理器扩展,例如 Tampermonkey 篡改猴,才能安装此脚本。

您需要先安装一款用户脚本管理器扩展,例如 Tampermonkey 篡改猴Violentmonkey 暴力猴,才能安装此脚本。

您需要先安装一款用户脚本管理器扩展,例如 Tampermonkey 篡改猴Userscripts ,才能安装此脚本。

您需要先安装一款用户脚本管理器扩展,例如 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  2
// @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
// @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