Sync reading position from Moon Reader app to Bookhive atproto records
atproto bookhive ereader moonreader
3
fork

Configure Feed

Select the types of activity you want to include in your feed.

update readme

+57 -37
+57 -37
README.md
··· 2 2 3 3 # spacebee 4 4 5 - A WebDAV shim for syncing [Moon+ Reader](https://www.moondownload.com) reading position. Translates 6 - the `.po` position files into ATProto reads/writes on your 7 - [bookhive.buzz](https://bookhive.buzz) book records. 5 + Sync [Moon+ Reader](https://www.moondownload.com) reading position to your Atmosphere account and share your progress on [bookhive.buzz](bookhive.buzz). 8 6 9 - ```json 10 - { 11 - "$type": "buzz.bookhive.book", 12 - "bookProgress": { 13 - "percent": 11, 14 - "updatedAt": "2026-04-17T10:01:24.000Z", 15 - "moonReader": { 16 - "file": "The Necromancers House - Buehlman Christopher.epub.po", 17 - "position": "1703297605115*21@0#4826:11.1%", 18 - "syncedAt": "2026-04-17T10:01:24.000Z" 19 - }, 20 - "currentChapter": 22 21 - } 22 - } 7 + It also serves a simple web page showing your reading status: 8 + <img src="sshot_spacebee.png"> 9 + 10 + > 🚨 *This is vibecoded, I don't know much Python but it works 👍️* 11 + 12 + ## How to use 13 + Spacebee pretends to be WebDAV but reads and writes from your Atmosphere account. In the Moon Reader app, go to `Options->Sync with WebDAV` and point it to spacebee: 14 + 15 + <img src="sshot_moonreader.webp"> 16 + 17 + ### Running locally 18 + 19 + ```sh 20 + cp .env.example .env 21 + uv sync --extra dev 22 + uv run uvicorn spacebee.main:app --reload --port 8080 23 23 ``` 24 24 25 - Also serves a static page showing your reading progress. 25 + Point a test device at `http://<wherever>:8080/` as the WebDAV target. 26 + 27 + ### Docker 26 28 27 - > 🚨 *This is vibecoded, I don't know what I'm doing but it works 👍️* 29 + Copy compose file, fill in a `.env`, run: 30 + 31 + ```sh 32 + curl -O https://raw.githubusercontent.com/oakbrad/spacebee/main/docker-compose.yml 33 + curl -O https://raw.githubusercontent.com/oakbrad/spacebee/main/.env.example 34 + mv .env.example .env # then edit with your creds 35 + docker compose up -d 36 + ``` 37 + 38 + By default it listens on `127.0.0.1:8080`. 39 + 40 + ### Configuration 41 + 42 + Copy `.env.example` to `.env` and fill in: 43 + 44 + | Var | Purpose | 45 + | --- | --- | 46 + | `BSKY_HANDLE` | The handle spacebee writes records as | 47 + | `BSKY_APP_PASSWORD` | An app password for that handle | 48 + | `DAV_USER` / `DAV_PASSWORD` | Basic-auth credentials Moon+ Reader will send | 49 + | `PASSTHROUGH_ROOT` | Local-disk scratch dir for non-`.po` paths | 50 + | `PDS` | *Optional.* If unset, resolved from the handle. | 28 51 29 52 ## How it works 30 53 ··· 50 73 cover-image blob proxy at `/blob/{cid}` are public; all WebDAV endpoints are 51 74 gated by HTTP Basic. 52 75 53 - ## Configuration 76 + ### Record 54 77 55 - Copy `.env.example` to `.env` and fill in: 56 - 57 - | Var | Purpose | 58 - | --- | --- | 59 - | `BSKY_HANDLE` | The handle spacebee writes records as | 60 - | `BSKY_APP_PASSWORD` | An [app password] for that handle | 61 - | `DAV_USER` / `DAV_PASSWORD` | Basic-auth credentials Moon+ Reader will send | 62 - | `PASSTHROUGH_ROOT` | Local-disk scratch dir for non-`.po` paths | 63 - | `PDS` | *Optional.* If unset, resolved from the handle. | 64 - 65 - ## Running locally 66 - 67 - ```sh 68 - cp .env.example .env 69 - uv sync --extra dev 70 - uv run uvicorn spacebee.main:app --reload --port 8080 78 + ```json 79 + { 80 + "$type": "buzz.bookhive.book", 81 + "bookProgress": { 82 + "percent": 11, 83 + "updatedAt": "2026-04-17T10:01:24.000Z", 84 + "moonReader": { 85 + "file": "The Necromancers House - Buehlman Christopher.epub.po", 86 + "position": "1703297605115*21@0#4826:11.1%", 87 + "syncedAt": "2026-04-17T10:01:24.000Z" 88 + }, 89 + "currentChapter": 22 90 + } 91 + } 71 92 ``` 72 93 73 - Point a test device at `http://<your-laptop>:8080/` as the WebDAV target. 74 94 75 95 ## Related 76 96
sshot_moonreader.webp

This is a binary file and will not be displayed.

sshot_spacebee.png

This is a binary file and will not be displayed.