Skip to content

Commit d3220c9

Browse files
committed
feat: convert to bibtex code using Zotero exporter
1 parent 81a0ee8 commit d3220c9

7 files changed

Lines changed: 2325 additions & 880 deletions

File tree

background.js

Lines changed: 123 additions & 74 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
1-
import { createTranslateEngine } from "./sources/translateEngine.js";
1+
import { createTranslateEngine, exportItems } from "./sources/translateEngine.js";
22

33
// Provide a minimal compatibility shim: if `browser` is missing, alias it to `chrome`.
44
if (typeof browser === "undefined" && typeof chrome !== "undefined") {
@@ -198,91 +198,140 @@ async function initContentScript(tabId) {
198198
});
199199
}
200200

201-
async function onPopupOpened(tab, info, sendResponse) {
201+
async function onPopupOpened(tab, info) {
202202
if (!info.translators.length) throw new Error("No translator paths provided");
203203

204204
// If offscreen is available (Chrome), forward the request so the offscreen
205205
// document runs the translator. If not (Firefox), run the translator
206206
// from the content script (which has a DOM available, unlike the background page).
207-
try {
208-
if (browser.offscreen) {
209-
await initOffscreenDocument();
210-
} else {
211-
await initContentScript(tab.id);
212-
}
213-
await browser.tabs.sendMessage(tab.id, {
214-
type: "runTranslators",
215-
url: tab.url,
216-
translatorsInfo: info.translators.map((translator) => {
217-
// We cannot send the full translator object as it contains functions
218-
return {
219-
translatorID: translator.translatorID,
220-
translatorType: translator.translatorType,
221-
label: translator.label,
222-
creator: translator.creator,
223-
target: translator.target,
224-
priority: translator.priority,
225-
path: translator.path,
226-
file: translator.file,
227-
lastUpdated: translator.lastUpdated,
228-
};
229-
}),
230-
});
231-
} catch (e) {
232-
sendResponse({ ok: false, error: String(e) });
233-
console.log(`JabRef: Failed to run translators for tab ${tab.id}: ${e}`);
234-
return;
207+
if (browser.offscreen) {
208+
await initOffscreenDocument();
209+
} else {
210+
await initContentScript(tab.id);
235211
}
236-
return;
212+
await browser.tabs.sendMessage(tab.id, {
213+
type: "runTranslators",
214+
url: tab.url,
215+
translatorsInfo: info.translators.map((translator) => {
216+
// We cannot send the full translator object as it contains functions
217+
return {
218+
translatorID: translator.translatorID,
219+
translatorType: translator.translatorType,
220+
label: translator.label,
221+
creator: translator.creator,
222+
target: translator.target,
223+
priority: translator.priority,
224+
path: translator.path,
225+
file: translator.file,
226+
lastUpdated: translator.lastUpdated,
227+
};
228+
}),
229+
});
237230
}
238231

239-
browser.runtime.onMessage.addListener(async function (message, sender, sendResponse) {
240-
if (message.type === "popupOpened") {
241-
// The popup opened, i.e. the user clicked on the page action button
242-
console.log("JabRef: Popup opened confirmed");
232+
async function getConversionMode() {
233+
const cfg = await browser.storage.sync.get({ exportMode: "bibtex" });
234+
return cfg.exportMode || "bibtex";
235+
}
243236

244-
browser.tabs
245-
.query({
246-
active: true,
247-
currentWindow: true,
248-
})
249-
.then(async (tabs) => {
250-
var tab = tabs[0];
251-
var info = tabInfo.get(tab.id);
237+
async function prepareForExport(items) {
238+
const { takeSnapshots } = await browser.storage.sync.get({ takeSnapshots: false });
239+
240+
for (var i = 0; i < items.length; i++) {
241+
var item = items[i];
242+
for (var j = 0; j < item.attachments.length; j++) {
243+
var attachment = item.attachments[j];
252244

253-
if (info && info.isPDF) {
254-
console.log("JabRef: Export PDF in tab %o", JSON.parse(JSON.stringify(tab)));
255-
savePdf(tab);
256-
} else if (!info.translators) {
257-
console.log("JabRef: No translators, simple saving %o", JSON.parse(JSON.stringify(tab)));
258-
saveAsWebpage(tab);
245+
var isLink =
246+
attachment.mimeType === "text/html" || attachment.mimeType === "application/xhtml+xml";
247+
if (isLink && attachment.snapshot !== false) {
248+
// Snapshot
249+
if (takeSnapshots && attachment.url) {
250+
attachment.localPath = attachment.url;
259251
} else {
260-
console.log("JabRef: Start translation for tab %o", JSON.parse(JSON.stringify(tab)));
261-
await onPopupOpened(tab, info, sendResponse);
252+
// Ignore
262253
}
254+
} else {
255+
// Normal file
256+
// Pretend we downloaded the file since otherwise it is not exported
257+
if (attachment.url) {
258+
attachment.localPath = attachment.url;
259+
}
260+
}
261+
}
262+
263+
// Fix date string
264+
if (item.accessDate) {
265+
item.accessDate = new Date().toISOString();
266+
}
267+
}
268+
}
269+
270+
browser.runtime.onMessage.addListener(async function (message, sender, _sendResponse) {
271+
try {
272+
if (message.type === "popupOpened") {
273+
// The popup opened, i.e. the user clicked on the page action button
274+
console.log("JabRef: Popup opened confirmed");
275+
const tabs = await browser.tabs.query({
276+
active: true,
277+
currentWindow: true,
263278
});
264-
} else if (message.type === "COHTTP.request") {
265-
const { method, url, options } = message;
266-
console.debug(`JabRef: COHTTP request in background.js: ${method} ${url} %o`, options);
267-
const xhr = await Zotero.HTTP.request(method, url, options);
268-
// From upstream: https://github.com/zotero/zotero-connectors/blob/ea060a0aa2fea1267049b5fc880e53aa6c915eeb/src/common/messages.js#L302-L316
269-
let result = {
270-
response: xhr.response,
271-
responseType: xhr.responseType,
272-
status: xhr.status,
273-
statusText: xhr.statusText,
274-
responseHeaders: xhr.getAllResponseHeaders(),
275-
responseURL: xhr.responseURL,
276-
};
277-
return result;
278-
} else if (message.eval) {
279-
console.debug("JabRef: eval in background.js: %o", JSON.parse(JSON.stringify(message.eval)));
280-
return evalInTab(sender.tab.id, message.eval);
281-
} else if (message[0] === "Debug.log") {
282-
console.log(message[1]);
283-
} else if (message[0] === "Errors.log") {
284-
console.log(message[1]);
285-
} else {
286-
console.log("JabRef: other message in background.js: %o", JSON.parse(JSON.stringify(message)));
279+
var tab = tabs[0];
280+
var info = tabInfo.get(tab.id);
281+
282+
if (info && info.isPDF) {
283+
console.log("JabRef: Export PDF in tab %o", JSON.parse(JSON.stringify(tab)));
284+
savePdf(tab);
285+
} else if (!info.translators) {
286+
console.log("JabRef: No translators, simple saving %o", JSON.parse(JSON.stringify(tab)));
287+
saveAsWebpage(tab);
288+
} else {
289+
console.log("JabRef: Start translation for tab %o", JSON.parse(JSON.stringify(tab)));
290+
await onPopupOpened(tab, info);
291+
}
292+
293+
return { ok: true };
294+
} else if (message.type === "COHTTP.request") {
295+
const { method, url, options } = message;
296+
console.debug(`JabRef: COHTTP request in background.js: ${method} ${url} %o`, options);
297+
const xhr = await Zotero.HTTP.request(method, url, options);
298+
// From upstream: https://github.com/zotero/zotero-connectors/blob/ea060a0aa2fea1267049b5fc880e53aa6c915eeb/src/common/messages.js#L302-L316
299+
let result = {
300+
response: xhr.response,
301+
responseType: xhr.responseType,
302+
status: xhr.status,
303+
statusText: xhr.statusText,
304+
responseHeaders: xhr.getAllResponseHeaders(),
305+
responseURL: xhr.responseURL,
306+
};
307+
return result;
308+
} else if (message.type === "offscreenResult") {
309+
console.debug("JabRef: offscreenResult in background.js: %o", message);
310+
if (message.error) {
311+
await browser.runtime.sendMessage({ type: "offscreenResult", url, error: message.error });
312+
return;
313+
}
314+
const { url, items } = message;
315+
const conversionMode = await getConversionMode();
316+
await prepareForExport(items);
317+
await browser.runtime.sendMessage({ onConvertToBibtex: "convertStarted" });
318+
const bib = await exportItems(items, conversionMode);
319+
console.debug("JabRef: Exported BibTeX: %o", bib);
320+
} else if (message.eval) {
321+
console.debug("JabRef: eval in background.js: %o", JSON.parse(JSON.stringify(message.eval)));
322+
return evalInTab(sender.tab.id, message.eval);
323+
} else if (message[0] === "Debug.log") {
324+
console.log(message[1]);
325+
} else if (message[0] === "Errors.log") {
326+
console.log(message[1]);
327+
} else {
328+
console.log(
329+
"JabRef: other message in background.js: %o",
330+
JSON.parse(JSON.stringify(message)),
331+
);
332+
}
333+
} catch (e) {
334+
console.error("JabRef: Error handling message in background.js", e);
335+
throw e;
287336
}
288337
});

0 commit comments

Comments
 (0)