File indexing completed on 2024-04-28 05:32:50
0001 /* 0002 Copyright (C) 2017 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 // URL - data URL 0019 let favIconDataForUrl = {}; 0020 let clearFavIconDataTimeoutId = 0; 0021 let runningGetTabsQueries = 0; 0022 0023 addCallback("tabsrunner", "activate", function (message) { 0024 var tabId = message.tabId; 0025 0026 console.log("Tabs Runner requested to activate tab with id", tabId); 0027 0028 raiseTab(tabId); 0029 }); 0030 0031 addCallback("tabsrunner", "setMuted", function (message) { 0032 0033 var tabId = message.tabId; 0034 var muted = message.muted; 0035 0036 chrome.tabs.update(tabId, {muted: muted}, function (tab) { 0037 0038 if (chrome.runtime.lastError || !tab) { // this "lastError" stuff feels so archaic 0039 // failed to mute/unmute 0040 return; 0041 } 0042 }); 0043 0044 }); 0045 0046 // only forward certain tab properties back to our host 0047 var whitelistedTabProperties = [ 0048 "id", "active", "audible", "favIconUrl", "incognito", "title", "url", "mutedInfo" 0049 ]; 0050 0051 // FIXME We really should enforce some kind of security policy, so only e.g. plasmashell and krunner 0052 // may access your tabs 0053 addCallback("tabsrunner", "getTabs", function (message) { 0054 ++runningGetTabsQueries; 0055 0056 chrome.tabs.query({ 0057 windowType: "normal" 0058 }, (tabs) => { 0059 if (clearFavIconDataTimeoutId) { 0060 clearTimeout(clearFavIconDataTimeoutId); 0061 clearFavIconDataTimeoutId = 0; 0062 } 0063 0064 // remove incognito tabs and properties not in whitelist 0065 let filteredTabs = tabs; 0066 0067 // Firefox before 67 runs extensions in incognito by default 0068 // but we keep running after an update, so exclude those tabs for it 0069 if (IS_FIREFOX) { 0070 filteredTabs = filteredTabs.filter(function (tab) { 0071 return !tab.incognito; 0072 }); 0073 } 0074 0075 filteredTabs = filterArrayObjects(filteredTabs, whitelistedTabProperties); 0076 0077 let favIconUrlsToFetch = new Set(); 0078 0079 // Collect a set of fav icons to be requested 0080 filteredTabs.forEach((tab) => { 0081 const url = tab.favIconUrl; 0082 if (!url) { 0083 return; 0084 } 0085 0086 // Already a data URL 0087 if (url.match(/^data:image/)) { 0088 return; 0089 } 0090 0091 // Already in cache 0092 if (favIconDataForUrl[url]) { 0093 return; 0094 } 0095 0096 favIconUrlsToFetch.add(url); 0097 }); 0098 0099 // Prepare the download requests for all fav icons 0100 let requests = []; 0101 favIconUrlsToFetch.forEach((url) => { 0102 requests.push(new Promise((resolve) => { 0103 fetch(url, { 0104 cache: "force-cache" 0105 }).then((response) => { 0106 if (!response.ok) { 0107 return resolve(); 0108 } 0109 0110 response.blob().then((blob) => { 0111 let reader = new FileReader(); 0112 reader.onloadend = function() { 0113 favIconDataForUrl[url] = reader.result; 0114 return resolve(); 0115 } 0116 reader.readAsDataURL(blob); 0117 }, (err) => { 0118 console.warn("Failed to read response of", url, "as blob", err); 0119 resolve(); 0120 }); 0121 }, (err) => { 0122 console.warn("Failed to get favicon from", url, err); 0123 resolve(); 0124 }); 0125 })); 0126 }); 0127 0128 // Download all favicons and send them out 0129 Promise.all(requests).then(() => { 0130 filteredTabs = filteredTabs.map((tab) => { 0131 const favIconUrl = tab.favIconUrl; 0132 if (!favIconUrl) { 0133 return tab; 0134 } 0135 0136 if (favIconUrl.match(/^data:image/)) { 0137 tab.favIconData = favIconUrl; 0138 return tab 0139 } 0140 0141 const data = favIconDataForUrl[favIconUrl]; 0142 if (data) { 0143 tab.favIconData = data; 0144 } 0145 return tab; 0146 }); 0147 0148 --runningGetTabsQueries; 0149 if (runningGetTabsQueries === 0) { 0150 clearFavIconDataTimeoutId = setTimeout(() => { 0151 favIconDataForUrl = {}; 0152 clearFavIconDataTimeoutId = 0; 0153 }, 60000); 0154 } 0155 0156 port.postMessage({ 0157 subsystem: "tabsrunner", 0158 event: "gotTabs", 0159 tabs: filteredTabs 0160 }); 0161 }); 0162 }); 0163 });