osmo1/ephemera
1
0
Fork
You've already forked ephemera
0
No description
  • TypeScript 98.4%
  • JavaScript 1%
  • Dockerfile 0.3%
  • Shell 0.2%
OrwellianEpilogue 3d3eaef1b3 chore: release v2.0.0
### Major Changes
- Features:
 multi user auth / oidc (#45)
 proxy auth fall through (#95)
 post-download EPUB normalization and format conversion (#99)
 approval workflow for users without download permission (#90)
 domain fallback for searcher and quick download URLs (#110)
 Tolino Cloud integration with ebook conversion and book metadata enrichment and Tolino series collections (#93, #103 #111)
 dynamic page titles (#96)
 detect searcher issues and show maintenance mode
 pause/resume functionality for downloads
 show active count and pause indicator in browser tab title
 9 new notification events and fix triggers (#107)
 action buttons to BookCard when downloaded (#109)
 book tracking app list imports feature (#102)
 text filter to search requests
 FlareSolverr health check and maintenance mode (#100)
 styling and display improvements (#105)
 Fixes:
 optimize queue page with single JOIN query
 enforce delete permissions at API level (#88)
 include IP address in untrusted proxy log message
 resolve 404/429 loop on settings page and persist auth secret
 cache setup status to reduce API calls
 add cross-request session cache to reduce Better Auth calls
 respect keepInDownloads setting for automated actions
 bundle React and Mantine together to prevent race condition
 allow clearing author & title
 config endpoint, permission check procps, render loops (#98)
 pin Node to 22.16.0 to avoid undici fetch bug (#97)#
 add self-unregistering service worker to clear stale caches (#94)
 optimize API caching and database queries (#91)
### Patch Changes
- Updated dependencies
 - @ephemera/shared@2.0.0
2026年01月05日 18:13:51 +01:00
.changeset feat: run prettier on save, reformat all files ( #16 ) 2025年11月12日 16:58:38 +01:00
.github/workflows feat: build for arm64 ( #37 ) 2025年11月13日 22:47:59 +01:00
.husky feat: type safety, linting, pre-commit hooks ( #10 ) 2025年11月12日 14:25:34 +01:00
.vscode feat: run prettier on save, reformat all files ( #16 ) 2025年11月12日 16:58:38 +01:00
packages chore: release v2.0.0 2026年01月05日 18:13:51 +01:00
preview update screenshots 2025年11月13日 19:18:04 +01:00
scripts feat: expose newznab/sabnzbd APIs for usenet indexer tools like readarr ( #32 ) 2025年11月13日 18:02:54 +01:00
.dockerignore docker setup 2025年11月04日 20:16:34 +01:00
.editorconfig feat: run prettier on save, reformat all files ( #16 ) 2025年11月12日 16:58:38 +01:00
.gitignore feat(ui): styling and display improvements ( #105 ) 2025年12月29日 11:15:41 +01:00
.nvmrc specify node version 2025年12月27日 10:24:46 +01:00
.prettierignore feat: run prettier on save, reformat all files ( #16 ) 2025年11月12日 16:58:38 +01:00
.prettierrc.json feat: run prettier on save, reformat all files ( #16 ) 2025年11月12日 16:58:38 +01:00
docker-compose.yml feat: multi user auth / oidc ( #45 ) 2025年12月26日 21:39:17 +01:00
docker-entrypoint.sh feat(tolino): add Tolino Cloud integration with ebook conversion ( #93 ) 2025年12月27日 23:12:34 +01:00
Dockerfile fix: config endpoint, permission check procps, render loops ( #98 ) 2025年12月28日 12:20:43 +01:00
eslint.config.js feat: multi user auth / oidc ( #45 ) 2025年12月26日 21:39:17 +01:00
LICENSE ephemera 1.0.0 2025年11月04日 18:15:49 +01:00
package.json chore: release v2.0.0 2026年01月05日 18:13:51 +01:00
pnpm-lock.yaml feat(metadata): add book metadata enrichment and Tolino series collections ( #111 ) 2025年12月29日 19:06:05 +01:00
pnpm-workspace.yaml feat: run prettier on save, reformat all files ( #16 ) 2025年11月12日 16:58:38 +01:00
README.md feat(search): detect searcher issues and show maintenance mode 2025年12月30日 13:19:08 +01:00

Ephemera Book Downloader

Search and download books from your girl's favorite archive. Includes a request system to auto-download books once they're available. Supports auto-move to a BookLore or Calibre-Web-Automated ingest folder or BookLore API upload.

Main features

  • Download books from any archive
  • Use donator key for super fast downloads or a l----n library for fast free downloads (also supports slow downloads as a fallback)
  • Automatically import books to BookLore or Calibre-Web-Automated by utilizing their ingest folders and/or upload APIs
  • Request system to auto download non-available books once they become available
  • Notifications on newly available books or fulfilled requests with Apprise
  • Implement Ephemera as a usenet indexer into newznab tools like Readarr
  • Realtime updates in UI
  • Supports all popular book formats (epub, awz3, mobi, pdf, cbz, cbr etc.)
  • Link your BookLore or CWA library in the menu
  • OpenAPI specs for 3rd party integrations, Swagger-UI
  • Simple setup with Docker
  • Cloudflare bypassing with Flaresolverr

Docker setup

Setup the container using the Docker Compose template below:

services:ephemera:image:ghcr.io/orwellianepilogue/ephemera:latestcontainer_name:ephemerarestart:unless-stoppedports:- "8286:8286"environment:# FlareSolverr URL (for slow download fallback)FLARESOLVERR_URL:http://flaresolverr:8191# Optional: Set your public URL for CORS (required if not using localhost)# BASE_URL: https://ephemera.yourdomain.com# User/Group IDsPUID:1000PGID:100volumes:- ./data:/app/data- ./downloads:/app/downloads- ./ingest:/app/ingest# Set DNS server to prevent EU blocking#dns:# - 1.1.1.1# - 1.0.0.1healthcheck:test:["CMD","wget","--no-verbose","--tries=1","--spider","http://127.0.0.1:8286/health",]interval:30stimeout:10sstart_period:40sretries:3flaresolverr:image:ghcr.io/flaresolverr/flaresolverr:latestcontainer_name:flaresolverrrestart:unless-stoppedenvironment:- LOG_LEVEL=info- LOG_HTML=false- CAPTCHA_SOLVER=none- TZ=Europe/Berlin# Set DNS server to prevent EU blocking#dns:# - 1.1.1.1# - 1.0.0.1healthcheck:test:["CMD","curl","-f","http://127.0.0.1:8191/health"]interval:30stimeout:10sstart_period:30sretries:3

Docker Image Tags

The following Docker image tags are available:

Tag Description Update Frequency
latest Latest stable release On version tags (v*.*.* releases)
dev Latest development build On commits to dev branch
1.2.3 Specific version Never (immutable)
1.2 Latest patch of minor version On patch releases
1 Latest minor/patch of major version On minor/patch releases
dev-sha-abc1234 Specific dev build Never (immutable)

Examples

# Production (stable release)
docker pull ghcr.io/orwellianepilogue/ephemera:latest
# Development (latest dev branch)
docker pull ghcr.io/orwellianepilogue/ephemera:dev
# Specific version
docker pull ghcr.io/orwellianepilogue/ephemera:1.2.2
# Specific dev build
docker pull ghcr.io/orwellianepilogue/ephemera:dev-sha-7aa9d68

Note: The latest tag always points to the most recent stable release. If you want to test new features before they're released, use the dev tag.

Environment Variables

Most settings are now configured via the web UI setup wizard and stored in the database. Only infrastructure-level settings need environment variables.

Variable Default Description
FLARESOLVERR_URL http://127.0.0.1:8191 FlareSolverr URL (required for slow downloads)
PORT 8286 Application port
DB_PATH /app/data/database.db Database location
NODE_ENV production Node environment
API_BASE_PATH /api API base path
HTML_BASE_HREF empty HTML base href (for iframes/subpaths)
BASE_URL http://localhost:8286 Public URL (for CORS/auth in production)
ALLOWED_ORIGINS empty Additional CORS origins (comma-separated)

Note: Archive URLs, API keys, download folders, and other app settings are configured in the setup wizard on first run.

Advanced: Configurable API Base Path

Ephemera supports hosting behind a proxy or at a subpath by configuring the API base path:

Use Cases:

  • Hosting behind a reverse proxy with a custom path
  • Embedding in an iframe with a different base path
  • Running multiple instances with different API paths

Configuration:

environment:# Change API base path from /api to /api/v1API_BASE_PATH:/api/v1# Optional: Set HTML base href for iframe embedding# Must end with trailing slashHTML_BASE_HREF:/ephemera/

Examples:

Scenario API_BASE_PATH HTML_BASE_HREF Result
Default /api (empty) Standard setup
Subpath hosting /ephemera/api /ephemera/ Hosting at /ephemera/
Versioned API /api/v1 (empty) API at /api/v1/*
Iframe embed /api /app/ UI embedded at /app/

Notes:

  • The frontend automatically detects the API base path from the backend
  • Backward compatible - existing deployments continue working with default /api
  • Both development and production environments support custom paths

Monorepo Structure

ephemera/
├── packages/
│ ├── api/ # Hono API backend with Crawlee scraping
│ ├── shared/ # Shared TypeScript types and API client
│ └── web/ # React frontend with Vite
└── data/ # SQLite database

Development Quick Start

Prerequisites

  • Node.js 22+
  • pnpm 9+

Installation

# Install all dependencies
pnpm install
# Approve build scripts for native modules
pnpm approve-builds
# Select: better-sqlite3, esbuild
# Copy environment template
cp packages/api/.env.example packages/api/.env
# Edit with your searcher API key and url
nano packages/api/.env
# Run migrations
cd packages/api && pnpm db:migrate

Development

# Run everything (API + Frontend)
pnpm dev
# Or run individually:
pnpm dev:api # Backend only (http://localhost:8286)
pnpm dev:web # Frontend only (http://localhost:5173)

Build for Production

# Build all packages
pnpm build
# Build individually
pnpm build:api
pnpm build:web

Architecture

Tech Stack

Backend (packages/api)

  • Framework: Hono 4.6+ (lightweight, fast, type-safe)
  • Database: SQLite + Drizzle ORM
  • Scraping: Crawlee + Cheerio
  • Validation: Zod schemas
  • OpenAPI: Swagger UI and auto-generated spec at http://host:8286/api/docs & http://host:8286/api/openapi.json

Frontend (packages/web)

  • Framework: React 18 + TypeScript
  • Build Tool: Vite 6
  • UI Library: Mantine UI 7
  • Routing: TanStack Router v1
  • Data Fetching: TanStack Query v5
  • Icons: Tabler Icons

Shared (packages/shared)

  • Schemas: Zod validation schemas
  • Types: TypeScript types (exported from Zod)
  • API Client: Typed fetch wrapper using OpenAPI types
  • Type Generation: openapi-typescript from live API

Type Safety

Full end-to-end type safety:

API (Zod schemas) → OpenAPI spec → TypeScript types → React frontend

Changes to the API automatically propagate to the frontend through:

  1. Zod schemas in packages/shared/src/schemas.ts
  2. Generated OpenAPI types via openapi-typescript
  3. Type-safe client in packages/shared/src/client.ts

Scripts

Root-Level Scripts

pnpm dev # Run all packages in parallel
pnpm build # Build all packages
pnpm type-check # Type-check all packages
pnpm clean # Clean all build artifacts

API Scripts

pnpm --filter @ephemera/api dev # Dev mode with watch
pnpm --filter @ephemera/api build # Build TypeScript
pnpm --filter @ephemera/api db:generate # Generate migrations
pnpm --filter @ephemera/api db:migrate # Run migrations
pnpm --filter @ephemera/api db:studio # Open Drizzle Studio

Web Scripts

pnpm --filter @ephemera/web dev # Dev server with HMR
pnpm --filter @ephemera/web build # Production build
pnpm --filter @ephemera/web preview # Preview prod build

Shared Scripts

pnpm --filter @ephemera/shared build # Build types
pnpm --filter @ephemera/shared generate:client # Generate API types

Version Management

This monorepo uses Changesets for synchronized versioning. All packages (api, web, shared) always share the same version number.

Quick Release Workflow

  1. Make your changes and commit them normally
  2. Create a changeset describing what changed:
    pnpm changeset
    # Follow prompts: select change type (patch/minor/major) and write summary
    
  3. When ready to release, run:
    pnpm release
    # This will: version packages → create git tag → push to trigger Docker build
    

Version Management Scripts

# Create a changeset (describes your changes)
pnpm changeset
# Check status of pending changesets
pnpm changeset:status
# Apply changesets and update versions + CHANGELOG
pnpm version
# Full release (version → tag → push)
pnpm release
# Individual release steps (if you want more control)
pnpm release:version # Update package.json + CHANGELOG
pnpm release:tag # Commit changes and create git tag
pnpm release:push # Push code and tags to trigger Docker build

How It Works

  • Changesets track what changed between versions
  • Synchronized versioning: All packages version together (currently at v1.0.3)
  • Automatic changelog: Generated from changeset summaries
  • Docker automation: Pushing a git tag (e.g., v1.0.4) triggers the GitHub Action to build and publish a new Docker image

Example Release Flow

# 1. After implementing a new feature
git add .
git commit -m "feat: add book metadata export"
# 2. Create a changeset
pnpm changeset
# → Select "minor" (new feature)
# → Enter summary: "Add book metadata export functionality"
# 3. Continue working, create more changesets for other changes
pnpm changeset
# → Select "patch" (bug fix)
# → Enter summary: "Fix download progress bar display"
# 4. When ready to release
pnpm release
# → All changesets consumed
# → package.json versions bumped (e.g., 1.0.3 → 1.1.0)
# → CHANGELOG.md updated
# → Git tag v1.1.0 created
# → Changes pushed to GitHub
# → Docker build triggered automatically

Version Types

  • patch (1.0.3 → 1.0.4): Bug fixes, minor tweaks
  • minor (1.0.3 → 1.1.0): New features, backwards-compatible changes
  • major (1.0.3 → 2.0.0): Breaking changes

Development Workflow

1. Update API Schema

Edit packages/shared/src/schemas.ts:

export const myNewSchema = z.object({
 id: z.string(),
 name: z.string(),
});

2. Use in API

import { myNewSchema } from "@ephemera/shared";
const route = createRoute({
 request: { body: myNewSchema },
 // ...
});

3. Regenerate OpenAPI Types

# Start API first
pnpm dev:api
# In another terminal, generate types
pnpm --filter @ephemera/shared generate:client

4. Use in Frontend

import { client } from "@ephemera/shared";
const data = await client.get("/api/new-endpoint");
// `data` is fully typed!

API Documentation

Frontend Routes

  • / - Search books
  • /queue - Download queue management
  • /settings - App and Booklore settings

Proxy Configuration

The frontend proxies API requests to the backend during development. The base path is configurable via the API_BASE_PATH environment variable (defaults to /api):

// vite.config.ts
const API_BASE_PATH = process.env.API_BASE_PATH || '/api';
proxy: {
 [API_BASE_PATH]: {
 target: 'http://localhost:8286',
 changeOrigin: true,
 },
}

To use a custom API base path during development, set the API_BASE_PATH environment variable before running pnpm dev.

License

MIT