Repository navigation
Releases: rainhuang0220/wePaper
Release list
v1.7.0 — Automatic Zotero sync
Automatic near-real-time Zotero synchronization and live catalog refresh.
What changed
- A background daemon polls Zotero
Last-Modified-Version, debounces writes, then reconciles the configured collection. Startup, a 5-minute reconcile, and sleep/wake catch-up cover missed events. - The previous LaunchAgent died on transient network errors (thousands of exit-1 respawns). The process now retries instead of exiting, and launchd uses an isolated venv plus crash-only KeepAlive.
wepaper daemon install|uninstall|statusandwepaper statusshow whether automatic sync is alive. The plist does not embed the sync token.- Public
GET /api/v1/library/version. An already-open catalog tab updates in place within a few seconds and keeps search/filters. Visibility/focus runs an immediate check.
wepaper sync --once remains for diagnostics and repair. It is not the normal workflow.
This is interval-based (seconds), not sub-100ms realtime.
v1.6.0 — mobile recovery, open status, paper discussions
What’s new
v1.6.0 recovers mobile reading and adds lightweight paper discussions. Desktop PDF behavior is unchanged.
- Mobile recovery. The broken v1.5 Android inline viewer is no longer the default. Every device uses Library →
/paper/:id→ 302 →/paper/:id/pdf. - Raw PDF fallback. Mobile may display the file in the browser or offer a download. That is the shipped safe path, not a bug. wePaper does not claim a reliable inline Android viewer.
- Reading status. 待泛读 / 待精读 / 泛读中 / 精读中 / 已泛读 / 已精读. Any visitor can set or clear a label from the catalog.
/owneris gone. - Discussions. Each paper has comments, one-level replies, and likes at
/paper/:id/discussion. Desktop and mobile:评论 · N. Mobile: long-press the title (a normal tap still opens the PDF). - No accounts. Status and comments are intentionally open for a small audience. Writes are validated; they are not authenticated.
- Test isolation. Automated status/comment tests use a fixture database. They do not write the production papers.
Tests
uv run pytest (83 passed). Playwright E2E on an isolated server (18 passed, 12 skipped opt-in benches).
Known limitation
No real Android Chrome/WebView inline viewer was verified. Mobile stays on raw PDF.
v1.5.0 — mobile inline reader and reading status
Superseded by v1.6.0. Mobile default is now 302 → raw PDF. Reading status is openly editable.
/ownerwas removed.
Summary (historical)
- Desktop still reads papers in the browser-native PDF viewer: Library →
/paper/:id→ 302 →/paper/:id/pdf. - Mobile opened the same canonical
/paper/:idURL in a lazy official Mozilla PDF.js viewer (pdfjs-dist@5.7.284). That default later failed on real Android (“The PDF could not be opened.”). /paper/:id/pdfremained rawapplication/pdf(Range / 206) on every device.- Owner reading-status labels (待泛读 / 待精读 / 泛读中 / 精读中 / 已泛读 / 已精读) were server-persisted and only editable after
/ownersign-in.
Production: https://wepaper.plainlist.space
Code commit: 4bdc8b47c3f37c4028388323211f1eb9afdbe414
Release commit: a4ce6edf873156f8e16b5f557d5a462091acc81b
v1.4.0
Summary
- Paper titles now open native PDF directly (
/paper/:id/pdf). /paper/:idredirects (HTTP 302) to the native PDF route.- Native PDF is now the default reading experience.
- The in-app PDF.js viewer is removed.
Notes
Click a catalog title to read the real PDF in the browser. Bookmarked /paper/:id URLs land on the same native PDF. There is no second “Open PDF” click and no in-app canvas viewer.
v1.3.0 — official PDF.js viewer
Default reader migrated from the custom canvas renderer to Mozilla's official PDF.js viewer layer (PDFViewer + EventBus + find/history/link services).
Clicking a paper title on https://wepaper.plainlist.space now opens /paper/:id in that mature reader immediately. Open PDF remains a secondary action for the raw /paper/:id/pdf bytes (browser-native view, print, download).
The old custom stack is gone (PdfReader, canvasScale 32M ceiling, zoomSteps, pdfWindow, findHits). Zoom, search, continuous scroll, and high-DPI detail canvas are owned by pdf.js. V1.2 Range transport and first-page timing are unchanged.
Public cold-open (click → readable page 1): desktop P50 1410 ms / P95 2365 ms; mobile P50 1350 ms / P95 2334 ms. Gate remains P50 ≤ 2.0 s / P95 ≤ 3.0 s.
Commit: d1a563e
Production JS: /assets/index-Bu5KI4pS.js
SHA-256: 6e966ea60288122193c93ef15f95faf9ef92c656d4b3443bafb1cefb77558f09
wePaper v1.2.2
wePaper v1.2.2
Follow-up to v1.2.1 after re-measuring against the real production IP (175.24.134.228). Clash’s fake-IP path had made v1.2.1 benches look faster than production.
Root cause
A single Range of ~378–512 KB on this path takes ~3.5 s. doc.getData() (Cache API persist) also started before the first canvas paint and contended with page 1.
Fix
- Custom
PDFDataRangeTransportthat never issues a Range larger than 256 KiB - Persist the full PDF only after
[data-ready=true] - Playwright benches pin DNS to
175.24.134.228
Isolated cold catalog click (real IP)
| Paper | Desktop | Mobile |
|---|---|---|
| 228 KB | 1336 ms | 846 ms |
| 2.7 MB | 1377 ms | 2360 ms |
| 1.9 MB | 1861 ms | 1343 ms |
| 5.6 MB | 1855 ms | 1855 ms |
Desktop P50 1.38 s / P95 1.86 s. Mobile P50 1.34 s / P95 2.36 s.
Warm reload of the 2.7 MB paper: 308 ms.
Public library: https://wepaper.plainlist.space
wePaper v1.2.1
wePaper v1.2.1
Follow-up to v1.2.0 after the adversarial review. Ordinary PDFs under 15 MB now meet the click → readable first page gate on production.
Performance
- Linearized serve copies (original Zotero checksums unchanged)
- Range-only PDF.js load (streaming a linearized file still waited on the full GET)
- Isolated cold catalog clicks, production Chromium:
| Paper | Desktop | Mobile |
|---|---|---|
| 228 KB | 839 ms | 840 ms |
| 2.7 MB | 2360 ms | 1849 ms |
| 1.9 MB | 1896 ms | 2863 ms |
| 5.6 MB | 2355 ms | 2854 ms |
Desktop P50 1.90 s / P95 2.36 s. Mobile P50 1.85 s / P95 2.86 s.
Warm reload of the 2.7 MB paper: 314 ms.
Fidelity
- Canvas pixel cap 32M so 300% on a 390×844 @3 viewport is a larger backing store than 200%
- Zoom still re-renders; continuous scroll / find / select unchanged
Cache
If-None-Match→ 304- Cache API persist after first page
Public library: https://wepaper.plainlist.space
wePaper v1.2.0
wePaper v1.2.0
Public library: https://wepaper.plainlist.space
First-page performance
- Reader mounts immediately (no metadata waterfall).
- PDF.js loads with Range only (
disableStream/disableAutoFetch), so page 1 is not held hostage to the rest of the file. - Gzip for JS/CSS (PDFs stay uncompressed so byte ranges stay valid).
- PDF.js worker is module-preloaded.
- nginx
proxy_cacheis off for this vhost — a cached206can no longer replace a PDF with a 64 KB fragment.
Target for ordinary small papers: click → readable first page P50 ≤ 2.0 s / P95 ≤ 3.0 s. Measured cold opens of a 228 KB paper: ~0.33–0.85 s.
PDF fidelity
- High-DPI canvas using
devicePixelRatio(cap 3, 16M pixel clamp). - Zoom 50–400% re-renders the page (not CSS stretch).
- Continuous vertical scroll, text layer, find, and select preserved.
Zotero sync
Unchanged: Local API → agent → server → public catalog.
Dedicated origin and repository
- Production: https://wepaper.plainlist.space
- Repository: https://github.com/rainhuang0220/wePaper
Security
Public read / bearer write. /openapi.json stays 404. PDF Cache-Control is private so shared proxies do not store Range fragments.