File indexing completed on 2024-04-28 05:32:49

0001 /*
0002     Copyright (C) 2017-2019 Kai Uwe Broulik <kde@privat.broulik.de>
0003 
0004     This program is free software; you can redistribute it and/or
0005     modify it under the terms of the GNU General Public License as
0006     published by the Free Software Foundation; either version 3 of
0007     the License, or (at your option) any later version.
0008 
0009     This program is distributed in the hope that it will be useful,
0010     but WITHOUT ANY WARRANTY; without even the implied warranty of
0011     MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
0012     GNU General Public License for more details.
0013 
0014     You should have received a copy of the GNU General Public License
0015     along with this program.  If not, see <http://www.gnu.org/licenses/>.
0016  */
0017 
0018 var activeDownloads = []
0019 var downloadUpdateInterval = 0;
0020 
0021 function startSendingDownloadUpdates() {
0022     if (!chrome.downloads.onChanged.hasListener(onDownloadChanged)) {
0023         // Register this listener only when needed. If it's active during
0024         // browser startup, it can be triggered for existing downloads (also
0025         // no longer existing files!) and freeze the UI for >1min!
0026         chrome.downloads.onChanged.addListener(onDownloadChanged);
0027     }
0028 
0029     if (!downloadUpdateInterval) {
0030         downloadUpdateInterval = setInterval(sendDownloadUpdates, 1000);
0031     }
0032 }
0033 
0034 function stopSendingDownloadUpdates() {
0035     if (downloadUpdateInterval) {
0036         clearInterval(downloadUpdateInterval);
0037         downloadUpdateInterval = 0;
0038     }
0039 }
0040 
0041 function sendDownloadUpdates() {
0042     chrome.downloads.search({
0043         state: 'in_progress',
0044         paused: false
0045     }, function (results) {
0046         if (!results.length) {
0047             stopSendingDownloadUpdates();
0048             return;
0049         }
0050 
0051         results.forEach(function (download) {
0052             if (activeDownloads.indexOf(download.id) === -1) {
0053                 return;
0054             }
0055 
0056             var payload = {
0057                 id: download.id,
0058                 bytesReceived: download.bytesReceived,
0059                 estimatedEndTime: download.estimatedEndTime,
0060                 // Firefox ends along "-1" as totalBytes on download creation
0061                 // but then never updates it, so we send this along periodically, too
0062                 totalBytes: download.totalBytes
0063             };
0064 
0065             port.postMessage({subsystem: "downloads", event: "update", download: payload});
0066         });
0067     });
0068 }
0069 
0070 function createDownload(download) {
0071     // don't bother telling us about completed downloads...
0072     // otherwise on browser startup we'll spawn a gazillion download progress notification
0073     if (download.state === "complete" || download.state === "interrupted") {
0074         return;
0075     }
0076 
0077     activeDownloads.push(download.id);
0078     startSendingDownloadUpdates();
0079 
0080     port.postMessage({subsystem: "downloads", event: "created", download: download});
0081 }
0082 
0083 function sendDownloads() {
0084     // When extension is (re)loaded, create each download initially
0085     chrome.downloads.search({
0086         state: 'in_progress',
0087     }, function (results) {
0088         results.forEach(createDownload);
0089     });
0090 }
0091 
0092 chrome.downloads.onCreated.addListener(createDownload);
0093 
0094 function onDownloadChanged(delta) {
0095     if (activeDownloads.indexOf(delta.id) === -1) {
0096         return;
0097     }
0098 
0099     // An interrupted download was resumed. When a download is interrupted, we finish (and delete)
0100     // the job but the browser re-uses the existing download, so when this happen,
0101     // pretend a new download was created.
0102     if (delta.state) {
0103         if (delta.state.previous === "interrupted" && delta.state.current === "in_progress") {
0104             console.log("Resuming previously interrupted download, pretending a new download was created");
0105             chrome.downloads.search({
0106                 id: delta.id
0107             }, function (downloads) {
0108                 createDownload(downloads[0]);
0109             });
0110             return;
0111         }
0112     }
0113 
0114     // The update timer stops automatically when there are no running downloads
0115     // so make sure to restart it when a download is unpaused
0116     if (delta.paused) {
0117         if (delta.paused.previous && !delta.paused.current) {
0118             startSendingDownloadUpdates();
0119         }
0120     }
0121 
0122     var payload = {};
0123 
0124     Object.keys(delta).forEach((key) => {
0125         payload[key] = delta[key].current;
0126     });
0127 
0128     payload.id = delta.id; // not a delta, ie. has no current and thus isn't added by the loop below
0129 
0130     port.postMessage({subsystem: "downloads", event: "update", download: payload});
0131 };
0132 
0133 addCallback("downloads", "cancel", function (message) {
0134     var downloadId = message.downloadId;
0135 
0136     console.log("Requested to cancel download", downloadId);
0137 
0138     chrome.downloads.cancel(downloadId);
0139 });
0140 
0141 addCallback("downloads", "suspend", function (message) {
0142     var downloadId = message.downloadId;
0143 
0144     console.log("Requested to suspend download", downloadId);
0145 
0146     chrome.downloads.pause(downloadId);
0147 });
0148 
0149 addCallback("downloads", "resume", function (message) {
0150     var downloadId = message.downloadId;
0151 
0152     console.log("Requested to resume download", downloadId);
0153 
0154     chrome.downloads.resume(downloadId);
0155 });
0156 
0157 addCallback("downloads", "createAll", () => {
0158     sendDownloads();
0159 });