Skip to content

Dhairya3391/kari

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 5+ providers at once (Miruro, VidNest, VidKing, WCO, 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 — Built-in HLS segment downloader (Miruro) and HTTP range-request downloader (WCO), with yt-dlp as fallback for everything else.
  • Subtitles — Pulls from OpenSubtitles automatically, Yify as fallback.
  • 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 Downloading non-Miruro/WCO sources Yes
aria2c Speeds up yt-dlp downloads Yes
curl WCO cookie bootstrap + MPV pipe playback Yes
upx Compressing build artifacts (build script only) No

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

If you don't want to install Go, grab a binary 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 (e.g. http://192.168.1.100:8096). 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 — Shows resolved sources, subtitles, 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).

Media Providers

Provider Mode Method Priority
Miruro Anime API 1
VidNest Movies, TV API (via TMDB) 1
VidKing Movies, TV API (via TMDB) disabled
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)

Android support is a bit hacky (MPV Android doesn't expose a normal config directory), but it works:

  1. Install Termux from F-Droid (not Play Store — the Play Store version is abandoned)

  2. Install dependencies:

    pkg install golang curl termux-api yt-dlp
    Package Why
    golang Build kari
    curl Cookie bootstrap + pipe-to-mpv playback
    termux-api Provides termux-am-starter to launch MPV/MX Player via Android intents (the bare am binary is broken on newer Android)
    yt-dlp Required for downloads (optional — skip if you only stream)
  3. Grant storage access (needed to write mpv.conf to the MPV Android config dir):

    termux-setup-storage

    Then allow the storage permission when prompted. Without this, kari falls back to ~/.config/mpv/mpv.conf (MPV Android may not read it).

  4. Clone and build:

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

  6. Create a mpv.conf at /storage/emulated/0/Android/media/is.xyz.mpv/mpv.conf:

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

Kari launches MPV via Android am start intents. The mpv.conf redirect lets it write playback scripts where they can actually be read. See docs/PLAYERS.md for the details of this hack.

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/    — HLS segment downloader + yt-dlp wrapper
    ├── 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.

License

MIT

About

Kari (狩り) — hunt media from the terminal. Search, stream, and download anime, movies, TV shows & cartoons across 5+ providers with MPV/IINA/VLC/MX Player support, Trakt/AniList scrobbling, and auto-subtitles.

Topics

Resources

License

Stars

27 stars

Watchers

0 watching

Forks

Packages

 
 
 

Contributors