]>
git.wh0rd.org - chrome-ext/tabs-backup.git/blob - background.js
1 // Create a backup on first install (or if storage is wiped for some reason.
2 chrome
.storage
.local
.get(function(items
) {
4 if (items
.prefs_max_backup_items
=== undefined) {
5 chrome
.storage
.local
.set({prefs_max_backup_items
: 10});
7 if (items
.prefs_backup_timer
=== undefined) {
8 chrome
.storage
.local
.set({prefs_backup_timer
: 30});
11 // If a backup exists already, nothing to do.
12 if (items
.backups_list
) {
16 // Create a backup now
18 var formattedDate
= date_format (d
);
20 backupNow(true, formattedDate
, function({success
, backupName
, backupObj
}) {
25 function initAlarm () {
26 //console.log("initAlarm");
28 var BACKUP_ALARM_NAME
= "backup_alarm";
30 // Clear any previous alarm
31 chrome
.alarms
.clearAll();
33 chrome
.storage
.local
.get(function(items
) {
34 const timerMinutes
= items
.prefs_backup_timer
;
35 chrome
.alarms
.create(BACKUP_ALARM_NAME
, {periodInMinutes
: timerMinutes
});
41 function onAlarm (alarm
) {
43 var formattedDate
= date_format (d
);
45 console
.log("Alarm {" + alarm
+ "} fired up: " + formattedDate
);
47 // if last backup time != lastTabsEdit
48 // perform automatic backup
49 backupNow(true, formattedDate
, function({success
, backupName
, backupObj
}) {
50 // automatic backup completed
51 chrome
.runtime
.sendMessage({
52 action
: 'insertBackupItem',
53 args
: [backupName
, backupObj
, true /*insertAtBeginning*/, true /*doAnimation*/],
58 chrome
.alarms
.onAlarm
.addListener(onAlarm
);
60 // yyyy-mm-dd hh:mm:ss
61 function date_format(d
) {
62 const prependZero
= (val
) => val
.toString().padStart(2, '0');
63 return d
.getFullYear() + "-" +
64 prependZero(d
.getMonth() + 1) + "-" +
65 prependZero(d
.getDate()) + " " +
66 prependZero(d
.getHours()) + ":" +
67 prependZero(d
.getMinutes()) + ":" +
68 prependZero(d
.getSeconds());
72 function backupNowManual (callbackDone
) {
74 var formattedDate
= date_format (d
);
76 backupNow(false, formattedDate
, callbackDone
);
81 async
function deleteOldestBackup() {
82 const items
= await chrome
.storage
.local
.get();
83 if (!items
.backups_list
) {
87 const backupsList
= items
.backups_list
;
88 const numItemsToDelete
= backupsList
.length
- items
.prefs_max_backup_items
;
89 for (let i
= 0; i
< numItemsToDelete
; ++i
) {
90 const deletedBackupName
= backupsList
[i
];
91 await
deleteBackup(deletedBackupName
);
93 chrome
.runtime
.sendMessage({
94 action
: 'removeBackupItemDiv',
95 args
: [deletedBackupName
],
100 //var isCreatingBackup = false;
102 function backupNow(isAutomatic
, backupName
, callbackDone
) {
103 console
.log("backupNow - isAutomatic: " + isAutomatic
+ " name: " + backupName
);
104 /*if (isCreatingBackup === true) {
105 console.log("backupNow - already running..skipping..");
109 //isCreatingBackup = true;
111 /*if (!confirm("Perform a full backup? All windows and their tabs will be saved!")) {
117 isAutomatic
: isAutomatic
,
121 chrome
.windows
.getAll({populate
: true}, function (window_list
) {
124 for(var i
=0;i
<window_list
.length
;i
++) {
125 var window
= window_list
[i
];
127 //console.log ("Window " + i);
134 height
: window
.height
,
138 var windowTabs
= window
.tabs
;
140 // If it's a single window sittig at the new tab page, don't bother
141 // saving it. This is a nice shortcut when things crash as it will
142 // only show a single window.
143 if (windowTabs
.length
== 1) {
144 const tab
= windowTabs
[0];
145 if (tab
.url
== 'chrome://newtab/')
149 for (var j
= 0; j
< windowTabs
.length
; j
++) {
150 var tab
= windowTabs
[j
];
152 //console.log("==> Tab " + j + " (" + tab.index + "): " + tabUrl);
154 // Ignore windows that we can't/shouldn't backup.
155 if (tab
.url
.startsWith('chrome-untrusted://')) {
162 highlighted
: tab
.highlighted
,
166 // Add tab to tabs arrays
167 bkpWindow
.tabs
.push(bkpTab
);
170 if (bkpWindow
.tabs
.length
) {
171 totNumTabs
+= bkpWindow
.tabs
.length
;
173 fullBackup
.windows
.push(bkpWindow
);
180 fullBackup
.totNumTabs
= totNumTabs
;
182 var storageSetValues
= {};
183 storageSetValues
[backupName
] = fullBackup
;
186 chrome
.storage
.local
.set(storageSetValues
, function () {
187 if (chrome
.runtime
.lastError
) {
188 //isCreatingBackup = false;
189 // TODO change icon to error..
190 //alert ("Error: " + chrome.runtime.lastError.message);
191 updateBrowserActionIcon (1);
193 callbackDone({success
: false});
195 console
.log("backup saved");
196 //alert("Backup saved successfully!");
198 chrome
.storage
.local
.get(function(items
) {
199 var backupsList
= [];
200 if(items
.backups_list
) {
201 backupsList
= items
.backups_list
;
204 console
.log("Updating 'backups_list' - cur. size: " + backupsList
.length
);
206 backupsList
.push(backupName
);
208 chrome
.storage
.local
.set({"backups_list": backupsList
}, function () {
209 //isCreatingBackup = false;
211 if (chrome
.runtime
.lastError
) {
212 console
.log ("Error saving backups_list: " + chrome
.runtime
.lastError
.message
);
213 updateBrowserActionIcon (1);
214 callbackDone({success
: false});
216 console
.log("Backups list saved successfully");
218 updateBrowserActionIcon (0);
222 backupObj
: fullBackup
,
225 if (backupsList
.length
> items
.prefs_max_backup_items
) {
226 deleteOldestBackup();
240 function updateBrowserActionIcon (status
) {
244 icon
= "icon_ok.png";
247 icon
= "icon_error.png";
251 chrome
.action
.setIcon({path
: icon
});
254 async
function deleteBackup(backupName
) {
255 console
.log("Deleting backup " + backupName
);
257 await chrome
.storage
.local
.remove(backupName
);
258 //console.log("=> Deleted backup " + backupName);
260 const items
= await chrome
.storage
.local
.get("backups_list");
261 //console.log("==> got backups_list " + backupName);
263 if (!items
.backups_list
) {
267 var backupsList
= items
.backups_list
;
269 var index
= backupsList
.indexOf(backupName
);
271 backupsList
.splice(index
, 1);
274 //console.log("===> Updating backups_list (removing " + backupName + ")");
276 await chrome
.storage
.local
.set({"backups_list": backupsList
});
277 //console.log("===> Updated backups_list (removed " + backupName + ")");
280 function restoreNow(backupName
) {
281 console
.log("restoreNow");
283 chrome
.storage
.local
.get(backupName
, function(items
) {
284 if(!items
[backupName
]) {
285 alert("No Backup found");
289 /*if (!confirm("Restore full backup?")) {
293 if (confirm("Would you like to close all existing windows first?")) {
294 chrome.windows.getAll({populate : false}, function (window_list) {
295 for(var i=0;i<window_list.length;i++) {
296 var window = window_list[i];
297 chrome.windows.remove(window.id);
303 var fullBackup
= items
[backupName
];
305 for(var i
=0;i
<fullBackup
.windows
.length
;i
++) {
306 const window
= fullBackup
.windows
[i
];
308 //console.log ("Window " + i);
312 const windowTabs
= window
.tabs
;
313 for (let j
= 0; j
< windowTabs
.length
; j
++) {
314 const tab
= windowTabs
[j
];
315 const tabUrl
= tab
.url
;
316 urlsToOpen
.push(tabUrl
);
319 const windowProperties
= {
325 height
: window
.height
,
328 // Create a new Window
329 chrome
.windows
.create(windowProperties
, function(createdWindow
) {
330 // Chrome errors if the dimensions are set on non-normal windows.
331 // So we create the window first with the right settings, then
332 // update the window state.
333 if (window
.state
!= 'normal') {
334 chrome
.windows
.update(createdWindow
.id
, {state
: window
.state
});
337 chrome
.windows
.get(createdWindow
.id
, {populate
: true}, ({tabs
}) => {
338 for (let tabi
= 0; tabi
< windowTabs
.length
; ++tabi
) {
339 const oldtab
= windowTabs
[tabi
];
340 const newtab
= tabs
[tabi
];
341 chrome
.tabs
.update(newtab
.id
, {
342 highlighted
: oldtab
.highlighted
,
343 pinned
: oldtab
.pinned
,
345 if (!oldtab
.highlighted
) {
346 // If we discard a tab too fast, Chrome will completely
347 // throw it away. Wait until it's in a stable enough
348 // state for us to discard it.
350 const checktab
= (id
) => {
351 if (retryCount
-- < 0)
353 chrome
.tabs
.get(id
, (tab
) => {
355 setTimeout(() => checktab(id
), 500);
357 chrome
.tabs
.discard(id
);
371 * Callback from other pages (like the popup).
373 chrome
.runtime
.onMessage
.addListener(function(request
, sender
, sendResponse
) {
374 console
.log(`Got message from ${sender.id}: action=${request.action}`, request
);
376 let asyncResponse
= false;
377 switch (request
?.action
) {
383 restoreNow(...request
.args
);
387 deleteBackup(...request
.args
).then(sendResponse
);
388 asyncResponse
= true;
391 case 'backupNowManual':
392 backupNowManual(sendResponse
);
393 asyncResponse
= true;
396 return asyncResponse
;