Skip to content

Repository files navigation

Kari (狩り)

Stars License Go Version Last Commit

I wanted MPV for playback, Trakt for tracking, AniList for anime, subtitles when I needed them, and exactly zero browser tabs.

So I built Kari.

Built with Bubble Tea.

kari demo

Quick Start

git clone https://github.com/Dhairya3391/kari.git
cd kari
go build -o kari ./cmd/kari
./kari

Type a query, press Space, pick a result.

Features

  • Multi-source search — Searches multiple providers at once (MovieBox, VidKing, Miruro, WCO, and optional Jellyfin). Results grouped by source.
  • 5 media modes — Anime, Movies, TV Shows, Cartoons, Jellyfin. Switch with Tab.
  • Episode browsing — Season/episode lists with filler badges and sub/dub toggles.
  • Parallel source resolution — Queries every provider at once, shows all available qualities.
  • External player support — MPV (any OS), IINA (macOS), VLC (Windows), MX Player (Android).
  • IPC position tracking — MPV reports back via Unix socket. Close mid-episode, resume where you left off.
  • Auto-skip intro/outro — Pulls timestamps from AniSkip, generates an MPV Lua script on the fly.
  • Scrobbling — Syncs watch status to Trakt.tv (movies/TV) via device auth (no tokens to copy) and AniList (anime) via OAuth.
  • Watch history — Local JSON store, grouped by series, remembers your position.
  • Downloading — yt-dlp powered downloads with aria2c multi-connection acceleration for HLS, DASH, and direct HTTP sources.
  • Posters & metadata — TMDB/AniList poster art in search results and the preview screen, plus overview, genres, and rating. Renders as real pixel images on Kitty/WezTerm/Ghostty, and falls back to Unicode half-block art everywhere else — no config needed, capability is auto-detected.
  • Customizable accent color — Pick from curated presets or type your own hex code in Settings; applies immediately across the whole UI.
  • Download progress bar — Live byte-percentage (single downloads) or episode-count (batch downloads) progress bar during downloads.
  • Subtitles — Tries the playback provider's own subtitles first (matching your preferred language, then English), falls back to other providers, then OpenSubtitles, then Yify — never a random unrelated language. Re-syncs automatically if you switch source or change the subtitle language setting.
  • Self-update./kari -u fetches the latest release from GitHub.
  • Cross-platform — Linux, macOS, Windows, Android (Termux).

Installation

Prerequisites

At least one media player in $PATH:

Player Platforms Notes
MPV Linux, macOS, Windows, Android Full support
IINA macOS MPV-based; position tracking works
VLC Windows No position tracking
MX Player Android Launched via am start; no position tracking

Optional tools:

Tool Used for In $PATH
yt-dlp All downloads (HLS, DASH, MP4, etc.) Required for downloads
aria2c Multi-connection parallel downloads — strongly recommended for fast speeds (16 connections per file) Recommended
curl MPV pipe playback fallback Yes
upx Compressing build artifacts (build script only) No

Tip: Install aria2c for significantly faster downloads. yt-dlp uses it as an external downloader with 16 parallel connections per file. Without it, downloads use yt-dlp's single-connection HTTP client which is much slower.

# macOS
brew install aria2
# Ubuntu/Debian
sudo apt install aria2
# Arch
sudo pacman -S aria2

Build from source

git clone https://github.com/Dhairya3391/kari.git
cd kari
go build -o kari ./cmd/kari

The binary lands in the current directory as ./kari.

Pre-built binaries

macOS / Linux / Termux:

curl -fsSL https://raw.githubusercontent.com/Dhairya3391/kari/main/install.sh | bash

Windows (PowerShell):

irm https://raw.githubusercontent.com/Dhairya3391/kari/main/install.ps1 | iex

Both scripts detect your OS/architecture, download the matching binary from the latest release, and put kari on your PATH — no admin/sudo required. Set KARI_INSTALL_DIR before running to install somewhere other than the default.

Or grab a binary manually from the releases page.

Configuration

All config is through environment variables. No config files to wrangle.

Essential

Variable Description Default
KARI_PLAYER Preferred player (mpv, iina, vlc) Auto-detected

API Keys (optional — built-in fallbacks are there if you don't set these)

Variable Description
TMDB_API_KEY Your own TMDB key. If unset, a pool of built-in keys is rotated through.
OPENSUBTITLES_API_KEY OpenSubtitles API key. If unset, falls back to Yify.
OPENSUBTITLES_USERNAME Required if you set the API key.
OPENSUBTITLES_PASSWORD Same.
JELLYFIN_URL Your Jellyfin server URL (example: "https://jfn.fqdn.com/"). When set, a JELLYFIN mode appears.
JELLYFIN_API_KEY Jellyfin API key. Required if JELLYFIN_URL is set. Generate one in Dashboard → API Keys.
TRAKT_CLIENT_ID / TRAKT_ID Trakt.tv OAuth client ID
TRAKT_CLIENT_SECRET / TRAKT_SECRET Trakt.tv OAuth client secret
ANILIST_CLIENT_ID / ANILIST_ID AniList OAuth client ID
ANILIST_CLIENT_SECRET / ANILIST_SECRET AniList OAuth client secret

The binary ships with fallback keys for Trakt, AniList, and TMDB. They work fine for casual use. If you hit rate limits, set your own.

Other

Variable Description Default
KARI_DOWNLOAD_DIR Where downloaded episodes land ./downloads
KARI_LOG_FILE Log file path ~/.config/kari/kari.log
KARI_LOG_DEBUG Enable debug logging (1, true) false
KARI_LOG_STDERR Also write logs to stderr (1, true) false

Usage

./kari                    # Opens the TUI. Start typing to search.
./kari "one piece"        # Skips straight to search results.
./kari -v --version       # Print version.
./kari -u --update        # Self-update from GitHub releases.

Controls

Navigation

Key Action
↑/↓ or j/k Move through lists
Enter Select series / episode / play
Esc Go back
/ Filter list items

Search & Browse

Key Action
Space Start search
Tab / Shift+Tab Cycle media mode (Anime → Movies → TV → Cartoon → Jellyfin)
Ctrl+H Go to home/search

Playback

Key Action
n Play next episode
A Toggle autoplay
a Toggle sub/dub (anime only)
r Restart episode from beginning
Ctrl+P Switch players

Downloads

Key Action
d Download selected episode
x Stop active download / cancel

App

Key Action
h / H Open watch history
s / S Settings (Trakt/AniList auth)
Ctrl+D Toggle debug panel
q / Ctrl+C Quit

Views

  1. Search — Type a query, hit Space. Results come back grouped by provider.
  2. Episodes — Season/episode list with filler badges. Sub/dub toggle is there for anime.
  3. Preview — Poster, description, genres, rating, resolved sources, selected subtitle, and any saved position. Hit Enter to play.
  4. History — Grouped by series. Resume or delete.
  5. Settings — Authenticate with Trakt or AniList via device auth (no manual token fiddling), set quality mode, toggle MovieBox languages, pick a preferred subtitle language, toggle image rendering, and pick an accent color (curated presets or your own hex code).

Media Providers

Provider Mode Method Priority
Miruro Anime API 1
MovieBox Movies, TV API (via TMDB) 2
VidKing Movies, TV API (via TMDB) 2
WCO Cartoons, Anime HTML scraping 2
Jellyfin Movies, TV Jellyfin API 1

Lower priority = queried first. All providers are queried in parallel regardless — priority only affects result ordering when multiple providers return the same content.

Want to add another provider? See docs/PROVIDERS.md and PROVIDER_GUIDE.md.

Android Setup (Termux)

Kari supports MPV and MX Player on Android via Termux intents and automatic configuration injection:

  1. Install Termux (source) from F-Droid (do not use Play Store — the Play Store version is obsolete).

  2. Install required packages:

    pkg install golang curl termux-api yt-dlp aria2
    Package Why
    golang Build kari
    curl Direct/pipe fallback playback
    termux-api Provides the termux-am/termux-am-starter fallback for launching MPV/MX Player via Android intents (source)
    yt-dlp Required for downloads
    aria2 Multi-connection parallel downloads for fast speeds

    Kari launches players by trying am start first (works out of the box on most devices), then falling back to termux-am/termux-am-starter if am is blocked. That fallback needs the Termux:API app — a separate APK from the termux-api package above, install it from F-Droid too — and it must be opened once after install to start its background socket service. If you ever see a playback error mentioning Could not connect to socket, that service isn't running: reopen the Termux:API app (or reboot).

  3. Grant storage access:

    termux-setup-storage

    Allow storage permission when prompted. This allows Kari to write headers (Referer, Origin, User-Agent, Cookies) and subtitle files directly to the MPV Android media folder.

  4. Clone and build:

    git clone https://github.com/Dhairya3391/kari.git
    cd kari
    go build -o kari ./cmd/kari
  5. Install MPV Android (or MX Player) from Play Store.

  6. (Required, one-time) Link Kari's playback config into MPV Android — no root needed:

    Open the MPV Android app → SettingsAdvancedEdit mpv.conf, and add this single line:

    include=/storage/emulated/0/Android/media/is.xyz.mpv/.mpv.conf

    Why this step matters: mpv-android only reads configuration from its own app-data directory, which Termux apps cannot write (and it has no Intent-extra for HTTP headers). This one include= line is the sole bridge — Kari rewrites .mpv.conf in the MPV media folder on every play with fresh playback headers (Referer, Origin, User-Agent, Cookie), the title, resume position, and the subtitle track, so they reach MPV on the next launch. Do it once and every episode just works.

Note: Kari writes the playback config to .mpv.conf (and a mirrored mpv.conf) under /storage/emulated/0/Android/media/is.xyz.mpv/ on every play launch. It does not write to Termux's ~/.config/mpv/ — mpv-android's libmpv never reads that path, so headers only apply once your own app config above contains the include= line.

  1. Run ./kari

Kari launches MPV via Android am start intents (falling back to termux-am/termux-am-starter automatically if am is blocked on your device). Since Android intents can't carry stream headers, Kari injects them through the config bridge from step 6 (the include= line). See docs/PLAYERS.md for architectural details.

Note: On some Android versions, DNS resolution may fail for downloads. Kari includes a built-in fallback to Cloudflare (1.1.1.1) and Google (8.8.8.8) DNS for Android builds.

Architecture

Kari is split into three layers. Providers fetch data from streaming sites (API calls or HTML scraping). Players send media URLs to external apps (MPV, IINA, VLC, MX Player) and track playback position via IPC. Between them sits a Bubble Tea TUI that handles search, episode browsing, and download management. Each provider and player is a self-contained package — adding a new one doesn't touch anything outside its own directory.

cmd/kari/main.go
    |
internal/
    ├── app/           — Wires everything together
    ├── config/        — Environment config + API constants
    ├── service/       — Media, download, subtitle orchestration
    ├── provider/      — One package per streaming site
    ├── player/        — Platform-specific player backends
    ├── tui/           — Bubble Tea model-view-update
    ├── scrobble/      — Trakt.tv + AniList sync
    ├── history/       — Local JSON watch storage
    ├── downloader/    — yt-dlp wrapper with aria2c acceleration
    ├── subtitles/     — OpenSubtitles + Yify clients
    ├── aniskip/       — Fetches intro/outro timestamps
    ├── tmdb/          — Key pool with rotation
    ├── httpclient/    — Shared retryable HTTP client
    └── logging/       — Structured slog wrapper

See docs/ARCHITECTURE.md for more detail.

Development

Project structure

Same layout as above. cmd/kari/main.go is the entry point. Everything else lives under internal/ — one package per concern.

Cross-compile

chmod +x build.sh
./build.sh all     # linux/{amd64,arm64}, windows/{amd64,arm64},
                   # darwin/{amd64,arm64}, android/arm64

Or pick one:

./build.sh target linux amd64

Or build for whatever machine you're on:

./build.sh

Versioning

Version is derived from git tags and baked in via -ldflags:

Scenario Example
Tagged release (v1.0.0) 1.0.0
5 commits after tag 1.0.5 (patch increments)
No tags yet 1.0.42 (commit count)
Uncommitted changes 1.0.0-dirty
go run / go build (no ldflags) 0.0.0-dev

To cut a release:

git tag v1.0.0
git push origin v1.0.0

The CI builds all platforms, creates a GitHub Release, and auto-generates release notes from commits since the last tag.

Build and verify

go build ./...
go vet ./...
go test ./...

Code conventions

See docs/CONVENTIONS.md and AGENTS.md (AI assistant rules for this repo) for the full list. Key rules:

  • No global state — pass dependencies explicitly
  • Wire everything in internal/app/app.go
  • Use internal/httpclient instead of raw http.Client
  • Log through internal/logging
  • Wrap errors with %w

Contributing

Pull requests are welcome. The best place to start is adding a new media provider — see PROVIDER_GUIDE.md for the full walkthrough.

A few ground rules:

  • Run go build ./... && go vet ./... && go test ./... before opening a PR
  • Don't add global state. Wire new components in internal/app/app.go
  • Wrap errors with %w
  • Kari does not host or distribute copyrighted content. Contributions that add DRM circumvention or direct content hosting will not be accepted.

Troubleshooting

macOS — "Kari cannot be opened" or "damaged"

Downloaded binaries get flagged by Gatekeeper. Clear the quarantine attribute:

xattr -d com.apple.quarantine ./kari

If you built from source, this doesn't apply.

Linux — "Permission denied"

chmod +x ./kari

Windows — "Windows protected your PC"

Click More infoRun anyway. SmartScreen flags unsigned binaries — the binary is clean, it just isn't code-signed.

Android — MPV not launching

Ensure termux-api is installed (pkg install termux-api) and that you've run termux-setup-storage. MPV Android must be installed from the Play Store, not from Termux packages. On some devices, the am binary is blocked by SELinux — kari will automatically fall back to termux-am or termux-am-starter if available.

Android — Downloads fail with DNS errors

Kari uses a built-in DNS fallback (Cloudflare/Google) on Android. If downloads still fail, check that your network connection is active. The system DNS resolver in Termux can be unreliable — this is a known Termux limitation.

No player detected

Make sure your player is in $PATH. Run which mpv (or which iina, which vlc) to verify.

Logs

Written to ~/.config/kari/kari.log. Set KARI_LOG_DEBUG=true for verbose output. The log rotates once it passes 10MB — the previous file is kept as kari.log.1.

License

MIT

About

Kari just a tui for getting media from providers and playing it in your media player with nice to have features.

Topics

Resources

Stars

41 stars

Watchers

0 watching

Forks

Releases

Packages

Contributors

Languages