Greasy Fork

Greasy Fork is available in English.

Evolve Idle Cloud Save

Automatically upload your evolve save to a gist

当前为 2024-12-23 提交的版本,查看 最新版本

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

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

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

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

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

您需要先安装一款用户脚本管理器扩展后才能安装此脚本。

(我已经安装了用户脚本管理器,让我安装!)

您需要先安装一款用户样式管理器扩展,比如 Stylus,才能安装此样式。

您需要先安装一款用户样式管理器扩展,比如 Stylus,才能安装此样式。

您需要先安装一款用户样式管理器扩展,比如 Stylus,才能安装此样式。

您需要先安装一款用户样式管理器扩展后才能安装此样式。

您需要先安装一款用户样式管理器扩展后才能安装此样式。

您需要先安装一款用户样式管理器扩展后才能安装此样式。

(我已经安装了用户样式管理器,让我安装!)

// ==UserScript==
// @name         Evolve Idle Cloud Save
// @namespace    https://github.com/Alistair1231/my-userscripts/
// @version      1.0.0
// @description  Automatically upload your evolve save to a gist
// @author       Alistair1231
// @match        https://pmotschmann.github.io/Evolve/
// @icon         https://icons.duckduckgo.com/ip2/github.io.ico
// @grant        GM.xmlhttpRequest
// @grant        GM.setValue
// @grant        GM.getValue
// @license GPL-3.0
// @require https://cdn.jsdelivr.net/gh/Alistair1231/my-userscripts@232b1d6f0a0a6eb47fcccb94e6346d8230562154/lib.js

// @grant GM_getValue
// @grant GM_setValue
// @grant GM_deleteValue
// @grant GM_listValues
// @require https://cdn.jsdelivr.net/gh/Alistair1231/my-userscripts@232b1d6f0a0a6eb47fcccb94e6346d8230562154/libValues.js

// @grant GM_xmlhttpRequest
// @require https://cdn.jsdelivr.net/gh/Alistair1231/my-userscripts@232b1d6f0a0a6eb47fcccb94e6346d8230562154/libRequest.js
// ==/UserScript==
// http://greasyfork.icu/en/scripts/490376-automatic-evolve-save-upload-to-gist
// https://github.com/Alistair1231/my-userscripts/raw/master/EvolveIdleSavegameBackup.user.js

/*
# Evolve Idle Cloud Save
Automatically upload your evolve save to a gist, on first run you will be prompted to enter your 
Gist ID and Personal Access Token. These will be saved as cleartext in the Userscript storage. 
The token should have the `gist` scope.  
The Gist, has to be created manually, and the ID should be entered in the settings.  
Exporting is always done to the filename specified in the settings.  
Import can be done from any file in the Gist. (e.g. after changing PCs).  
Automatic backup is done every 15 minutes. Manual backup can be done by clicking the "Save to" button.  
The script also exposes the `evolveCloudSave` object to the window for manual use.
*/

(async function () {
  "use strict";
  const lib = { ...libDefault, ...libRequest, ...libValues };

  const evolveCloudSave = {
    // Create an overlay to collect secrets from the user
    openSettings: () => {
      const saveSettings = () => {
        const gistId = document.getElementById("gist_id").value.trim();
        const token = document.getElementById("gist_token").value.trim();
        const fileName =
          document.getElementById("file_name").value.trim() || "save.txt";
        if (!gistId || !token) {
          alert("Gist ID and Token are required!");
          return;
        }
        lib.settings.gistId = gistId;
        lib.settings.token = token;
        lib.settings.fileName = fileName;
        document.body.removeChild(overlay);
      };

      const fillCurrentSettings = () => {
        document.getElementById("gist_id").value = lib.settings.gistId || "";
        document.getElementById("gist_token").value = lib.settings.token || "";
        document.getElementById("file_name").value =
          lib.settings.fileName || "save.txt";
      };

      let overlay = document.createElement("div");
      overlay.innerHTML = `
    <div id='settings_overlay'
        style='position: fixed; top: 0; left: 0; width: 100%; height: 100%; background-color: rgba(0, 0, 0, 0.5); display: flex; align-items: center; justify-content: center; z-index: 1000'>
        <div id='settings_modal'
            style='background-color: white; padding: 20px; border-radius: 8px; box-shadow: 0 4px 8px rgba(0, 0, 0, 0.2); width: 400px'>
            <span style='font-size: 14px; margin-bottom: 10px'>
                You will need a GistID and a Personal Access Token to use this cloud-save script. They will be saved as
                cleartext in the Userscript storage!
            </span>
            <form id='settings_form'>
                <input id='gist_id' type='text' placeholder='Enter your Gist ID'
                    style='margin-top: 5px; padding: 8px; font-size: 14px'>
                <input id='gist_token' type='text' placeholder='Enter your Token'
                    style='margin-top: 5px; padding: 8px; font-size: 14px'>
                <input id='file_name' type='text' placeholder='Enter your Filename'
                    style='margin-top: 5px; padding: 8px; font-size: 14px'>
                <button id='save_button'
                    style='margin-top: 15px; padding: 10px; font-size: 14px; cursor: pointer'>Save</button>
            </form>
        </div>
    </div>
    `;

      document.body.appendChild(overlay);
      //   clicking on overlay and esc handling
      overlay.addEventListener("click", (e) => {
        if (e.target.id === "settings_overlay") {
          document.body.removeChild(overlay);
        }
      });
      document.addEventListener("keydown", (e) => {
        if (e.key === "Escape") {
          if (document.getElementById("settings_overlay")) {
            document.body.removeChild(overlay);
          }
        }
      });

      document.getElementById("save_button").addEventListener("click", (e) => {
        e.preventDefault();
        saveSettings();
      });

      fillCurrentSettings();
    },

    getFiles: async (request) => {
      const files = await request.get("");
      return JSON.parse(files).files;
    },
    createOrUpdateFile: async (request, filename, content) => {
      const files = await evolveCloudSave.getFiles(request);
      if (files[filename] === undefined) {
        return request.post("", { files: { [filename]: { content } } });
      } else {
        return request.patch("", { files: { [filename]: { content } } });
      }
    },

    makeBackup: async (request) => {
      const saveString = unsafeWindow.exportGame();
      const response = await evolveCloudSave.createOrUpdateFile(
        request,
        lib.settings.filename,
        saveString,
      );
      return response;
    },

    getBackup: async (request) => {
      const files = await evolveCloudSave.getFiles(request);
      const filename = document.getElementById("cloudsave_fileSelect").value;
      const content = files[filename].content;
      document.querySelector("textarea#importExport").value = content;
    },

    addButtons: async (request) => {
      const buttons = document.createElement("div");
      let files = await evolveCloudSave.getFiles(request);
      const filenames = Object.keys(files);

      buttons.innerHTML = `
    <div class='importExport' style='display: flex; justify-content: center; margin-top: 1rem'>
      <select id='cloudsave_fileSelect' style='margin-top: .75rem'>
        ${filenames.map((file) => `<option value='${file}'>${file}</option>`)}
      </select>
      <button id='cloudsave_importGistButton' class='button' style='margin-top: .75rem'>Import selected</button>
      <button id='cloudsave_exportGistButton' class='button' style='margin-top: .75rem'>Save to "${lib.settings.filename}"</button>
      <button id='cloudsave_settingsButton' class='button' style='margin-top: .75rem'>Settings</button>
    </div>
    <div id='success_message' style='display: none; position: fixed; top: 20px; right: 20px; background-color: green; color: white; padding: 10px; border-radius: 5px;'>Backup successful!</div>
    `;
      const div = document.querySelectorAll("div.importExport")[1];
      div.appendChild(buttons);
      document
        .getElementById("cloudsave_importGistButton")
        .addEventListener("click", () => {
          evolveCloudSave.getBackup(request);
        });
      document
        .getElementById("cloudsave_exportGistButton")
        .addEventListener("click", async () => {
          await evolveCloudSave.makeBackup(request);
          const successMessage = document.getElementById("success_message");
          successMessage.style.display = "block";
          setTimeout(() => {
            successMessage.style.transition = "opacity 1s";
            successMessage.style.opacity = "0";
            setTimeout(() => {
              successMessage.style.display = "none";
              successMessage.style.opacity = "1";
            }, 1000);
          }, 2000);
        });
      document
        .getElementById("cloudsave_settingsButton")
        .addEventListener("click", () => {
          evolveCloudSave.openSettings(request);
        });
    },

    init: async () => {
      const request = new lib.Request(
        `https://api.github.com/gists/${lib.settings.gistId}`,
        {
          Authorization: `token ${lib.settings.token}`,
        },
      );
      evolveCloudSave.addButtons(request);
    },
  };

  lib.waitFor("div#main", () => {
    if (lib.settings.gistId === undefined || lib.settings.token === undefined) {
      evolveCloudSave.openSettings();
      return;
    } else {
      evolveCloudSave.init();

      // run every 15 minutes
      setInterval(evolveCloudSave.makeBackup, 1000 * 60 * 15);

      // export for manual use
      unsafeWindow.evolveCloudSave = evolveCloudSave;
      unsafeWindow.evolveCloudSave.settings = lib.settings;
    }
  });
})();