Auch von meiner Seite vielen Dank.
Meins läuft mit der Änderung von hier: RE: BackupProfile.uc.js - div. Fragen dazu
auch wieder einwandfrei.
Mfg.
Endor
BackupProfile.uc.js - div. Fragen dazu
-
2002Andreas -
20. Oktober 2021 um 18:45 -
Erledigt
-
-
Skript ProfileBackup@Fu.uc.js
=============================Vor Nutzung des Skriptes müssen zwei Ordner für die Sicherungen eingerichtet werden ( Beispiele aus dem Skript ersichtlich ). In den ersten Ordner wird dann der vollständige Profilordner hinein kopiert (kein ZIP), wobei ganz wichtig ist, den richtigen Namen des Profils in das Skript einzutragen (about:profiles aufrufen und Namen entnehmen, z.B. qtqwpmy7.default-release). Bei jedem neuen Backup wird
der Profilordner hier überschrieben. Auch portable können mit entsprechenden Angaben (Pfade) gesichert werden.
Der zweite Ordner gilt als doppelte Sicherung, hier wird auch der Profilordner hinein kopiert, hat als Endung aber eine fortlaufende Nummerierung mit Datum und Uhrzeit (wichtig wenn mehrmals gesichert wird).
Die Pfade zu diesen Ordnern sind bei jedem Profil in das Skript einzutragen.Das Skript wird über den Button in der Navbar gestartet, es öffnet sich ein Menü (Grafik 1) über das eine Auswahl für ein Backup getroffen werden kann, bei Klick darauf erscheint ein Bestätigungs-Dialog (Grafik 2), der bedient werden muss. Bei OK startet das Backup, bei Erfolg wird dann über Windows eine Benachrichtigung ausgegeben (Grafik 3).
CSS
Alles anzeigen// ==UserScript== // @name ProfileBackup@Fu.uc.js // @description Firefox Profil sichern (Backup + Archiv, gesperrte Dateien ignoriert) // @version 2026.07-icons-css-final // ==/UserScript== (function () { "use strict"; if (location.href !== "chrome://browser/content/browser.xhtml") return; if (typeof CustomizableUI === "undefined") return; if (!window.gBrowser) return; // ========================= // Pro Profil konfigurieren // ========================= const PROFILES = [ { label: "Nightly2", profilePath: "G:\\Firefox Test\\Nightly2\\Profilordner", profileName: "Profilordner", backup1Path: "G:\\Firefox Sicherung\\Nightly2", archiveRootPath: "G:\\Sicherung2\\Nightly2", iconPath: "file:///C:/FoxIcons2/Nightly.png" }, { label: "Beta1", profilePath: "G:\\Firefox Test\\Beta1\\Profilordner", profileName: "Profilordner", backup1Path: "G:\\Firefox Sicherung\\Beta1", archiveRootPath: "G:\\Sicherung2\\Beta1" iconPath: "file:///C:/FoxIcons2/Beta.png" } // Weitere Profile hier ergänzen: // { // label: "Stable", // profilePath: "D:\\Firefox\\Stable\\Profilordner", // profileName: "Stable_Profil", // backup1Path: "D:\\Firefox Sicherung\\Stable", // archiveRootPath: "D:\\Sicherung2\\Stable", // iconPath: "file:///C:/FoxIcons2/002.png" // } ]; // ========================= // UI IDs // ========================= const BTN_ID = "profilebackup_menu_button_icons_final"; const POPUP_ID = BTN_ID + "_popup"; // ========================= // Button-Icon // ========================= const btnIconPath = "file:///C:/FoxIcons2/backup.png"; // ========================= // Helpers // ========================= function showAlert(text) { try { let w = null; try { w = Services.wm.getMostRecentWindow("navigator:browser"); } catch (_) {} Services.prompt.alert(w || null, "Profilsicherung", text); } catch (e) { console.error("Alert Fehler:", e); } } function pad(n) { return String(n).padStart(2, "0"); } // ========================= // Backup-Logik // ========================= function getArchiveFolder(root, profileName) { const d = new Date(); const timestamp = pad(d.getMonth() + 1) + pad(d.getDate()) + "_" + pad(d.getHours()) + pad(d.getMinutes()); const archiveTarget = root.clone(); archiveTarget.append(profileName + "_" + timestamp); return archiveTarget; } function copyDirectoryContents(srcDir, destDir) { let entries = srcDir.directoryEntries; while (entries.hasMoreElements()) { let entry = entries.getNext().QueryInterface(Ci.nsIFile); // gesperrte / WAL / shm ignorieren if ( entry.leafName === "parent.lock" || entry.leafName === "lock" || entry.leafName === "recovery.jsonlz4" || entry.leafName.endsWith(".sqlite-wal") || entry.leafName.endsWith(".sqlite-shm") ) { continue; } const newFile = destDir.clone(); newFile.append(entry.leafName); try { if (entry.isDirectory()) { if (!newFile.exists()) newFile.create(Ci.nsIFile.DIRECTORY_TYPE, 0o755); copyDirectoryContents(entry, newFile); } else { entry.copyTo(destDir, entry.leafName); } } catch (e) { console.warn("⚠️ Datei konnte nicht kopiert werden (gesperrt?): " + entry.path, e); } } } function runBackup(profile) { try { const profileDir = new FileUtils.File(profile.profilePath); if (!profileDir.exists()) { throw new Error("Profilordner existiert nicht: " + profile.profilePath); } const backupRoot = new FileUtils.File(profile.backup1Path); if (!backupRoot.exists()) backupRoot.create(Ci.nsIFile.DIRECTORY_TYPE, 0o755); const archiveRoot = new FileUtils.File(profile.archiveRootPath); if (!archiveRoot.exists()) archiveRoot.create(Ci.nsIFile.DIRECTORY_TYPE, 0o755); // BACKUP 1 const backupTarget = backupRoot.clone(); backupTarget.append(profile.profileName); if (backupTarget.exists()) backupTarget.remove(true); backupTarget.create(Ci.nsIFile.DIRECTORY_TYPE, 0o755); copyDirectoryContents(profileDir, backupTarget); // BACKUP 2 (Archiv + Zeitstempel) const archiveTarget = getArchiveFolder(archiveRoot, profile.profileName); archiveTarget.create(Ci.nsIFile.DIRECTORY_TYPE, 0o755); copyDirectoryContents(profileDir, archiveTarget); // Alert nachträglich (robuster) setTimeout(() => { showAlert( "✅ Backup abgeschlossen!\n\n" + "👤 Profil: " + profile.label + "\n\n" + "📁 Backup Ordner 1: " + backupTarget.path + "\n" + "📁 Archiv Ordner 2: " + archiveTarget.path ); }, 50); } catch (e) { console.error("Backup Fehler:", e); setTimeout(() => showAlert("❌ Fehler: " + e.message), 0); } } // ========================= // Menü bauen // ========================= function createMenu(doc) { const menupopup = doc.createXULElement("menupopup"); menupopup.setAttribute("id", POPUP_ID); PROFILES.forEach((profile) => { const menuitem = doc.createXULElement("menuitem"); menuitem.setAttribute("label", "Backup: " + profile.label); menuitem.setAttribute("class", "menuitem-iconic"); if (profile.iconPath) { menuitem.setAttribute("image", profile.iconPath); } menuitem.addEventListener("command", () => { let ok = false; try { ok = Services.prompt.confirm( null, "Profilsicherung", "Backup jetzt starten für: " + profile.label + " ?" ); } catch (_) { ok = true; // Fallback } if (ok) runBackup(profile); }); menupopup.appendChild(menuitem); }); return menupopup; } // ========================= // Button patchen (öffnet nur Popup) // ========================= function patchButton(btn) { if (!btn) return false; const oldPopup = btn.querySelector("#" + POPUP_ID); if (oldPopup) oldPopup.remove(); btn.setAttribute("type", "menu"); btn.setAttribute("aria-haspopup", "true"); btn.setAttribute("tooltiptext", "Profile auswählen (Backup starten)"); btn.setAttribute("image", btnIconPath); btn.appendChild(createMenu(btn.ownerDocument)); btn.addEventListener("click", (ev) => { if (ev.button !== 0) return; try { const p = btn.querySelector("#" + POPUP_ID); if (p) p.openPopup(btn, "after_start", 0, 0, false, false); } catch (_) {} }, false); return true; } // ========================= // Alte Instanz entfernen + Widget erstellen // ========================= try { if (CustomizableUI.getWidget && CustomizableUI.getWidget(BTN_ID)) { try { CustomizableUI.destroyWidget(BTN_ID); } catch (_) {} } } catch (_) {} try { const el = document.getElementById(BTN_ID); if (el) el.remove(); } catch (_) {} CustomizableUI.createWidget({ id: BTN_ID, defaultArea: CustomizableUI.AREA_NAVBAR, label: "Profilsicherung", tooltiptext: "Profile auswählen (Backup starten)", onCreated: (button) => setTimeout(() => patchButton(button), 0) }); // ========================= // ✅ Deine CSS Styles (Button & Popup) // ========================= const css = ` #${BTN_ID} .toolbarbutton-icon { width: 31px !important; height: 31px !important; padding: 5px !important; } #${POPUP_ID} { max-width: 250px !important; min-width: 250px !important; } #${POPUP_ID} menuitem.menuitem-iconic img.menu-icon { margin-left: -28px !important; } #${POPUP_ID} menuitem.menuitem-iconic label.menu-text { margin-left: 6px !important; } `; const sss = Cc["@mozilla.org/content/style-sheet-service;1"].getService(Ci.nsIStyleSheetService); const ios = Cc["@mozilla.org/network/io-service;1"].getService(Ci.nsIIOService); const uri = ios.newURI("data:text/css;charset=utf-8," + encodeURIComponent(css), null, null); sss.loadAndRegisterSheet(uri, sss.USER_SHEET); })(); -