Annotator Explorer Companion

approved

by Charles Zhao Changlin

Right-click a PDF or EPUB to create its Annotator note and open it in annotation view in one step. - This plugin has not been manually reviewed by Obsidian staff.

1 stars53 downloadsUpdated 18d agoMIT

Annotator Explorer Companion

Built on Annotator by Elias Sundqvist. Annotator does the real work: it brings Hypothesis into Obsidian and keeps every highlight as plain markdown in your own vault instead of on someone else's server. Thanks to Elias for building and maintaining it.

This plugin adds one thing on top. Right-click a PDF or EPUB, choose Annotate, and you land in the reader ready to highlight. Install Annotator first, since nothing here runs without it.

What it replaces

Annotator keeps highlights in a markdown note that points at the document. Writing that note by hand means creating a file beside the PDF, typing its vault-relative path into YAML frontmatter without typos, opening the note, then switching views through the top-right menu. This plugin does all of that from one right-click.

Why I wrote it

I was reading through a folder of research papers and kept hitting the same friction.

Annotator needs a note whose frontmatter carries annotation-target, and nothing in the interface tells you so. Right-clicking a PDF offers nothing about annotation. Opening one gives you Obsidian's ordinary PDF viewer with no way in. The reason is in Annotator's source, where its own menu handler is gated three ways:

leaf?.view instanceof MarkdownView       // an open note, not a file in the explorer
  && file instanceof TFile
  && this.getPropertyValue("annotation-target", file)   // which already has the field

The item only shows up on notes that are already configured, so it can never get you started from a PDF.

Worse, getting the note slightly wrong produces a blank pane and no error. My first attempt used a code fence instead of frontmatter, backticks where dashes belong, and Annotator saw no target at all. At least six different mistakes produce that same blank pane:

CauseWhy it fails
Code fence instead of ---Field never parsed
:: inside YAML frontmatterFrontmatter takes one colon; :: is a Dataview body field
Leading slash on the pathNot resolvable from the vault root
Doubled extension (.pdf.pdf)Path does not match the file on disk
Missing or misleading extensionWrong reader selected
Source renamed after annotatingHighlights resolve by path and are orphaned

Generating the frontmatter removes that whole category of mistake. And once you are doing this for twenty papers rather than one, the repetition is reason enough on its own.

The bug that took longest to find

Version 1.0.0 created the note correctly and still opened it as plain markdown, so you had to visit the top-right menu anyway. Half the point was missing.

Annotator ships annotationModeByDefault: true and patches setViewState to redirect qualifying notes into its own view. The patch gates on getPropertyValue, which reads Obsidian's metadata cache. Obsidian parses frontmatter asynchronously, so a note written and opened in the same tick is not in that cache yet. The check comes back undefined and the note opens as markdown.

That mechanism is fine for notes that already exist, which is why it looked correct when I first read the source. It only fails on freshly created files, and those are the only kind this plugin makes.

The fix has two parts. waitForTargetField polls the metadata cache every 25 ms, up to two seconds, before opening the note, so Annotator's own auto-switch fires normally. ensureAnnotationView then checks the leaf and, if it somehow came back as markdown, asks for type: "pdf-annotator" directly. Annotator's patch only intercepts type: "markdown", so that request passes straight through to the registered view.

If the cache never populates, the note still opens and a notice points you at the manual menu.

Why a separate plugin

Annotator ships minified, so patching it directly would be unreviewable and the next update would overwrite the change. Registering a second menu handler leaves Annotator alone and keeps this code readable.

Safety

Annotation data is painful to reconstruct, so the plugin will not destroy it.

An existing note is opened rather than overwritten. A note containing annotation-json is never modified, even when its frontmatter looks incomplete. If a same-named note exists for unrelated reasons, only the field is added through processFrontMatter and the body is left alone. Paths are quoted and escaped so a title containing : or " cannot corrupt the YAML. Each of these has a test behind it.

Installing

Search for Annotator Explorer Companion under Settings, Community plugins, Browse.

To install by hand, download main.js and manifest.json from the latest release into <vault>/.obsidian/plugins/annotator-explorer-companion/ and enable it under Community plugins.

Release assets carry GitHub artifact attestations, so you can verify they were built from this repository:

gh attestation verify main.js --repo ZharlieSineFine/annotator-explorer-companion

Development

Plain JavaScript, no build step. Edit main.js and reload Obsidian.

node --test test.js

Twelve tests cover menu registration, note creation, the metadata-cache race, view switching, and every safety rule above. The suite stubs the obsidian module, so it runs without Obsidian installed.

Undocumented APIs

Two Obsidian internals are used here, both guarded with optional chaining and a fallback. app.plugins.plugins and app.plugins.enabledPlugins check whether Annotator is active, and if the registry cannot be read the plugin proceeds instead of blocking. pdfAnnotatorFileModes on the Annotator instance is written only on the fallback path, to keep Annotator's own mode tracking consistent.

Neither is part of Obsidian's public API and either could break in a future release. When that happens the plugin opens the note in markdown rather than failing outright.

Limitations

Annotator does not run on iOS 16.3 or later, so this does not either. Annotations made on iOS will not match ones made on desktop, because iOS percent-encodes spaces in annotation URIs and desktop does not (see issue #89). Notes are always created beside their source file, with no setting to change that yet. Remote https:// targets have no file to right-click and still need a note written by hand.

Credits and license

Annotator by Elias Sundqvist, building on Hypothesis. All annotation functionality is theirs. This is an unaffiliated companion and is not endorsed by the Annotator project.

MIT.

For plugin developers

Search results and similarity scores are powered by semantic analysis of your plugin's README. If your plugin isn't appearing for searches you'd expect, try updating your README to clearly describe your plugin's purpose, features, and use cases.