Skip to content
datlt4Public

About

Koi's Jellyfin - Smoother, simplier - Vibe Coding

Resources

Stars

1 star

Watchers

0 watching

Forks

Repository files navigation

Kellyfin

Kellyfin

A fast, self-hosted home for your movies and series — a from-scratch alternative to Jellyfin, with a Rust server and light apps for the web, desktop and phones.

Download · Run the server · Migrate from Jellyfin · Developer handoff

Home

Why

Kellyfin was written to fix what hurt in daily Jellyfin use on a small home server:

  • Playback that starts right away, on the LAN and over a VPN. Files the device can play are sent as they are, with instant seeking; anything else is converted on the fly, only for the part being watched.
  • Thumbnails that never go missing. Every image is rendered once into small WebP files and cached forever by the browser.
  • Light enough for old phones. The web app is about 25 KB of JavaScript, and the same UI runs in the apps.
  • The Jellyfin layout you already know, redesigned: library bar on top, My Media, Continue Watching, Recently Added per library.

Features

Watching

  • Direct play, a lossless remux (MKV, other audio tracks), or an on-demand HLS transcode — chosen automatically, with fallback when a device refuses a file.
  • Quality menu from the original down to 144p, without storing any extra copies. Auto picks a quality from your bandwidth and screen size.
  • Hardware transcoding: VAAPI (AMD / Intel GPU), NVENC (NVIDIA), or x264 on the CPU.
  • Subtitles from .srt / .vtt / .ass files next to the video or embedded in it; dual subtitles for language learning (a second language above the first).
  • Audio track switching, playback speed 0.25×–2×, resume where you left off, auto-play of the next episode (and of the next season).
  • Picture-in-picture, fullscreen, keyboard shortcuts, double tap a side on phones to skip ±10 s.
  • Black bars around the picture are found during the scan and cut away in the player and the thumbnails (one button turns it off); files are never modified.
  • Cast to Chromecast (Chrome) and AirPlay (Safari / iOS).

Library

  • Libraries of folders, scanned in the background; titles and thumbnails editable, or taken from the file name and a frame of the video.
  • Accent-insensitive search (am muu finds Âm Mưu), where numbers match whole (Tập 1 is not Tập 10).
  • Suggestions by title: other seasons and related series on every video page.
  • Import from Jellyfin (libraries, folders, titles, images, watch progress), and export/import of Kellyfin's own data.
  • A repair tool for wrong titles and posters that Jellyfin matched online to unrelated films.

Server and apps

  • Users, avatars, passwords; dashboard with now-playing sessions, scans, restart.
  • Apps for Windows, macOS, Linux, Android and iOS. Several servers can be saved and switched in one tap, including servers behind an authenticating proxy such as Pangolin that needs extra request headers.
  • The apps check for new versions: desktop apps update themselves (signed), Android opens the new APK.
  • AI upscaling (experimental): GPU workers turn low-resolution videos into 1080p copies, chosen per library or episode, that appear as an extra quality in the player.
  • Narration (thuyết minh): subtitles from the speech (Whisper) or read off the picture (OCR of burned-in subtitles), translated, read out by a voice and mixed over the original sound — added to the video file as extra audio tracks, with the subtitles next to it. Pipelines are node graphs you can draw and save.

Screenshots

Library Video page
Library Video page
Dual subtitles Subtitle menu
Dual subtitles Subtitle menu
Dashboard Libraries
Dashboard Libraries

Search

On a phone:

Home on a phone Video page on a phone Sign-in with server picker

Player on a phone

Apps

Download from the latest release:

Platform File
Windows (x64, x86, ARM64) *-setup.exe, *.msi, or the portable .zip
macOS (Apple Silicon, Intel) *.dmg
Linux (x64, ARM64) .deb, .rpm, .AppImage
Android 7+ kellyfin_android_*.apk
iOS kellyfin_ios_*_unsigned.ipa — sign it with your Apple ID (AltStore, Sideloadly, or Xcode)

The browser needs no install: open the server's address.

Run the server

Requirements: Docker, and ideally a GPU for transcoding (AMD/Intel through /dev/dri, or NVIDIA with the NVIDIA Container Toolkit).

# docker-compose.yml
services:
  kellyfin:
    image: hienanh/kellyfin:latest
    container_name: kellyfin
    restart: unless-stopped
    user: "1000:1000"
    ports:
      - "8024:8080"
    environment:
      KELLYFIN_ADMIN_PASSWORD: change-me     # first start only; otherwise a random one is logged
    devices:
      - /dev/dri:/dev/dri                    # AMD / Intel GPU (VAAPI)
    group_add:
      - "110"                                # the host's "render" group id
    volumes:
      - ./data:/data                         # database, images, transcode scratch
      - /path/to/movies:/movies:ro           # media; drop :ro to use narration (it writes into these folders)
docker compose up -d

Open http://<server>:8024, sign in as root, then add libraries in Settings → Libraries (folders are picked from what the container sees). Only narration writes to media folders (an extra audio track per voice, subtitles next to the video); with read-only media everything else works.

NVIDIA instead of VAAPI: install the NVIDIA Container Toolkit and add

    deploy:
      resources:
        reservations:
          devices:
            - driver: nvidia
              count: all
              capabilities: [gpu, video]

then choose the encoder in Settings → Playback (Auto prefers NVIDIA, then VAAPI, then the CPU).

Migrate from Jellyfin

Create an API key in Jellyfin (Dashboard → API Keys), then:

# 1. Export (read-only): libraries, folders, titles, images, watch progress
docker run --rm --network host -u 1000:1000 -v $PWD/jellyfin-export:/out hienanh/kellyfin \
  kellyfin jellyfin-export --url http://localhost:8096 --key <API_KEY> --out /out

# 2. Import into Kellyfin, then scan (add --map FROM=TO if media paths differ)
docker compose run --rm -v $PWD/jellyfin-export:/exp:ro kellyfin kellyfin import /exp

Mount the media at the same paths Jellyfin used, or map them with --map /old/path=/new/path. Jellyfin passwords cannot be exported: set them again with docker exec kellyfin kellyfin passwd <user> <password>. Afterwards, Dashboard → Wrong titles and thumbnails finds names and posters Jellyfin had matched to the wrong film.

AI upscaling (experimental)

A worker runs on a machine with an NVIDIA GPU, asks the server for jobs, and uploads the upscaled video. It needs no open port: it only connects to the server.

cd upscaler
KELLYFIN_URL=http://<server>:8024 KELLYFIN_UPSCALER_TOKEN=<token from Settings → AI upscale> docker compose up -d

Then queue a library in Settings → AI upscale, or one episode with AI upscale on its page. Models: lanczos (a plain resize, to try the pipeline), realesrgan-anime when realesrgan-ncnn-vulkan is installed, and your own trained models as upscaler/models/<name>.sh scripts (see the README there).

Narration (thuyết minh)

Needs a machine with an NVIDIA GPU for the services (Whisper, Argos/LibreTranslate, VieNeu-TTS behind one nginx) and the kellyfin-narrator worker; narrator/docker-compose.yml starts all of them (details in narrator/README.md):

cd narrator
cp .env.example .env    # KELLYFIN_URL, and KELLYFIN_NARRATOR_TOKEN from Settings → Narration
docker compose up -d

The worker connects to Kellyfin by itself and reports in Settings → Narration whether each service answers; queue a library there (spoken language: detect, or pick one) or one video with Narration on its page. Per video: subtitles in the spoken language (the video's own, else Whisper) → English, Vietnamese and Chinese subtitles (Argos) → Vietnamese voice (VieNeu) and Chinese voice (edge-tts, needs Internet) → mixed over the ducked original sound. The results go into the video folder: <video>.<lang>.srt beside it, and one more language-tagged audio track per voice muxed into the video file itself (video copied, not re-encoded; the new file is checked before it replaces the old one). The media folders must be mounted writable for this.

Command line

kellyfin [serve]                     run the server (default)
kellyfin scan                        scan every library
kellyfin import DIR [--map FROM=TO]  import an export (Jellyfin or Kellyfin)
kellyfin export DIR                  export libraries, titles, custom images, watch progress
kellyfin jellyfin-export --url URL --key KEY --out DIR
kellyfin repair [--apply]            list (or fix) titles/posters of unrelated films
kellyfin passwd USER PASSWORD

Environment: KELLYFIN_DATA (/data), KELLYFIN_ADDR (0.0.0.0:8080), KELLYFIN_ADMIN_USER (root), KELLYFIN_ADMIN_PASSWORD.

Development

server/      Rust: axum, SQLite, ffmpeg — API, scanning, images, streaming, transcoding
src/         SolidJS + TypeScript web client (also bundled into the apps)
src-tauri/   Tauri 2 shell for desktop and mobile, with a local proxy for header-protected servers
scripts/     version bump, local fallback builds, release publishing
npm install
KELLYFIN_DEV_SERVER=http://<server>:8024 npm run dev   # web client on :1420, proxies /api and /img
cd server && cargo run                                 # server on :8080 (needs ffmpeg and ffprobe)
npm run tauri dev                                      # desktop app

Every push to main is built and tested by GitHub Actions and pushes the Docker image; a push that bumps the version publishes the version in package.json as a release with all apps. How everything works, the reasons behind it and the open items are in docs/HANDOFF.md.

License

MIT

About

Koi's Jellyfin - Smoother, simplier - Vibe Coding

Resources

Stars

1 star

Watchers

0 watching

Forks

Releases

Packages

Contributors

Languages