paperful

Fill the gaps in your Zotero library.

Fetch the PDFs your items are missing. Keep them in a folder tree that mirrors your collections. Attach them back. Work stays on disk. Zotero is a library adapter, not the whole product.

The briefing for missing PDFs

Open access first. Campus EZProxy when you have a subscription. Sci-Hub is opt-in and off by default.

On disk first

Downloads land under out/. Resume lives in state/. Zotero is read in, then written back — attach and metadata apply are separate steps.

Routed sources

Each item only hits sources that match its metadata unless you pass --try-all. A circuit breaker skips blocked sources for the rest of the run.

Campus when you have it

Log in once with headed Chromium. EZProxy uses your library entitlement. Passwords never live in TOML.

Grey literature

Playbooks rewrite UN, FAO, ISA, and similar landings to PDFs. Optional HTML→PDF covers blogs and news pages.

What can I do with it?

  • Fill a collection (or the whole library) with missing PDFs
  • Keep a folder tree that matches Zotero collections
  • Lint DOIs and propose metadata patches on disk
  • Use campus EZProxy without storing your password
  • Opt in to Sci-Hub only when you choose to

Walkthrough: commands. Not sure if this is the right tool? comparison · architecture.

On your machine

paperful is a local CLI. Catalogue reads and PDF writes go through Zotero’s local API. Session cookies stay under state/sessions/. Sci-Hub stays off until you add it to sources or pass --scihub.

From a checkout to a filled collection

  1. Copy config.example.toml, set email and out_dir, then run paperful doctor.
  2. List collections with “No PDF” counts: paperful collections.
  3. Dry-run a collection, then fetch and attach.
  4. Optionally log in to EZProxy or Scholar before a big run.

Commands · Config · EZProxy · Sessions

Install

Python 3.10+ and uv. Zotero running with the local API enabled.

git clone https://github.com/glen-w/Paperful.git
cd Paperful
uv sync
cp config.example.toml config.toml
uv run paperful doctor
uv run paperful run --collection interesting --dry-run

Details: Documentation · 0.x / 1.0 · README