Files
zotero-notes-export-org/README.md
2026-02-17 21:25:46 +01:00

212 lines
6.9 KiB
Markdown

# Zotero Org Export Annotations
Export PDF and EPUB annotations from Zotero to Org-mode files for use with Emacs, org-roam, and citar.
## Features
- Export annotations to individual Org files named by citation key
- Automatic export after Zotero sync completes
- Export when closing a PDF/EPUB reader tab
- Configurable output directory
- Optional attachment of Org files to Zotero items
## Requirements
- **[Zotero](https://www.zotero.org/) 7.0+**
- **[Better Notes](https://github.com/windingwind/zotero-better-notes)** plugin — must be installed before this plugin
- **[Pandoc](https://pandoc.org/)** — for Markdown to Org conversion
## Installation
1. Install the **Better Notes** plugin first (see its own instructions)
2. Install **Pandoc** and ensure it is on your `PATH` (or note its full path)
3. Download the latest `.xpi` file from [Releases](../../releases)
4. In Zotero, go to **Tools → Add-ons**
5. Click the gear icon (top-right) and select **Install Add-on From File...**
6. Select the downloaded `.xpi` file and restart Zotero if prompted
## Configuration
After installation, open **Tools → Org Export Preferences** to configure:
| Preference | Default | Description |
| ----------------------- | --------- | --------------------------------------------------------------- |
| Notes Directory | _(empty)_ | Directory where Org files will be saved. Supports `~` for home. |
| Pandoc Path | `pandoc` | Full path to the pandoc binary if not on `PATH` |
| Attach Org file to item | `false` | Link exported Org files as Zotero attachments |
| Auto-export on sync | `true` | Export automatically after Zotero sync completes |
| Export on tab close | `true` | Export when closing a PDF/EPUB reader tab |
| Show notifications | `true` | Display a progress notification during export |
| Debug mode | `false` | Enable verbose logging to the Zotero error console |
## Usage
### Manual Export
- **Export all items**: **Tools → Export All Annotations to Org**
- **Export selected items**: Right-click one or more items → **Export Annotations to Org**
### Automatic Export
When enabled in preferences, exports happen automatically:
- After a Zotero sync completes (only items with new/changed annotations are exported)
- When you close a PDF or EPUB reader tab
### Output Format
Files are written to the configured Notes Directory, named by citation key:
```
~/org/notes/smith2020.org
~/org/notes/doe2019.org
```
Each file contains:
```org
#+title: The Full Title of the Referenced Work
* Annotation heading
Converted annotation text...
```
Only items that have a citation key (via Better BibTeX or the `citationKey` field) will be exported.
## For Maintainers
This section covers building, developing, and releasing the plugin.
### Architecture
```
src/
├── index.ts # Entry point: mounts addon to Zotero global
├── addon.ts # Core addon class (logging, init, module wiring)
├── hooks.ts # Lifecycle hooks (startup/shutdown, menu actions)
└── modules/
├── prefs.ts # Typed read/write for all preferences
├── exporter.ts # Attachment detection, sync checking, batch export
├── converter.ts # Markdown → Org via pandoc, file I/O
├── notifier.ts # Zotero event handlers (sync finish, tab close)
└── menu.ts # Menu registration (Zotero 7 + 8 compatible)
addon/ # Static plugin files copied verbatim into the XPI
├── manifest.json
├── bootstrap.js # Zotero plugin lifecycle entry point
├── prefs.js # Default preference values
└── content/
├── preferences.xhtml # Preferences pane UI (XUL)
├── scripts/preferences.js
├── icons/
└── locale/en-US/ # Fluent (.ftl) string bundles
```
The build system uses [zotero-plugin-scaffold](https://github.com/windingwind/zotero-plugin-scaffold) with esbuild, which bundles `src/` into a single `index.js` and packages everything as an XPI.
### Prerequisites
**With Nix (recommended):**
```bash
# Requires Nix with flakes enabled
nix develop
```
This provides Node.js 20, npm, TypeScript, ESLint, Prettier, and Pandoc.
**Without Nix:**
- Node.js 20+
- npm
- Pandoc (for manual testing)
```bash
npm install
```
### Environment Setup
Copy the environment template and fill in your local paths:
```bash
cp .env.example .env
```
Edit `.env`:
```bash
# Path to the Zotero binary (required for the dev server)
ZOTERO_PLUGIN_ZOTERO_BIN_PATH=/path/to/zotero
# Path to a Zotero development profile directory
ZOTERO_PLUGIN_PROFILE_PATH=/path/to/zotero-dev-profile
```
Create a dedicated Zotero profile for development to avoid affecting your main library.
### Development Workflow
```bash
# Start the dev server — builds and hot-reloads the plugin into a running Zotero instance
npm start
# One-off build — outputs XPI to .scaffold/build/
npm run build
# Lint TypeScript source
npm run lint
npm run lint:fix # auto-fix
# Format source files
npm run format
npm run format:check # check without writing
```
The dev server (`npm start`) watches for changes in `src/` and `addon/`, rebuilds, and reloads the plugin inside Zotero automatically. Zotero must already be running with the configured profile.
### Testing
There are no automated tests. To test manually:
1. `npm run build` to produce the XPI
2. Install the XPI in a Zotero 7 instance via **Tools → Add-ons → Install Add-on From File...**
3. Exercise the export functionality manually via the Tools menu and right-click context menu
### Releasing
Releases are created by pushing a version tag. The CI/CD pipeline (Gitea Actions) will build the XPI and publish a release automatically.
To cut a release locally:
```bash
npm run release
```
This runs [bumpp](https://github.com/antfu/bumpp) interactively to select the new version, then:
1. Updates `package.json` version
2. Commits and tags the version
3. Pushes the commit and tag to the remote
4. Builds the XPI
Once the tag is pushed, Gitea Actions takes over and creates the release with the XPI attached.
### Code Style
- **Formatter**: Prettier (config in `.prettierrc`) — double quotes, 2-space indent, semicolons
- **Linter**: ESLint with TypeScript-ESLint (config in `.eslintrc.js`) — strict mode
- **Naming**: PascalCase for classes/types, camelCase for functions/methods, UPPER_SNAKE_CASE for constants
- **Imports**: relative paths, `import type` for type-only imports, no namespace imports
- **Error handling**: always catch with a typed `error as Error`; use `_error` for non-critical ignores
See `AGENTS.md` for the full style guide used during AI-assisted development.
## License
GPL-3.0-or-later
## Credits
Based on the [zotero-plugin-template](https://github.com/windingwind/zotero-plugin-template) by windingwind.