1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140
|
/*
Copyright (C) 2020 Kai Uwe Broulik <kde@broulik.de>
This program is free software; you can redistribute it and/or
modify it under the terms of the GNU General Public License as
published by the Free Software Foundation; either version 3 of
the License, or (at your option) any later version.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
function getFavicon(url) {
return new Promise((resolve) => {
// Specal favicon URL, needs "favicon" permission
// see https://bugs.chromium.org/p/chromium/issues/detail?id=104102
let faviconUrl = new URL(chrome.runtime.getURL("_favicon"));
faviconUrl.searchParams.append("pageUrl", url);
// TODO devicePixelRatio
faviconUrl.searchParams.append("size", 32);
fetch(faviconUrl.href, {
// Unfortunately "only-if-cached" is only possible with "same-origin" mode
cache: "force-cache"
}).then((response) => {
if (!response.ok) {
return resolve();
}
response.blob().then((blob) => {
let reader = new FileReader();
reader.onloadend = function() {
resolve(reader.result);
}
reader.readAsDataURL(blob);
}, (err) => {
console.warn("Failed to read response of", faviconUrl.href, "as blob", err);
resolve();
});
}, (err) => {
console.warn("Failed to get favicon from", faviconUrl.href, err);
resolve();
});
});
}
addCallback("historyrunner", "find", (message) => {
const query = message.query;
chrome.permissions.contains({
permissions: ["history"]
}, (granted) => {
if (!granted) {
sendPortMessage("historyrunner", "found", {
query,
error: "NO_PERMISSION"
});
return;
}
chrome.history.search({
text: query,
maxResults: 15,
// By default searches only the past 24 hours but we want everything
startTime: 0
}, (results) => {
let promises = [];
// Collect open tabs for each history item URL to filter them out below
results.forEach((result) => {
promises.push(new Promise((resolve) => {
chrome.tabs.query({
url: result.url
}, (tabs) => {
if (chrome.runtime.lastError || !tabs) {
return resolve([]);
}
resolve(tabs);
});
}));
});
Promise.all(promises).then((tabs) => {
// Now filter out the entries with corresponding tabs we found earlier
results = results.filter((result, index) => {
return tabs[index].length === 0;
});
// Now fetch all favicons from special favicon provider URL
// There's no public API for this.
// chrome://favicon/ works on Chrome "by accident", and for
// Firefox' page-icon: scheme there is https://bugzilla.mozilla.org/show_bug.cgi?id=1315616
if (IS_FIREFOX) {
return;
}
promises = [];
results.forEach((result) => {
promises.push(getFavicon(result.url));
});
return Promise.all(promises);
}).then((favicons) => {
if (favicons) {
favicons.forEach((favicon, index) => {
if (favicon) {
results[index].favIconUrl = favicon;
}
});
}
}).then((faviconData) => {
sendPortMessage("historyrunner", "found", {
query,
results
});
});
});
});
});
addCallback("historyrunner", "run", (message) => {
const url = message.url;
chrome.tabs.create({
url
});
});
addCallback("historyrunner", "requestPermission", () => {
chrome.tabs.create({
url: chrome.runtime.getURL("permission_request.html") + "?permission=history"
});
});
|