- Svelte 49%
- TypeScript 42.5%
- CSS 7.4%
- Dockerfile 0.8%
- HTML 0.2%
| Filename | Latest commit message | Latest commit date |
|---|---|---|
|
All checks were successful
build and publish / check-build-publish (push) Successful in 1m44s
|
||
| .forgejo/workflows | ||
| apps | ||
| deploy/chart | ||
| docs | ||
| packages | ||
| .dockerignore | ||
| .env.example | ||
| .gitignore | ||
| .oxfmtrc.json | ||
| .oxlintrc.json | ||
| bun.lock | ||
| docker-compose.yml | ||
| package.json | ||
| README.md | ||
| tsconfig.json | ||
arcelia tv
A small, self-hosted streaming interface. It browses TMDB metadata, resolves third-party HLS sources through the internal Videasy port, and keeps upstream stream URLs behind signed proxy routes.
workspace
apps/web— SvelteKit browser and player UIapps/api— Hono metadata and playback APIapps/proxy— signed streaming proxy and HLS playlist rewriterpackages/shared— Zod contracts, types, and token signingpackages/videasy— TypeScript port of the internal Python resolver
The browser talks only to the API and proxy. TMDB images are streamed through a fixed API image route. Stream URLs accepted by the proxy must carry a valid HMAC token; there is no client-controlled upstream URL parameter.
local development
Requirements: Bun 1.3.14+, a TMDB v4 read access token, Valkey or Redis, and three terminals.
cp .env.example .env
bun install
docker compose up -d cache
bun run --cwd apps/proxy dev
bun run --cwd apps/api dev
bun run --cwd apps/web dev
Set TMDB_ACCESS_TOKEN and a random PROXY_SECRET of at least 32 characters in .env. Set OPENSUBTITLES_API_KEY to an OpenSubtitles.com consumer key to enable external captions; the player remains usable without it. The development scripts explicitly load this root environment file even though each process runs from its app directory.
REDIS_URL enables the shared API cache. TMDB metadata uses the same 2–60 minute TTLs sent to browsers. Successful Videasy source resolution is cached for five minutes, but proxy URLs are signed fresh for every playback response. Cache errors fail open, so provider requests continue if Valkey is down. Images and streamed media bodies are not stored in Valkey.
Default endpoints:
- web:
http://localhost:5173 - API:
http://localhost:3001 - proxy:
http://localhost:3002
Run all checks with:
bun run check
bun run test
bun run build
The Videasy cipher parity test uses the unchanged Python project at /home/ruri/stuff/videasy/videasy by default. Set PYTHON_VIDEASY_PATH when it lives elsewhere.
containers
docker compose up --build
Compose reads .env. PUBLIC_API_URL, PROXY_PUBLIC_URL, and WEB_ORIGIN must be addresses the viewer's browser can reach; internal Docker service names do not work in browser URLs. API_INTERNAL_URL is server-only and may use the Compose network.
deployment constraints
- The API and proxy must share the same
PROXY_SECRET. - Playback tokens default to four hours so signed HLS segment URLs remain valid for a full viewing session. They are non-renewable and never stored.
- The proxy is bandwidth-heavy and keeps streaming connections open. Tune
MAX_CONNECTIONSand upstream/load-balancer timeouts for expected concurrency. - API and proxy instances are stateless. They can scale horizontally as long as the signing secret is shared.
- Valkey is private and ephemeral, with persistence disabled, a 128 MB memory cap, and
allkeys-lrueviction. Losing it only causes upstream cache misses. - Allow outbound HTTPS to TMDB, OpenSubtitles,
speedracelight.com, and the media hosts returned by the resolver. - Terminate TLS before exposing the services publicly. Set exact HTTPS origins for CORS; do not use wildcard origins.
- Viewing history and watchlist stay in browser local storage. Clearing site data removes them.
Only stream media you are permitted to access. Source availability and host behavior are outside this project's control.