尚未偵測到更新。GitHub 發布版本後會顯示在這裡。
個人 GitHub 帳號下公開儲存庫的擁有者可以登入並驗證所有權,自行管理介紹,無需管理員核准。
登入並產生驗證檔案,在 30 分鐘內將其提交至此儲存庫的預設分支。其他分支或分叉儲存庫中的檔案無效。然後在下方檢查檔案,即可無需管理員核准直接管理專案。請保留檔案以維持管理權限。
如需登入,將前往登入頁面。登入後請回到此處,再次點擊所選的驗證按鈕。
在專案資料夾中執行 /nomorevibe verify,即可驗證所有權並自行管理介紹。
一分鐘完成驗證本機專用的 EPUB 與 PDF 閱讀器,支援 OPDS、離線 PWA 與 Omarchy 整合。無需帳號或雲端圖書館。
AI 翻譯
Local-only EPUB and PDF reader with OPDS, offline PWA and Omarchy integration. No accounts or cloud library.
取自儲存庫 README
正在載入完整 README。 以下為已儲存的摘錄。
A quiet, lightweight ebook reader. Open books.skriv.ist
A static SPA that runs in your browser. No account, backend, cloud library, or uploads; page visits are counted with cookie-free Cloudflare Web Analytics. Separate from app.skriv.ist. Every installation starts empty; no personal books, folders, credentials, or server configuration are bundled.檢視完整 README ↗A quiet, lightweight ebook reader. Open books.skriv.ist
A static SPA that runs in your browser. No account, backend, cloud library, or uploads; page visits are counted with cookie-free Cloudflare Web Analytics. Every installation starts empty; no personal books, folders, credentials, or server configuration are bundled.
Use arrow keys or Page Up/Down to turn pages and Escape to return to the shelf. Mark a book read when finished; marking it unread resets its reading position. File imports are limited to 128 MB each; encrypted/DRM-protected books are not supported. EPUB presentation is adapted for readable, safe text rather than reproducing publisher layouts or scripts.
Select text in an EPUB or text-based PDF, then choose Add note. Add your own thoughts, or save a quotation by itself. You can also add a note without a selection at the current chapter/spread or PDF page. Notes lists the book’s annotations, lets you edit them, and jumps back to their locations. Scanned PDFs without a text layer support page notes but not text selection; OCR is not included.
Notes are stored locally in IndexedDB. In Obsidian destination, enter your vault name and a folder within it (default Reading). Save & open Obsidian saves the note locally and passes Markdown to the installed Obsidian app using its built-in URI handler. No community plugin, API key, account, vault scanning, or book upload is needed. Spaces in Obsidian links use %20, preserving spaces in filenames and note text. Notes exported by v1.1.0 may already contain literal + characters: rename or edit those copies in Obsidian, or export the saved local note again. The app does not modify existing vault files. The browser may ask to open Obsidian. It cannot confirm that Obsidian completed the write.
Exports include title, author, quotation, your note, reading location, and a link back to that location. The same book file must be present in the browser at the linked reader origin. The EPUB location is a chapter and proportional spread position, so a different font size or screen width may change the visible text around it. Export is one-way; it never requests overwriting existing Obsidian files. To edit an exported copy, use Obsidian, or export another copy. Large notes that exceed app-link limits can be downloaded as Markdown; Download all Markdown exports a book’s notes together. Keep exported backups: removing a book deletes its local notes too.
In Notes, choose Anki ↓ for one saved note or Export all to Anki for the book. This downloads a UTF-8 CSV; nothing is sent to a server or AnkiWeb. In desktop Anki, choose File → Import, select the CSV and a standard two-field Basic note type, map Front/Back if needed, and choose your deck. Anki 2.1.54+ reads the included separator, HTML, field, and tag headers automatically.
The quotation becomes the front; your note, title, author, location, and return link become the back. A note without a quotation uses a question about that reading location as its front. Edit the cards in Anki to refine your questions. Text is escaped before HTML formatting, so imported book text and notes cannot load remote images or inject markup. Cards get the skrivist-books tag. Anki matches duplicates by the first field: review its duplicate settings when importing repeated quotations or re-exporting. This is a file export, not live synchronization.
Open Calibre → Choose library folder and select the library root containing metadata.db. Close Calibre first so its database is fully saved. The reader opens a read-only, in-memory SQLite snapshot in a background worker. Nothing is uploaded or written back, and no library is connected automatically.
Browse 24 books per page. Search titles, authors, series, or tags and filter by EPUB/PDF. Read EPUB / Read PDF reads only that file and saves it in this browser for offline reading. Calibre's title and author are used when adding a new book. A previously imported identical file retains its notes and reading progress. Other formats are listed; convert them in Calibre before reading. Calibre's own annotations, custom columns, and reading positions are not synchronized.
On browsers supporting the File System Access API, folder access is read-only and files are resolved on demand without recursively scanning the library. Use compatible folder picker works in other browsers; it enumerates filenames but reads book contents only when you choose a book. Both methods require explicit folder selection. Metadata and folder references remain in this page's memory and are released when you reload or disconnect; already opened books remain in your browser library.
Use Refresh library after changing metadata in Calibre (close Calibre again first). The compatible picker asks you to select the folder again for a fresh snapshot. Database snapshots are limited to 64 MB; pending SQLite WAL/journal files are rejected to avoid displaying an incomplete snapshot. Path traversal outside the selected root is rejected. A missing or moved book reports an error rather than searching other folders. For larger or remotely hosted libraries, use Calibre's OPDS feed through Catalogues instead.
Add your own OPDS 1 (Atom) or OPDS 2 catalogue in Catalogues. Save connections and individual shelves. Browse 24 entries at a time; server pagination is followed only when needed. Book files download only when you press Read book, then remain available locally.
Requests go directly from your browser to your catalogue. The server must permit CORS for your reader's origin (including the Authorization header for Basic or token login). The public HTTPS app needs an HTTPS catalogue. To use a local HTTP catalogue, run the local app below and allow its origin on your server. There is no public proxy.
Passwords remain in memory for the current session, scoped to the catalogue's connection URL and username, so two catalogues on one server never share them; they are never saved. A password without a username is sent as Basic login, which Armarium accepts for a token. An Armarium pairing token (the /opds/t/<token>/ part or the ?token= value of a pairing link or typed URL) is moved into an Authorization: Bearer header, so it never appears in a request URL, history, the form, a saved shelf's URLs or a downloaded book's record. A pairing link that opens Catalogues fills in only the plain catalogue URL, and a whole pairing link (https://books.skriv.ist/#opds=… or skrivist-books://pair#opds=…) pasted into the URL field connects to the catalogue inside it. On a computer, the link in the This computer section of Armarium Admin's pairing panel opens the desktop app with the catalogue filled in; press Connect there. The token is kept on this device in its own field of each saved shelf, so a paired shelf opens again after a reload. It is one token per library: pairing again gives the new token to every shelf saved from that catalogue. Forgetting a shelf deletes it; forgetting the catalogue's own shelf forgets every shelf saved from it, with the token. The token is only ever sent to the catalogue's own origin: a feed link that would carry it to another server is dropped, and a fetch of one is refused. Shelves and books saved by an earlier version with the token inside their URLs are rewritten the same way the next time they are read. Feed URLs of other servers may still carry access tokens in a query string, so treat this browser profile as private. Redirects are disabled to prevent credential forwarding; enter the final feed URL. A server without pagination still sends its metadata listing, but books are always fetched individually.
Install the webapp launcher and Custom → Skrivist Books entry:
git clone https://github.com/gandtr/books.skriv.ist.git
cd books.skriv.ist
python3 scripts/install-omarchy.py
This preserves other menu entries and backs up the menu before editing. It creates skrivist-books-spa.desktop, so existing local ebook services are not replaced.
An optional bar widget is included in manifest.json and omarchy/Books.qml. Install with omarchy plugin add https://github.com/gandtr/books.skriv.ist.git --yes, then optionally run omarchy plugin enable skrivist.books. It launches the app and does not scan or import any files. The url setting can point at a local installation.
npm ci
npm run build
python3 scripts/serve-local.py --port 8580
python3 scripts/install-omarchy.py --url http://127.0.0.1:8580
The optional server binds loopback and serves only dist/. It does not read ebook folders or expose an API. Book files still come only from explicit browser file selection or your chosen OPDS catalogue. For automatic startup, run this command as a systemd user service.
Node 22.12 or newer:
npm ci
npm run dev
npm run check
npm test
npm run build
Tests use generated fixtures, never a personal library. dist/ is the entire deployable app. Deploy it to any static host with SPA fallback and the supplied _headers. The service worker caches the shell and first-party runtime assets only, not OPDS requests or credentials.
Deployments are manual. .github/workflows/deploy.yml runs checks, tests, and the build before uploading to the Cloudflare Pages project books-skriv-ist. Configure CLOUDFLARE_API_TOKEN and CLOUDFLARE_ACCOUNT_ID repository secrets for CI. The custom domain belongs only to this static project; no personal server is exposed.
MIT licensed. See THIRD_PARTY_NOTICES.md.