README.md
Rama main · réplica de lectura del repositorio original.
<p align="center">
<img src="https://raw.githubusercontent.com/Get-Coral/aurora/main/public/aurora-app-icon.svg" width="128" alt="Aurora logo — a four-point star split by a glowing light beam" />
</p>
<h1 align="center">Aurora</h1>
<p align="center">
A cinematic, TV-friendly way to browse and watch your Jellyfin library.
</p>
<p align="center">
<a href="https://github.com/sponsors/ElianCodes"><img src="https://img.shields.io/badge/Sponsor-ElianCodes-ea4aaa?logo=githubsponsors&logoColor=white" alt="GitHub Sponsors" /></a>
<a href="https://discord.gg/M3wzFpGbzp"><img src="https://img.shields.io/discord/1495441903297237043?label=Discord&logo=discord&logoColor=white&color=5865F2" alt="Discord" /></a>
</p>
<p align="center">
<a href="https://play.google.com/store/apps/details?id=dev.getcoral.aurora">
<img alt="Get it on Google Play" height="80" src="https://play.google.com/intl/en_us/badges/static/images/badges/en_badge_web_generic.png" />
</a>
</p>
Aurora UI is an open-source Jellyfin frontend. It keeps Jellyfin as the source of truth and adds a living-room-ready way to browse and watch: a featured home, richer detail views, embedded playback, favorites, genre browsing, and a translation-ready UI. Self-host it, or install [Aurora for Jellyfin on Google Play](https://play.google.com/store/apps/details?id=dev.getcoral.aurora).
Aurora is an independent project and is not affiliated with or endorsed by the Jellyfin project.
## Why Aurora
Jellyfin's web client is the server console: libraries, metadata, users, and playback in one place. Aurora is a separate frontend built for the people watching.
- **A home screen for discovery.** Featured titles, Continue Watching, favorites, and recommendation rails.
- **Detail pages for the couch.** Cast, related titles, and series episode lists, with resume-next-up.
- **Shared households.** A Netflix-style profile picker. With required sign-in, each person gets their own Jellyfin session, so playback and watch progress stay on the right account.
- **The living room.** TV mode uses larger text and simpler navigation for a remote. The player can hand the stream to a TV over AirPlay or Cast.
- **Your server, your data.** Aurora has no accounts of its own, no ads, and no tracking. It talks only to the Jellyfin server you connect, and stores that connection in a local SQLite file, so self-hosting does not need another database.
Keep Jellyfin's web client for administering the server. Open Aurora when you want to watch.
## Screenshots
<p align="center">
<img src="./fastlane/metadata/android/en-US/images/phoneScreenshots/01_home.png" width="200" alt="Aurora home screen featuring Caminandes: Gran Dillama, with Play now and a cinematic mood rail" />
<img src="./fastlane/metadata/android/en-US/images/phoneScreenshots/02_rows.png" width="200" alt="Continue watching rail titled Resume your queue, with progress on War of the World" />
<img src="./fastlane/metadata/android/en-US/images/phoneScreenshots/03_details.png" width="200" alt="Movie spotlight for Caminandes: Llamigos with backdrop, poster, and Play now" />
</p>
<p align="center">
<img src="./fastlane/metadata/android/en-US/images/phoneScreenshots/04_series.png" width="200" alt="Series episode list with Resume next up for Pioneer One" />
<img src="./fastlane/metadata/android/en-US/images/phoneScreenshots/05_library.png" width="200" alt="Movie library with genre chips and sort controls" />
<img src="./fastlane/metadata/android/en-US/images/phoneScreenshots/07_player.png" width="200" alt="Now playing Caminandes: Llamigos, with transport controls and a progress bar" />
</p>
These are the English Google Play phone screenshots shipped in [`fastlane/metadata/android/en-US/images/phoneScreenshots`](./fastlane/metadata/android/en-US/images/phoneScreenshots). Dutch listings are in [`fastlane/metadata/android/nl-NL/images/phoneScreenshots`](./fastlane/metadata/android/nl-NL/images/phoneScreenshots).
## Quick start
Docker Compose, with the in-app Jellyfin setup:
```yaml
services:
aurora:
image: getcoral/aurora:latest
ports:
- "3000:3000"
volumes:
- aurora-data:/data
restart: unless-stopped
volumes:
aurora-data:
```
```bash
docker compose up -d
```
Open [http://localhost:3000](http://localhost:3000) and complete the Jellyfin onboarding form once. Aurora persists the connection in `/data/aurora.sqlite`.
The Jellyfin URL is requested by the Aurora container, so `localhost` in that form is the container itself. Use a hostname the container can reach: another Compose service name, a LAN address, or `host.docker.internal` on Docker Desktop.
The same stack with onboarding skipped (the container image is also published as [`ghcr.io/get-coral/aurora`](https://github.com/Get-Coral/aurora/pkgs/container/aurora)):
```yaml
services:
aurora:
image: getcoral/aurora:latest
ports:
- "3000:3000"
volumes:
- aurora-data:/data
environment:
JELLYFIN_URL: http://your-jellyfin:8096
JELLYFIN_API_KEY: your_api_key
JELLYFIN_USER_ID: your_user_id
JELLYFIN_USERNAME: your_username
JELLYFIN_PASSWORD: your_password
restart: unless-stopped
volumes:
aurora-data:
```
`JELLYFIN_USER_ID` is the Jellyfin user UUID. More on images, the local build, and `docker run` is in [Docker](#docker).
## Highlights
- Jellyfin-powered home screen with featured, continue watching, favorites, and recommendation rails
- Embedded playback with progress sync back to Jellyfin
- Rich title detail views with cast, related titles, and series episode context
- Movie and series library pages with genre browsing, sorting, and pagination
- `My List` / favorites workflow backed by Jellyfin favorites
- Multi-user profiles with a Netflix-style profile picker for shared households
- Optional required sign-in with per-user Jellyfin sessions, so playback and watch progress are attributed to the right account
- Admin dashboard for managing users, parental controls, libraries, and active sessions
- Translation-ready UI with locale files contributors can extend
- Local-first onboarding backed by SQLite so self-hosting does not require an external database
## Stack
- [TanStack Start](https://tanstack.com/start)
- React 19
- TanStack Router + TanStack Query
- Tailwind CSS v4
- Jellyfin API
## Getting Started
Install dependencies:
```bash
pnpm install
```
Create your local env file if you want to skip the in-app setup flow during development:
```bash
cp .env.example .env
```
Fill in the Jellyfin settings in `.env`:
```bash
JELLYFIN_URL=http://localhost:8096
JELLYFIN_API_KEY=your_api_key_here
JELLYFIN_USER_ID=your_user_id_here
JELLYFIN_USERNAME=your_username_here
JELLYFIN_PASSWORD=your_password_here
```
Start the app:
```bash
pnpm dev
```
Open [http://localhost:3000](http://localhost:3000).
If you do not provide Jellyfin env vars, Aurora will open a local onboarding screen at `/setup` and store the connection details in a local SQLite file under `./data/aurora.sqlite`.
## Scripts
```bash
pnpm dev
pnpm build
pnpm start
pnpm preview
pnpm test
```
## CI
GitHub Actions workflows are included for:
- CI on pushes and pull requests: install, test, web build, Android Capacitor sync, Android debug assemble, and Docker build validation
- Docker publish to Docker Hub and GHCR on `main`, version tags, or manual dispatch
Workflow files:
- [`.github/workflows/ci.yml`](./.github/workflows/ci.yml)
- [`.github/workflows/docker-publish.yml`](./.github/workflows/docker-publish.yml)
## Local Storage
Aurora stores local app configuration in SQLite.
- Default database path: `./data/aurora.sqlite`
- Override with: `AURORA_DATA_DIR=/path/to/data`
- Main use today: persisted Jellyfin connection details for onboarding and self-hosted installs
This keeps Aurora simple to deploy on a VM or home server because there is no external database requirement.
## Jellyfin Notes
Aurora uses Jellyfin as the system of record.
- API key access is enough for browsing, favorites, and most library features
- Username/password are used to create a real Jellyfin playback session so Aurora can sync progress and watched state more reliably; with required sign-in enabled, each signed-in user's own session is used instead and the configured credentials are only the fallback
- `JELLYFIN_USER_ID` must be the actual Jellyfin user UUID, not the app name
- If you use the onboarding flow, Aurora stores these values in local SQLite instead of requiring env vars
## User Profiles
Aurora supports multiple profiles for shared households: everyone picks their own Jellyfin user on a profile screen when opening Aurora.
- Enable it in Settings → User profiles, or force it on with `AURORA_MULTI_USER=true` in the environment
- Administrators manage users (create, disable, delete, parental controls) from the dashboard at `/admin`
- When required sign-in is enabled, switching to another profile asks for that profile's password
## Requiring Sign-In
By default anyone who can reach your Aurora instance can browse and stream the connected library. If your instance is reachable from the internet (or any network you do not fully trust), enable **Require sign-in** in Settings → Security. Everyone then has to sign in with their own Jellyfin username and password before Aurora serves anything.
- Sessions are stored server-side in the local SQLite database and last 30 days
- Sign-in is validated directly against your Jellyfin server, so Jellyfin account lockout policies apply
- Each sign-in gets its own Jellyfin access token, so playback and watch progress are attributed to the signed-in user (not the configured account), and signing out revokes the token on the Jellyfin side
- To force it on (so it cannot be disabled from the UI), set `AURORA_REQUIRE_LOGIN=true` in the environment
Administration is gated separately and always requires signing in. Even on an open
instance, the admin dashboard and the settings that change your Jellyfin connection,
users, or security options are only available to a signed-in Jellyfin administrator —
"Require sign-in" controls who can browse and stream, not who can administer. The one
exception is a brand-new install that is not connected to Jellyfin yet, since there is
no account to sign in with until setup completes.
## Playing on a TV (AirPlay & Cast)
The player has a "Play on TV" button that opens the browser's own device picker — AirPlay in Safari and on iOS, Cast in Chrome. It only appears once a receiver has been discovered, so give it a second or two on first load.
A TV doesn't play the video through your browser: it's handed the stream URL and fetches it itself. That has a few consequences worth knowing:
- **Aurora has to be reachable from the TV.** `http://localhost:3000` cannot work — serve Aurora on a hostname or IP the receiver can also reach.
- **Cast needs HTTPS.** Chrome only exposes the picker on a secure origin. AirPlay has no such requirement and works over plain HTTP on a LAN.
- **Subtitles stay on your device.** The receiver plays the stream as its own player, so neither Aurora's subtitle tracks nor the OpenSubtitles overlay reach the TV.
- **Quality is fixed for the duration of the cast**, and seeking is limited to what's already buffered — changing either would restart the stream and drop the connection to the TV.
With **Require sign-in** on, stream URLs are signed with a token so the TV can fetch them without your session cookie. Each token covers a single title, expires within six hours, and stops working the moment you sign out. Aurora generates the signing secret on first use; set `AURORA_STREAM_TOKEN_SECRET` only if you run several replicas behind a load balancer.
## Translations
Translations live in dedicated locale files so contributors can add languages without touching the runtime logic.
Files:
- [`src/lib/i18n/messages/en.ts`](./src/lib/i18n/messages/en.ts)
- [`src/lib/i18n/messages/nl.ts`](./src/lib/i18n/messages/nl.ts)
- [`src/lib/i18n/messages/index.ts`](./src/lib/i18n/messages/index.ts)
To add a new language:
1. Copy `src/lib/i18n/messages/en.ts` to a new file such as `fr.ts`
2. Translate the strings
3. Export and register the file in `src/lib/i18n/messages/index.ts`
4. Add the locale to the language picker if you want it selectable in the UI
## Docker
Aurora ships with a production Dockerfile and can be deployed to a VM with Docker or Docker Compose. The copy-paste Compose files are in [Quick start](#quick-start).
Build locally:
```bash
docker build -t aurora .
```
Run locally with the onboarding flow:
```bash
docker run --rm -p 3000:3000 \
-v aurora-data:/data \
getcoral/aurora:latest
```
Then open [http://localhost:3000](http://localhost:3000) and complete the Jellyfin onboarding form once. Aurora will persist the connection in `/data/aurora.sqlite`.
If you prefer skipping onboarding, you can still pass the Jellyfin env vars directly:
```bash
docker run --rm -p 3000:3000 \
-v aurora-data:/data \
-e JELLYFIN_URL=http://your-jellyfin:8096 \
-e JELLYFIN_API_KEY=your_api_key \
-e JELLYFIN_USER_ID=your_user_id \
-e JELLYFIN_USERNAME=your_username \
-e JELLYFIN_PASSWORD=your_password \
getcoral/aurora:latest
```
The container listens on port `3000` and stores local config in `/data`.
## Capacitor Wrappers
Aurora now supports a real local Capacitor build for Android and iOS.
How it works:
- Capacitor uses the built local web bundle from `dist/client`.
- TanStack Start SPA mode now emits a real `dist/client/index.html`, which Capacitor requires.
- `pnpm cap:sync`, `pnpm cap:copy`, and `pnpm cap:run:*` build Aurora first and then sync the native projects.
- In native-shell mode, Aurora stores Jellyfin and OpenSubtitles settings in device-local storage instead of relying on the Node server.
- Android hardware back now exits fullscreen first, then closes Aurora overlays, then navigates back before exiting the app at the true root.
The Capacitor config lives in [`capacitor.config.ts`](./capacitor.config.ts).
### Native Setup
Sync the latest web assets into Android and iOS:
```bash
pnpm cap:sync
```
Open the native projects:
```bash
pnpm cap:open:android
pnpm cap:open:ios
```
Run directly to a connected device or emulator:
```bash
pnpm cap:run:android
pnpm cap:run:ios
```
Build the Android debug app without launching a device target:
```bash
pnpm android:assemble:debug
```
### First Launch
On first launch in the native app:
1. Open the `/setup` flow.
2. Enter the Jellyfin server URL.
3. Either leave the API key empty and sign in with your Jellyfin username and password (the password may be empty for accounts without one), or enter an API key together with your user ID, username, and password.
4. Optionally add your OpenSubtitles API key in settings.
Aurora stores that configuration on the device.
### What Works Locally
- Setup and settings
- Home feeds
- Movie and series library browsing
- Search
- My List and favorites toggles
- History
- Media details and episode browsing
- Basic local playback bootstrapping
- OpenSubtitles search and download using the stored API key
### Current Limits
- The admin screen is still server-oriented.
- Native playback works locally, but full Jellyfin playback-session and progress sync is still less complete than the hosted server build.
- If you want the native shell to target a hosted Aurora deployment instead, you can still set `AURORA_APP_URL` before syncing.
Example hosted override:
```bash
AURORA_APP_URL=https://your-aurora-domain.example pnpm cap:sync
```
### Android Release Builds
The Play Store bundle is signed with an upload key that never goes in the repo. Copy [`android/keystore.properties.example`](./android/keystore.properties.example) to `android/keystore.properties` and point it at your keystore, or set the `AURORA_UPLOAD_STORE_FILE`, `AURORA_UPLOAD_STORE_PASSWORD`, `AURORA_UPLOAD_KEY_ALIAS` and `AURORA_UPLOAD_KEY_PASSWORD` environment variables. Then build the bundle:
```bash
pnpm android:bundle:release
```
The signed bundle is written to `android/app/build/outputs/bundle/release/app-release.aab`. Without a keystore the release build is left unsigned.
The version comes from `package.json`. The versionCode is `major * 1000000 + minor * 10000 + patch * 100 + build`, so 1.14.1 becomes `1140100`. To upload the same version again, raise the build number with `AURORA_BUILD_NUMBER` (0–99), for example `AURORA_BUILD_NUMBER=1 pnpm android:bundle:release`.
Store listing texts, release notes, the icon, the feature graphic and phone screenshots live in [`fastlane/metadata/android`](./fastlane/metadata/android). The privacy policy is in [`docs/privacy-policy.md`](./docs/privacy-policy.md) and is published at https://getcoral.dev/apps/aurora/privacy.
The public Android app is [Aurora for Jellyfin](https://play.google.com/store/apps/details?id=dev.getcoral.aurora) (`dev.getcoral.aurora`).
### Packaging Notes
- Android release bundles are built with `pnpm android:bundle:release` (see above). Android Studio is still useful for running and debugging.
- iOS packaging happens from Xcode after opening the generated project.
- Google TV should be treated as an Android TV target using the same Capacitor Android project once the TV UX is finalized.
- Capacitor Android 8 requires JDK 21 for local and CI builds.
- `pnpm cap:run:android` resolves `JAVA_HOME` automatically on macOS and prefers the Homebrew JDK 21 path when present, then falls back to system JDK 21 or 17.
- CI validates the native Android path with `pnpm cap:sync` and `pnpm android:assemble:debug`.
Published images go to:
- [`getcoral/aurora`](https://hub.docker.com/r/getcoral/aurora) on Docker Hub
- [`ghcr.io/get-coral/aurora`](https://github.com/Get-Coral/aurora/pkgs/container/aurora) on GHCR
## Contributing
Issues and pull requests are welcome.
If you want to contribute:
1. Fork the repo
2. Create a branch
3. Make your changes
4. Run `pnpm build`
5. Open a pull request
## Sponsoring
If Aurora helps you or you want to support ongoing work, you can sponsor the project here:
- [GitHub Sponsors: ElianCodes](https://github.com/sponsors/ElianCodes)
## License
Aurora UI is released under the [MIT License](./LICENSE).