https://github.com/mattstein/export-reeder-starred
Export Reeder 5 starred posts into JSON or CSV format.
https://github.com/mattstein/export-reeder-starred
reeder rss
Last synced: about 1 month ago
JSON representation
Export Reeder 5 starred posts into JSON or CSV format.
- Host: GitHub
- URL: https://github.com/mattstein/export-reeder-starred
- Owner: mattstein
- Created: 2026-03-18T16:19:24.000Z (4 months ago)
- Default Branch: main
- Last Pushed: 2026-03-18T16:21:46.000Z (4 months ago)
- Last Synced: 2026-04-29T02:11:36.989Z (2 months ago)
- Topics: reeder, rss
- Language: Swift
- Homepage:
- Size: 5.86 KB
- Stars: 0
- Watchers: 0
- Forks: 0
- Open Issues: 0
-
Metadata Files:
- Readme: README.md
Awesome Lists containing this project
README
# export-reeder-starred
Exports starred items from Reeder 5’s local database to JSON or CSV.
## What it does
Reads Reeder 5’s Realm database directly from its sandbox location, extracts all starred items, and writes them to stdout or a file. Each record includes:
| Field | Notes |
|-------|-------|
| `title` | Article title |
| `link` | Article URL |
| `author` | Author name |
| `feedUrl` | Feed URL (Reeder doesn’t store a feed title in the DB) |
| `starredDate` | ISO 8601 timestamp |
| `summary` | Plain-text excerpt |
Results are sorted newest-starred first.
## Requirements
- **Reeder 5 for Mac** — the database lives at `~/Library/Containers/com.reederapp.5.macOS/Data/Library/Application Support/default.realm`
- **macOS 13+**
- **Swift 5.9+** (ships with Xcode 15+; check with `swift --version`)
No need to close Reeder before running — the tool copies the database to a temp directory before opening it, so the original is never touched.
## Build
First build downloads ~300 MB of realm-core and takes several minutes. Subsequent builds are fast.
```sh
cd /Users/mattstein/Projects/export-reeder-starred
swift build -c release
```
The binary lands at `.build/release/export-reeder-starred`.
Optionally copy it somewhere permanent:
```sh
cp .build/release/export-reeder-starred /usr/local/bin/
```
## Usage
```
export-reeder-starred [options]
Options:
-f, --format Output format (default: json)
-o, --output Write to file instead of stdout
-r, --realm Realm file (default: Reeder 5 on current user)
-h, --help Show this help
```
**JSON to stdout:**
```sh
.build/release/export-reeder-starred
```
**CSV to a file:**
```sh
.build/release/export-reeder-starred -f csv -o ~/Desktop/starred.csv
```
**JSON to a file:**
```sh
.build/release/export-reeder-starred -o ~/Desktop/starred.json
```
## Non-obvious things
### realm-swift is pinned to an exact version — don’t upgrade it carelessly
`Package.swift` uses `exact: "10.32.0"` (realm-core 12.9.0). This is not arbitrary:
- **realm-core 13.x deadlocks** when opening Reeder’s format-9 file from a CLI process. The exception handler’s cold path (`Exception::what()`) and the notification listener thread (`kevent`) wait on each other and never resolve.
- **realm-core 14+** dropped support for file format 9 entirely and returns an immediate error.
- realm-core **12.9.0** is the sweet spot: it supports format 9 and produces real errors instead of deadlocking.
If Reeder ever upgrades to a newer Realm (writing format 10+), you’d need to bump the realm-swift dependency accordingly.
### The file must be copied before opening
Opening format 9 in read-only mode is rejected by realm-core 12.x — it needs write access to upgrade the format to its native version (22). The tool copies `default.realm` to a temp directory, upgrades the copy, reads it, and deletes the copy on exit.
### The schema has some surprises
- `Item.starred` is stored as `Int` (0 or 1), not `Bool`
- `Item.starredDate` is stored as a `Double` (Unix timestamp), not a `Date`
- `Feed` has **no title field** — the feed URL is the closest identifier available
- Both `Item` and `Feed` use `String` primary keys
### Migration version must be higher than the file’s
Reeder sets the Realm schema version to `1`. The tool sets `schemaVersion: 2` with a no-op migration block. This is what tells realm-core “I know the schema changed, proceed anyway” — without a higher version number, realm-core refuses to open the file when the Swift model definitions don’t exactly match what’s stored.
### Realm work runs on a dedicated thread
In CLI processes (no AppKit run loop), certain realm-core internal schedulers can stall. All Realm operations run on a background `Thread` while the main thread spins `RunLoop.main` to drain any callbacks.