Skip to content

Releases: cannolis/ZotRead

v0.1.9

Choose a tag to compare

@cannolis cannolis released this 10 May 05:51

Fix: sidenav / section-header / prefs icon was rendering as a flat white blob because Zotero masks those slots and our favicon was a raster wrapped in SVG. Add a single-path vector section-icon.svg (Z-shape, currentColor) for those slots; the full-colour logo stays for the add-ons list.

v0.1.8

Choose a tag to compare

@cannolis cannolis released this 10 May 03:31

Fix: icon SVG no longer rendered at fixed 578×560 — scales properly into Zotero's small icon slots (sidenav, section header, prefs, add-ons list).

v0.1.7

Choose a tag to compare

@cannolis cannolis released this 10 May 03:18

Cosmetic: replace plugin icon with new ZotRead artwork. No functional changes.

v0.1.6

Choose a tag to compare

@cannolis cannolis released this 10 May 03:08

ZotRead v0.1.6 — dark mode + reliable pane auto-follow

Two issues fixed

1. Text invisible in dark mode

The WhyRead sidebar pane hardcoded color: #333 / #555 / #666 everywhere — readable on white, near-invisible on a dark theme. All hardcoded greys are gone; the pane now inherits the parent's theme color and uses opacity: 0.6/0.7/0.8/0.95 to differentiate emphasis levels. Works on both light and dark Zotero.

2. Auto-follow ZotRead pane when navigating items

Earlier versions tried to detect "is the user looking at ZotRead?" by calling getBoundingClientRect synchronously inside onItemChange. That doesn't work on Zotero 9 because Zotero resets the item-pane scroll before firing onItemChange — so the snapshot always saw "not visible" and the auto-follow never fired.

Replaced with an IntersectionObserver attached to the section element on onRender. The observer's last-reported state reflects the user's actual most-recent visibility, not the post-reset state. So:

  • Open ZotRead and read it → userPrefersZotRead = true → next item navigation auto-scrolls back to ZotRead
  • Scroll away to Info / Abstract / Tags → observer reports isIntersecting = false → next navigation doesn't drag you back
  • Collapse ZotRead section header → also drops the flag, observer is gated on section.open

Install

Same routine — download zot-read.xpi from this release, Tools → Add-ons → gear icon → Install Add-on From File….

v0.1.5

Choose a tag to compare

@cannolis cannolis released this 09 May 15:00

ZotRead v0.1.5 — fix prefs pane unreachable after v0.1.4

What was wrong

v0.1.3 fixed blank labels by switching from <groupbox onload> to a top-of-document <script>. v0.1.4 then added await document.readyState === "complete" to fix scope dropdown emptiness from the script-runs-during-parse race. Neither pattern is robust on Zotero 9 prefs panes — the latter ended up deadlocking because the prefs sub-frame's readyState may never transition to "complete", leaving the prefs pane completely unreachable.

Fix

Switched to the pattern used by windingwind/zotero-pdf-translate (proven on Zotero 7 and 9): root the prefs pane in a <vbox id="..." onload="...">. onload fires reliably on <vbox> (unlike <groupbox>) after the DOM is fully parsed, so DOM lookups in registerPrefsScripts find every widget on the first try, and FTL labels render before the script runs.

-<script>
-  Zotero.__addonInstance__.hooks.onPrefsEvent("load", { window });
-</script>
-<groupbox>
+<vbox
+  id="zotero-prefpane-__addonRef__-root"
+  onload="Zotero.__addonInstance__.hooks.onPrefsEvent('load', { window })"
+>
+<groupbox>
   ...
 </groupbox>
+</vbox>

The DOM-ready wait in registerPrefsScripts is no longer needed and is removed.

Install

Same as before — download zot-read.xpi and re-install via Tools → Add-ons → gear icon → Install Add-on From File….

v0.1.4

Choose a tag to compare

@cannolis cannolis released this 09 May 14:28

ZotRead v0.1.4 — fix scope dropdown empty after v0.1.3 prefs hook change

What was wrong

v0.1.3 fixed prefs blank labels by switching the load-hook trigger from <groupbox onload> to a top-of-document <script> block. That worked — labels show — but introduced a new issue: the <script> runs synchronously while the DOM is still being parsed, so by the time registerPrefsScripts calls getElementById('zotero-prefpane-zotread-scope-picker'), the <menulist> element below the script hasn't been parsed yet. Result: scope dropdown rendered as a blank widget with no options.

Fix

registerPrefsScripts now waits for document.readyState === "complete" before any DOM lookup. One short await; matches what zotero-better-notes does in its prefs script.

Note on "API key auto-filled after install"

Re-installing the plugin does NOT reset settings — Zotero/Firefox preserves user_pref() values across plugin uninstall/reinstall. The API key you see was your own paste from a previous install (v0.1, v0.1.1, v0.1.2 or v0.1.3) on that machine, not anything bundled with the xpi. Verified:

  • prefs.js inside the xpi has apiKey as empty string ""
  • The entire build output and git history contain zero sk- strings

To wipe a saved key: about:config → search extensions.zotero.zotread.llm.apiKey → right-click → Reset.

Install

Same as before — download zot-read.xpi and re-install via Tools → Add-ons → gear icon → Install Add-on From File….

v0.1.3

Choose a tag to compare

@cannolis cannolis released this 08 May 10:34

ZotRead v0.1.3 — really, actually, fix prefs blank labels

After v0.1.1 and v0.1.2 both failed to fix the blank-prefs-on-first-install issue (one made it worse, the other had no effect), I dug into how proven Zotero plugins like zotero-better-notes and zotero-pdf-translate structure their preferences.xhtml. The root cause was finally clear:

What was wrong

Our preferences.xhtml triggered the load hook via <groupbox onload="...">. This pattern stopped working reliably in Zotero 9's prefs framework — the onload event on the groupbox doesn't fire in time (or at all) on a fresh-profile open, so registerPrefsScripts never ran, FTL never got translated, and labels stayed blank.

Zotero-better-notes (the most-used Zotero plugin) uses a <script> block directly inside the prefs document to invoke the load hook synchronously when the document parses. Switched to that pattern.

What changed

addon/content/preferences.xhtml:

 <linkset>
   <html:link rel="localization" href="__addonRef__-preferences.ftl" />
 </linkset>
-<groupbox
-  onload="Zotero.__addonInstance__.hooks.onPrefsEvent('load', { window })"
->
+<script>
+  Zotero.__addonInstance__.hooks.onPrefsEvent("load", { window });
+</script>
+<groupbox>

The v0.1.2 preheat (insertFTLIfNeeded for prefs FTL on main window load) is kept as a belt-and-suspenders measure but is no longer the primary mechanism.

Install

Same as before — download the new zot-read.xpi and re-install via Tools → Add-ons → gear icon → Install Add-on From File…. Settings preserved.

If v0.1.3 still shows blank labels on a fresh profile, please open Zotero's Tools → Developer → Run JavaScript and paste:

Zotero.debug("[ZotRead] manual debug: " + JSON.stringify(Object.keys(Zotero.ZotRead || {})));

Then send me the output of /tmp/zotero-win.log — that lets me see whether the prefs hook fired at all.

v0.1.2

Choose a tag to compare

@cannolis cannolis released this 08 May 03:29

ZotRead v0.1.2 — really fix prefs blank on first install

v0.1.1 was supposed to fix the blank-prefs-on-first-install issue, but the fix made it worse: the prefs panel's labels stayed blank permanently, and clicking a dropdown no longer brought them back. v0.1.2 corrects that.

What was wrong in v0.1.1

MozXULElement.insertFTLIfNeeded was called on the prefs window itself. But preferences.xhtml already declares the FTL via <linkset rel="localization">, so the bundle ended up registered twice — and Firefox's l10n engine then refused to translate any of the elements at all.

The actual fix

  1. Main-window preheat (src/hooks.ts) — when Zotero's main window loads, the plugin now also pre-registers preferences.ftl so Firefox's l10n cache knows about it before the user ever opens Settings.
  2. Post-open re-translate (src/modules/preferenceScript.ts) — when the prefs pane opens, the plugin asks document.l10n to re-translate the DOM fragment. This is a no-op when everything is already wired up, but rescues the rare case where the bundle finished loading after first paint.

No double-registration. Tested on a fresh dev profile: prefs labels appear immediately.

Install

If you have v0.1 or v0.1.1 installed: download the new zot-read.xpi below and re-install via Tools → Add-ons → gear icon → Install Add-on From File… — your existing settings, anchors, and cache are preserved.

What changed

  • src/hooks.ts — onMainWindowLoad now also pre-registers zotread-preferences.ftl via insertFTLIfNeeded
  • src/modules/preferenceScript.ts — registerPrefsScripts calls document.l10n.translateFragment(documentElement) instead of insertFTLIfNeeded
  • package.json — version 0.1.1 → 0.1.2

v0.1.1

Choose a tag to compare

@cannolis cannolis released this 08 May 03:08

ZotRead v0.1.1 — bug fixes

Patch release fixing two issues reported on a fresh-profile install.

Fixes

  • Preferences pane labels blank on first install — On a fresh profile, opening Edit → Settings → ZotRead the very first time would show empty rows (just controls, no labels) until the user clicked anything. The plugin now force-loads its FTL into the preferences window on entry, so labels resolve immediately.

  • Cryptic TypeError when API key contains non-ASCII characters — If a pasted API key had a stray full-width space, smart quote, or IME-leftover Chinese character, "Rescore" would fail with TypeError: Headers.append: Cannot convert argument 2 to ByteString. The plugin now trims the key and validates it's pure ASCII before calling the LLM, with a clear error pointing at the offending character and position.

Install

If you already have v0.1 installed: download the new zot-read.xpi below and re-install it via Tools → Add-ons → gear icon → Install Add-on From File… — your existing settings, anchors, and cache are preserved.

Fresh install: same process, no v0.1 needed first.

What changed

  • src/services/llm.ts — readConfig() trims the API key; chat() validates ASCII before fetch
  • src/modules/preferenceScript.ts — registerPrefsScripts() calls MozXULElement.insertFTLIfNeeded for zotread-preferences.ftl on entry
  • package.json — version 0.1.0 → 0.1.1; author reverted to npm string format

v0.1

Choose a tag to compare

@cannolis cannolis released this 07 May 12:52

ZotRead v0.1

First public release.

What it does

ZotRead scores papers in your Zotero library by relevance to your own
published work or to a research-idea text, using any OpenAI-compatible LLM.

Features

  • Two anchor modes — mark your own papers as anchors, or write a research-idea text and rank against it
  • Sortable Relevance column in the main item list
  • WhyRead sidebar pane showing the rationale, referencing concrete methods and findings from both papers
  • Auto-maintained "ZotRead Top" collection containing the highest-scoring papers
  • Bring your own model — DeepSeek (default), OpenAI, OpenRouter, local Ollama, or any OpenAI-compatible endpoint
  • Local SQLite cache — re-evaluation is nearly free; English and Chinese rationales cached independently
  • Cost-aware — explicit scope selection, preview dialog showing the number of API calls, cancellable mid-run
  • Manual score override with the original LLM rationale preserved

Install

Download the zot-read.xpi asset below, then in Zotero: Tools → Add-ons → gear icon → Install Add-on From File… and select the .xpi.

Requirements

  • Zotero 7 or newer
  • An OpenAI-compatible LLM API key (DeepSeek by default; configurable)

Notes for first run

Before the first rescore, open Edit → Settings → ZotRead and:

  1. Paste your API key
  2. Pick a Ranking scope (a collection or "My library") — required, no default
  3. Either mark a paper as "my paper" (right-click → ZotRead → Mark as my paper) or add a research idea
  4. Click Rescore all now — a preview dialog will show the number of API calls before anything runs

🤖 Built with zotero-plugin-template