Not a member of Pastebin yet?
Sign Up,
it unlocks many cool features!
- // ==UserScript==
- // @name Restore LocalStorage Across Domains
- // @namespace res.ls.pb
- // @version 1.1.0
- // @description Persists localStorage for specific sites across private browsing sessions using GM storage. Allows manual restore from other backed-up domains.
- // @author Gemini
- // @license UNLICENSE
- // @match *://*.8chan.moe/*
- // @match *://*.8chan.se/*
- // @match *://*.8chan.cc/*
- // @match *://alephchvkipd2houttjirmgivro5pxullvcgm4c47ptm7mhubbja6kad.onion/*
- // @grant GM.setValue
- // @grant GM.getValue
- // @grant GM.registerMenuCommand
- // @run-at document-start
- // ==/UserScript==
- //PROBLEMS:
- //- Currently Tampermonkey's Permanent incognito storage option doesn't work perfectly, it only works when closing the whole browser? I think it works on violentmonkey though.
- (async function () {
- "use strict";
- // == OPTIONS ==================================================================================================
- // == OPTIONS ==================================================================================================
- // == OPTIONS ==================================================================================================
- // The following options control the behavior of the script
- // --- Toggle for automatic restore/save ---
- // If true, the script will automatically restore the page's localStorage from GM storage when the page loads.
- // If false, the script will not automatically restore the page's localStorage, but you can still use the menu command to manually restore.
- const AUTOMATIC_RESTORE_ENABLED = false;
- // =============================================================================================================
- // =============================================================================================================
- // =============================================================================================================
- const SCRIPT_PREFIX = "rLS_"; // General prefix for keys to avoid collisions
- const PAGE_LS_FLAG_KEY_NAME = `${SCRIPT_PREFIX}flag_v1`; // Flag in page's localStorage
- const GM_LS_DATA_KEY_PREFIX = `${SCRIPT_PREFIX}bkp_`; // Prefix for GM storage key for LS data
- const GM_FIRSTRUN_FLAG_KEY_PREFIX = `${SCRIPT_PREFIX}firstrun_v1_`; // Prefix for GM storage key for first run flag
- const GM_DEBUG_EVENTS_KEY = `${SCRIPT_PREFIX}debug_events`; // Key for GM storage to log events
- // --- Dynamic Keys based on current hostname ---
- const currentHostname = window.location.hostname;
- const gmStorageKeyForCurrentHost = `${GM_LS_DATA_KEY_PREFIX}${currentHostname}`;
- const gmFirstRunFlagKeyForCurrentHost = `${GM_FIRSTRUN_FLAG_KEY_PREFIX}${currentHostname}`;
- // --- Helper Functions ---
- function log(message, ...args) {
- console.log(`[RestoreLS] (${currentHostname}) ${message}`, ...args);
- }
- function error(message, ...args) {
- console.error(`[RestoreLS] (${currentHostname}) ${message}`, ...args);
- }
- async function savePageLSToGM(targetGmKey) {
- try {
- const lsData = { ...localStorage }; // Modern way to copy localStorage
- await GM.setValue(targetGmKey, JSON.stringify(lsData));
- log(`Page localStorage saved to GM storage key: ${targetGmKey}`);
- } catch (e) {
- error("Failed to save page localStorage to GM storage:", e);
- }
- }
- async function restoreLSFromGM(sourceGmKey, isManualRestore = false, sourceDomainForManualRestore = "") {
- try {
- const storedDataString = await GM.getValue(sourceGmKey, null);
- if (storedDataString) {
- const dataToRestore = JSON.parse(storedDataString);
- // Clear current LS before restoring to handle deletions properly
- // Preserve our flag if it was set by the first-run logic on THIS page load,
- // otherwise, the restore operation itself will set a new appropriate flag.
- const flagExistedBeforeClear = localStorage.getItem(PAGE_LS_FLAG_KEY_NAME);
- localStorage.clear();
- if (flagExistedBeforeClear && !isManualRestore && flagExistedBeforeClear.startsWith("initial_")) {
- localStorage.setItem(PAGE_LS_FLAG_KEY_NAME, flagExistedBeforeClear);
- }
- for (const key in dataToRestore) {
- if (Object.prototype.hasOwnProperty.call(dataToRestore, key)) {
- localStorage.setItem(key, dataToRestore[key]);
- }
- }
- let flagValue;
- if (isManualRestore) {
- flagValue = `manually_restored_from_${sourceDomainForManualRestore}_at_${new Date().toISOString()}`;
- log(`Page localStorage manually restored from GM key: ${sourceGmKey} (origin: ${sourceDomainForManualRestore}).`, Object.keys(dataToRestore).length, "items.");
- alert(`Restored ${Object.keys(dataToRestore).length} items from ${sourceDomainForManualRestore} to the current page.`);
- } else {
- flagValue = `restored_from_gm_at_${new Date().toISOString()}`;
- log("Page localStorage automatically restored from GM storage.", Object.keys(dataToRestore).length, "items.");
- }
- localStorage.setItem(PAGE_LS_FLAG_KEY_NAME, flagValue);
- } else {
- if (isManualRestore) {
- log(`No data found in GM storage for key: ${sourceGmKey} (for domain ${sourceDomainForManualRestore})`);
- alert(`No localStorage backup found for domain: ${sourceDomainForManualRestore}`);
- } else {
- log("No data found in GM storage to restore. Page localStorage remains as is (likely empty or new session).");
- localStorage.setItem(PAGE_LS_FLAG_KEY_NAME, `no_gm_data_to_restore_at_${new Date().toISOString()}`);
- }
- }
- } catch (e) {
- error("Failed to restore page localStorage from GM storage:", e);
- localStorage.setItem(PAGE_LS_FLAG_KEY_NAME, `restore_failed_at_${new Date().toISOString()}`);
- if (isManualRestore) {
- alert(`Error restoring data from ${sourceDomainForManualRestore}: ${e.message}`);
- }
- }
- }
- // async function logEventToGMStorage(eventName) {
- // try {
- // const timestamp = new Date().toISOString();
- // const eventData = { event: eventName, time: timestamp };
- // // Get existing events or create new array
- // const existingEvents = JSON.parse(await GM.getValue(GM_DEBUG_EVENTS_KEY, '[]'));
- // existingEvents.push(eventData);
- // // Keep only last 20 events
- // const trimmedEvents = existingEvents.slice(-20);
- // await GM.setValue(GM_DEBUG_EVENTS_KEY, JSON.stringify(trimmedEvents));
- // log(`Event logged: ${eventName} at ${timestamp}`);
- // } catch (e) {
- // error("Failed to log event to GM storage:", e);
- // }
- // }
- // --- Main Logic ---
- // log("Script starting.");
- if (AUTOMATIC_RESTORE_ENABLED) {
- // Check for userscript's first run for THIS specific domain
- const isScriptFirstRunForThisDomain = (await GM.getValue(gmFirstRunFlagKeyForCurrentHost, null)) === null;
- if (isScriptFirstRunForThisDomain) {
- log("Userscript first-run detected for this domain.");
- // On the very first run for this domain, set the flag in page LS.
- // This signifies that the current page LS is the "source of truth" for the first save.
- try {
- localStorage.setItem(PAGE_LS_FLAG_KEY_NAME, `initial_userscript_setup_at_${new Date().toISOString()}`);
- log("Page LS flag set due to userscript first run for this domain.");
- // And immediately save the current (potentially empty or pre-existing) LS to GM
- await savePageLSToGM(gmStorageKeyForCurrentHost);
- } catch (e) {
- error("Could not set page LS flag or save initial LS (localStorage might be disabled/full):", e);
- }
- await GM.setValue(gmFirstRunFlagKeyForCurrentHost, true); // Mark first run for this domain as completed
- } else {
- // Not the first run for this domain. Check if page LS needs restoration.
- const pageLSFlagExists = localStorage.getItem(PAGE_LS_FLAG_KEY_NAME) !== null;
- if (!pageLSFlagExists) {
- log("Page LS flag not found. Attempting to restore from GM storage for this domain.");
- await restoreLSFromGM(gmStorageKeyForCurrentHost);
- } else {
- log("Page LS flag found. Page localStorage assumed to be initialized or already restored for this session.");
- }
- }
- } else {
- log("AUTOMATIC_RESTORE_ENABLED is false. Skipping automatic restore/save logic.");
- }
- if (AUTOMATIC_RESTORE_ENABLED) {
- // window.addEventListener('beforeunload', async () => {
- // log("beforeunload: Saving current page LS to GM storage for this domain.");
- // await logEventToGMStorage('beforeunload');
- // await savePageLSToGM(gmStorageKeyForCurrentHost);
- // });
- window.addEventListener('visibilitychange', async () => {
- if (document.hidden) {
- log("visibilitychange: Saving current page LS to GM storage for this domain.");
- // await logEventToGMStorage('visibilitychange');
- await savePageLSToGM(gmStorageKeyForCurrentHost);
- }
- });
- window.addEventListener('pagehide', async () => {
- log("pagehide: Saving current page LS to GM storage for this domain.");
- // await logEventToGMStorage('pagehide');
- await savePageLSToGM(gmStorageKeyForCurrentHost);
- });
- }
- // Register Menu Command for manual restore
- GM.registerMenuCommand("Restore LS from a domain's backup", async () => {
- const sourceDomain = prompt(
- "Enter the domain name (e.g., example.com) whose localStorage backup you want to restore to THIS page:",
- currentHostname // default to current domain
- );
- if (sourceDomain && sourceDomain.trim() !== "") {
- const trimmedSourceDomain = sourceDomain.trim();
- log(`Manual restore initiated. Source domain: ${trimmedSourceDomain}`);
- const sourceGmKey = `${GM_LS_DATA_KEY_PREFIX}${trimmedSourceDomain}`;
- await restoreLSFromGM(sourceGmKey, true, trimmedSourceDomain);
- // After a manual restore, we also want to ensure this newly restored state is saved for the *current* domain when the page unloads.
- // The 'beforeunload' or 'visibilitychange' handler will take care of this naturally.
- } else if (sourceDomain !== null) {
- // Not null means user didn't press Cancel
- alert("Invalid or empty domain entered.");
- }
- });
- // Register Menu Command for manual save
- GM.registerMenuCommand("Save current domain's LS to GM storage", async () => {
- log("Manual save triggered via menu command.");
- await savePageLSToGM(gmStorageKeyForCurrentHost);
- alert("Current page localStorage has been saved to GM storage for this domain.");
- });
- // Add a menu command to view the logged events
- GM.registerMenuCommand("View Debug Event Logs", async () => {
- const events = JSON.parse(await GM.getValue(GM_DEBUG_EVENTS_KEY, '[]'));
- if (events.length === 0) {
- alert("No events have been logged yet.");
- return;
- }
- const formattedEvents = events.map(e => `${e.event}: ${e.time}`).join('\n');
- alert(`Last ${events.length} events:\n\n${formattedEvents}`);
- });
- // log("Script initialized.");
- })();
Add Comment
Please, Sign In to add comment