-
Notifications
You must be signed in to change notification settings - Fork 1
/
background.js
181 lines (146 loc) · 5.34 KB
/
background.js
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
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
const doiRegex = new RegExp('10[.][0-9]{2,}(?:[.][0-9]+)*/(?:(?![%"#? ])\\S)+')
const stcUrl = "https://libstc.cc/#/stc/doi:"
const hubBaseUrl = new URL('https://hub.libstc.cc')
const trueRed = "#BC243C";
async function onInstalled(details) {
// add nexus option to context menu (right click)
await browser.contextMenus.create({
id: "nexus-doi-selection",
title: "Find article on Nexus!",
contexts: ["selection", "link"],
});
// open options page to choose autodownload if they want
if (details.reason === "install") {
await browser.runtime.openOptionsPage();
}
}
function getStcWebUrl(doi) {
return stcUrl + doi;
}
function getDownloadUrl(doi) {
return new URL(`${doi}.pdf`, hubBaseUrl);
}
const downloadDois = new Map();
async function handleDoi(doi) {
const optionsData = await browser.storage.sync.get("options");
const autodownload = optionsData?.options?.autodownload;
if (autodownload) {
const url = getDownloadUrl(doi);
console.log(`Attempting to download pdf from ${url}`)
const downloadId = await browser.downloads.download({
url: url.href,
filename: `${doi}.pdf`
});
if (!downloadId) {
console.log(`Download for ${url} failed to start`)
return
}
downloadDois.set(downloadId, doi);
console.log(`Started download with id ${downloadId} from ${url}`);
// if the PDF is not found it will typically instantly 404
// if PDF exists, it may take some time for iroh to locate
const timeout = (optionsData?.options?.timeout || 30) * 1000;
await new Promise(r => setTimeout(r, timeout));
if (downloadId) {
const downloads = await browser.downloads.search({id: downloadId});
const download = downloads[0];
if (!download) {
return;
}
const bytesReceived = download.bytesReceived;
console.log(`Received ${bytesReceived} after ${timeout} ms`);
const downloadStarted = bytesReceived !== 0;
if (!downloadStarted) {
// clean up if download failed to start
await handleDownloadFailed(downloadId)
}
}
} else {
const url = getStcWebUrl(doi);
console.log(`Opening STC in new tab: ${url}`)
await openTab(url);
}
}
async function openTab(url) {
await browser.tabs.create({
url: url
});
}
async function onNexusContextClick(info, tab) {
// if right-clicked on link, then parse link address first
let doi = info.linkUrl;
doi = doi ? doi.match(doiRegex)[0].split(";")[0] : doi;
// if link not valid, try the highlighted text
if (!doi) {
doi = info.selectionText;
}
await handleDoi(doi);
}
async function onMessage(request, sender, sendResponse) {
console.log(request);
if (request.openTab) {
await handleDoi(request.openTab);
} else if (request.fail) {
await browser.action.setBadgeTextColor({color: "white"});
await browser.action.setBadgeBackgroundColor({color: trueRed});
await browser.action.setBadgeText({text: ":'("});
}
}
async function onExtensionClick(tab) {
await browser.scripting.executeScript({
target: {tabId: tab.id},
func: async () => {
if (typeof browser === "undefined") {
browser = chrome;
}
const re = new RegExp('10[.][0-9]{2,}(?:[.][0-9]+)*/(?:(?![%"#? ])\\S)+')
let foundRegex = location.href.match(re);
if (!foundRegex) foundRegex = document.body.innerHTML.match(re);
if (foundRegex) {
let doi = foundRegex[0].split(";")[0];
doi = doi.replace(/\.pdf/, "");
await browser.runtime.sendMessage({openTab: doi});
} else {
await browser.runtime.sendMessage({fail: true});
}
}
});
}
async function onDownloadChanged(delta) {
if (!downloadDois.has(delta.id)) return
console.log(`download delta: ${JSON.stringify(delta)}`)
if (delta.state) {
if (delta.state.current === "complete") {
handleDownloadComplete(delta.id)
} else if (delta.state.current === "interrupted") {
await handleDownloadFailed(delta.id)
}
}
}
function handleDownloadComplete(id) {
console.log(`Download ${id} succeeded for doi ${downloadDois.get(id)}`)
downloadDois.delete(id)
}
async function handleDownloadFailed(id) {
const doi = downloadDois.get(id)
downloadDois.delete(id)
console.log(`Download ${id} failed for doi ${doi}`)
await browser.downloads.erase({id: id})
const url = stcUrl + doi;
console.log(`Opening STC in new tab: ${url}`)
await openTab(url);
}
async function resetBadgeText() {
await browser.action.setBadgeText({text: ""});
}
if (typeof browser === "undefined") {
browser = chrome;
}
browser.runtime.onInstalled.addListener(onInstalled);
// when nexus option in context menu is clicked
browser.contextMenus.onClicked.addListener(onNexusContextClick);
// when extension toolbar icon is clicked
browser.action.onClicked.addListener(onExtensionClick);
browser.runtime.onMessage.addListener(onMessage);
browser.downloads.onChanged.addListener(onDownloadChanged);
browser.tabs.onUpdated.addListener(resetBadgeText);