Skip to main content

anime-sh

Watch anime from your terminal.

Type a title. It finds a source, picks a mirror that works, and plays it in mpv.
Providers, mirrors and resolvers are plumbing you never have to think about.

PyPI Downloads Python CI Providers License: MIT

anime-sh at 190 by 50: a one-row top bar, then a large cover-art panel for the highlighted show with its title, format, genres, airing status, progress bar, synopsis and a filled bar reading resume episode 8, and below it horizontal shelves of cover-art posters for Continue Watching and Favourites, each poster captioned with its title and how far through it you are

🚀 One line, from nothing

Both of these work on a machine with nothing on it. No Python, no administrator, no editing PATH by hand. mpv is installed alongside, because without it nothing plays.

Windows — paste into a normal PowerShell, not an administrator one:

irm https://raw.githubusercontent.com/Anime123450/anime-sh/master/install.ps1 | iex

macOS and Linux:

curl -LsSf https://raw.githubusercontent.com/Anime123450/anime-sh/master/install.sh | sh

Then run anime.

What those scripts do — and how to check one before you run it

Piping a script off the internet into your shell deserves a look first. Both take --dry-run, which prints every step and changes nothing:

irm https://raw.githubusercontent.com/Anime123450/anime-sh/master/install.ps1 -OutFile install.ps1
.\install.ps1 -DryRun
curl -LsSf https://raw.githubusercontent.com/Anime123450/anime-sh/master/install.sh -o install.sh
sh install.sh --dry-run

They are install.ps1 and install.sh in this repo, short enough to read in a minute.

On Windows it installs Scoop if you do not have it, adds the extras bucket (mpv lives there) and the anime-sh bucket, then installs anime-sh and mpv. Scoop is per-user, so nothing prompts for administrator and nothing is written outside your own profile.

On macOS and Linux it installs mpv with whatever package manager you already have — Homebrew, apt, dnf, pacman, zypper or apk — then installs uv and installs anime-sh with it. uv brings its own Python, so none needs to be on the system.

Both re-read PATH before finishing, so anime works in the window you ran them from rather than only the next one. Both are safe to run twice: a second run upgrades. Add -WithFfmpeg or --with-ffmpeg to also install ffmpeg, which only anime download needs.


📖 Contents

⚡ Install · 🔌 PATH · ▶️ A minute with it · 🎬 What you get · 🚀 First run · ⌨️ Keys · 🎨 Themes · 🔗 AniList · 📋 Commands · ⚙️ Config · 🩺 Troubleshooting · 🛠️ Develop


⚡ Install

Prefer to drive your own package manager? Each of these is live.

Channel Platform Brings mpv anime on PATH
🥄 Scoop Windows ✅ ✅ straight away
🍫 Chocolatey Windows ✅ ✅ after a new terminal
🍺 Homebrew macOS · Linux ✅ ✅ straight away
🐍 uv any ❌ ✅ via uv tool update-shell
📦 pipx any ❌ ✅ via pipx ensurepath
🐧 AUR Arch ✅ ✅ straight away
🧱 Single .exe Windows ❌ ❌ you pick where it lives

🥄 Scoop — the quickest route on Windows

# Skip these two if you already have Scoop.
Set-ExecutionPolicy -ExecutionPolicy RemoteSigned -Scope CurrentUser
Invoke-RestMethod -Uri https://get.scoop.sh | Invoke-Expression

scoop bucket add extras
scoop bucket add anime-sh https://github.com/Anime123450/scoop-anime-sh
scoop install anime-sh

Use a normal PowerShell. Scoop installs per-user and refuses to run elevated.

The first line is what stops Windows refusing the second one with a message about running scripts being disabled. It applies to your account only, and RemoteSigned still requires downloaded scripts to be signed — it is what Microsoft ships on Windows Server. Answer Y when it asks.

The extras bucket is not optional. mpv lives there, a fresh Scoop has only main, and anime-sh declares mpv as a dependency — so without that bucket the install stops on something it cannot resolve.

Scoop's shims directory went on your PATH when you installed Scoop, so anime works immediately in the same window.

🍫 Chocolatey

choco install anime-sh

mpv comes with it. For downloads, choco install ffmpeg.

Chocolatey edits the machine PATH, which your current terminal read when it started. Open a new one.

🍺 Homebrew — macOS and Linux

brew tap Anime123450/anime-sh
brew install anime-sh

mpv comes with it. For downloads, brew install ffmpeg.

This builds from source: 10–20 minutes. Two CI runs of 0.2.89 measured 11m and 12m on macOS, 14m and 20m on Linux — runner speed is most of the spread. A tap carries no prebuilt bottles, so Homebrew builds anime-sh and any dependency it cannot pour — pydantic-core is Rust, and it is most of that time. Upgrades reuse what is already built.

It used to be closer to an hour, almost all of it compiling Pillow; 0.2.89 pours Homebrew's instead.

If that is still unappealing, the one-liner at the top uses uv and finishes in seconds.

🐍 uv — any OS, no Python needed

uv is one standalone binary that brings its own Python, so this works on a machine with no Python at all.

# 1. uv, and mpv
curl -LsSf https://astral.sh/uv/install.sh | sh    # macOS / Linux
brew install mpv                                   # or apt / dnf / pacman

# 2. anime-sh
uv tool install "anime-sh[tui]"

# 3. put it on PATH, once
uv tool update-shell

On Windows the same thing, with winget install astral-sh.uv and winget install shinchiro.mpv for step 1.

Do not drop the [tui]. Without it anime still installs and anime --version still answers, so a missing extra is easy to miss until the interface refuses to start.

uv tool update-shell edits the right profile for your shell. Open a new terminal afterwards, or export PATH="$HOME/.local/bin:$PATH" for this one.

📦 pipx

pipx install "anime-sh[tui]"
pipx ensurepath

pipx is itself a Python package, so it cannot be the first thing installed on a clean machine. Already have it? Then this is fine.

🐧 Arch

yay -S anime-sh    # or: paru -S anime-sh
Other ways in — one file, no terminal, or from source

Just the executable. Every release carries anime-sh-<version>-windows-x64.exe, about 21 MB with Python and every library inside it. Download it and run it; there is no install step. You still need mpv on your PATH, and since you chose where the .exe lives, putting that on PATH is yours to do as well.

No terminal at all. Download this repo as a ZIP, unzip, double-click run-anime.bat. It installs what is missing and starts the app.

From source:

git clone https://github.com/Anime123450/anime-sh.git && cd anime-sh
uv sync --extra tui
uv run anime

🔌 Will anime be on my PATH?

Yes, with every method except the bare .exe. The longer answer earns its space, because "command not found straight after installing" is the most common thing people hit and it is almost never a broken install.

Why it happens. A program is found by searching the directories in PATH. An installer adds its directory to the stored PATH, but a terminal reads that value once, when it opens. Your terminal is still holding the old copy. The install worked. The window has not heard about it.

Installed with What to do
One-line installer Nothing. Both scripts re-read PATH before finishing.
Scoop Nothing. The shims directory went on PATH with Scoop itself.
Chocolatey Open a new terminal.
Homebrew Nothing, as long as brew works in that shell.
uv uv tool update-shell once, then a new terminal.
pipx pipx ensurepath once, then a new terminal.
Bare .exe Add its folder to PATH, or run it by full path.

Repair the window you already have, without restarting it:

# Windows
$env:Path = [Environment]::GetEnvironmentVariable('Path','Machine') + ';' +
            [Environment]::GetEnvironmentVariable('Path','User')
# macOS / Linux
export PATH="$HOME/.local/bin:$PATH"

Two copies? Install with two managers and anime exists twice, with PATH order quietly deciding which runs — so upgrading one can look like it did nothing at all. where.exe anime on Windows, which -a anime on Unix, lists every match. The Windows one-line installer warns about this rather than silently adding a second.

What you need alongside it

Why Required?
🎥 mpv plays the video yes — every package manager above brings it
✂️ ffmpeg saves downloads only for anime download
🐍 Python 3.11+ runs the app only for the uv, pipx and source installs

anime doctor checks all of them and prints the exact command for whichever package manager you actually have. anime doctor --streams goes further and plays something through each provider from your own connection, which answers "is it broken, or is it me?"


▶️ A minute with it

anime-sh in use: the home screen with Continue Watching, typing a search, a show's episodes as a grid, and the same episodes as a list

Home · search-as-you-type · a show's episodes, in two of the three layouts

Every frame is the real application, rendered and captured from the app itself. Not a mockup of it.


🎬 What you get

🔎 Forgiving search atack on titan, dont toy with me — it finds them anyway
🎥 Plays in mpv driven over JSON IPC, and your own mpv config still applies
⏭️ Skips intros and outros then rolls straight into the next episode
📚 Remembers everything resume position, history and favourites, in a local database
🔄 AniList two-way sync finish an episode here and your phone knows
🧩 Multiple providers fanned out behind circuit breakers, so one site dying is not an outage
🖼️ Cover art in the terminal unicode block sextants, sharper again on Sixel or kitty
🎨 Nine themes previewed live as you arrow through them
🧱 Layouts that fit you episodes as a grid, a list or compact; two home densities
⬇️ Downloads ffmpeg-backed, resumable, played back offline automatically
🎒 Stocks up before you ask prefetch saves the next episode of everything you are watching
📊 Your year, wrapped streaks, top shows and busiest day, as a shareable SVG card
🔌 Plugin providers a provider is an entry point, so adding one needs no fork

🚀 First run

anime            # the TUI

One show leads, large, at the top: its cover art beside what it is, how far into the episode you got, when the next one airs, and what Enter will do.

Under it are shelves of cover art you walk sideways — Continue Watching, Favourites, This Season, Trending. ← → move along a shelf, ↑ ↓ change shelves, and a digit jumps straight to one. Whatever the cursor lands on becomes the show at the top, so the detail is always for exactly one thing and never for all of them at once. Each poster carries its own one line of state underneath — ep 8 · 18%, 3 eps ready, ep 9 in 1d 4h. The bottom row always says what the poster under the cursor can do.

It fits what it is given. Posters stay 14 cells wide at every size, so a wider terminal means more shows on a shelf rather than bigger ones; the panel at the top grows its poster from 16 cells to 24 across the breakpoints, and drops out below 30 rows, where the shelves need every row there is. v tightens the spacing if you would rather have one more shelf than the air between them.

Covers are cached on disk after the first fetch, so every launch after the first paints the whole wall in one frame. anime cache info says how much that is, and anime cache clear takes it back.

Prefer one-shot commands? anime "Frieren" searches, takes the best match and plays episode 1. anime play "Frieren" -e 18 --dub -q 1080p spells it all out.

Shell tab-completion is one command: anime --install-completion.


⌨️ Keys

Key Does
🕹️ ← → / h move along a shelf
🎚️ ↑ ↓ / j k move between shelves
⤒ Home / End first / last poster on this shelf
⤓ g / G first / last shelf
↹ Tab / Shift+Tab next / previous shelf
🔢 1 2 3 4 Continue · Favourites · This Season · Trending
▶️ Enter open a show, or play the highlighted episode
🔎 / search
↩️ Esc clear the search, or go back
📺 l your AniList list
🎨 t theme picker
🧩 p providers — which sources get searched
🧱 v view — tighter shelves, or episode layout on a show
⏭️ n next season, on a show
❓ ? every key, any time
🎛️ Ctrl+P command palette
🚪 q quit

🎨 Themes

Press t. Moving the cursor applies each theme to the whole app at once, so you choose by looking at anime-sh rather than at a list of names. Enter keeps it, Esc restores the one you arrived with.

Three are anime-sh's own — midnight (the default), ember and paper — next to tokyo-night, nord, gruvbox, dracula, catppuccin-mocha and solarized-light.

Cover art is drawn with unicode block sextants, so no special terminal is required — a poster on a shelf is 14 cells wide and the one at the top is 24. On Sixel or kitty terminals the large one sharpens to a true bitmap automatically.


🔗 Linking AniList (optional)

Everything works without an account. Linking one adds two-way sync: finish an episode here and your phone knows, and anime sync pull brings in whatever you have been watching elsewhere.

anime-sh ships no API credentials, and there is no shared app to sign in through. You create your own client. It takes about a minute, and it means the token belongs to you:

  1. Open AniList → Settings → Developer and create a client.
  2. Name: anything. Redirect URL: https://anilist.co/api/v2/oauth/pin
  3. Link it:
anime auth login --client-id <YOUR_ID> --secret <YOUR_SECRET>

The token is written to your own config directory with 0600 permissions, goes nowhere but AniList, and anime auth logout deletes it. Nothing about your account is stored in this project.


📋 Command reference

Every command — watch, discover, library, downloads, housekeeping
# ▶️  Watch
anime                          # the TUI
anime "Frieren"                # search, best match, play episode 1
anime play "Frieren" -e 18     # a specific episode
anime play "Frieren" --dub -q 1080p
anime resume                   # pick up the show you watched most recently
anime continue                 # what to watch next in every show you have going
anime sources "Frieren"        # every provider entry that matches
anime next "Frieren"           # find and play the sequel

# 🔭  Discover
anime search "frieren"         # AniList search, no providers touched
anime trending
anime seasonal                 # defaults to the current season
anime calendar                 # what is airing, and when
anime random
anime recommend "Frieren"
anime related "Frieren"

# 📚  Library and tracking
anime history
anime stats                    # what you watched here, plus your tracker's total
anime wrapped                  # your year, with a shareable SVG card
anime favorite add "Frieren"
anime favorite list
anime unmark "Frieren"         # clear local progress for a show

# 🔗  AniList
anime auth login --client-id <ID> --secret <SECRET>
anime auth logout
anime list --status watching
anime rate "Frieren" 9
anime status "Frieren" completed
anime sync push                # episodes you finished  ->  AniList
anime sync pull                # AniList  ->  local library

# ⬇️  Downloads
anime download "Frieren" -e 1-12
anime downloads                # what is already on disk
anime prefetch                 # next episode of everything you are watching

# 🎨  Appearance
anime themes

# 🧹  Housekeeping
anime doctor                   # player, ffmpeg, cover art, config, database, plugins
anime doctor --streams         # actually play through each provider
anime providers health         # circuit-breaker state per provider
anime config get ui.theme
anime config set ui.theme ember
anime --install-completion

⚙️ Config

anime config set <section>.<key> <value> writes one; anime config get reads it back. Only keys you set are stored, so defaults can keep improving without your file pinning them in place.

Section Keys
player name, args
playback quality, audio, auto_next, skip_intro, skip_outro, prefer_downloads
providers parallel, preferred, disabled, timeout_s, match_timeout_s, hianime_base
resolvers disabled
ui theme, episodes, density
downloads dir
anime config set playback.audio dub
anime config set playback.quality 1080p
anime config set ui.episodes grid
anime config set downloads.dir ~/Videos/anime

Any of them can be set by environment variable instead, which is the easier route for one-off runs and for scripts that should not touch your config file. The name is ANIME_SH_, the section, two underscores, then the key — and it wins over the file for that one setting, leaving the rest of your config alone.

ANIME_SH_PLAYBACK__AUDIO=dub anime play "Frieren"
ANIME_SH_UI__THEME=nord anime

When more than one of them sets the same thing, the winner is, highest first: a flag on the command line, an environment variable, your config file, the built-in default.


🩺 Troubleshooting

Symptom What is going on
🤔 anime not recognised right after installing The install worked; your shell has a stale PATH. See PATH.
🎥 doctor says mpv not found Nothing plays without it. doctor prints the right command for your package manager, or use scoop install mpv / brew install mpv / choco install mpvio.
🧊 A show will not play Plain anime doctor now carries a provider health line reading what the circuit breaker already learned on previous runs — it names any provider that is open or half-open and how many failures got it there, without touching the network. anime doctor --streams goes further and actually plays through each provider from your connection. A dead provider is normal and the fan-out routes past it; anime providers health shows the full counts.
🔇 Dub not playing anime config set playback.audio dub, or pass --dub per run. Not every provider carries one.
🐍 pipx or pip "not recognised" The wrong starting point on a clean machine — both are Python packages. Use the one-liner at the top, or scoop/choco.
🖼️ Cover art looks blocky anime doctor — run on its own, not piped — says which renderer the TUI will use. unicode blocks with no complaint beside it means your terminal reported no Sixel or kitty graphics, and that fallback is doing its job. A ✗ saying textual-image did not record a finished capability probe means a bitmap was refused rather than drawn: reinstall with uv tool install --force "anime-sh[tui]", and report the line if it survives that. true bitmap alongside a blocky poster is a bug worth reporting. ANIME_SH_NO_GRAPHICS=1 forces the blocks.
🧵 Cover art is sharp but slightly soft doctor also prints the character-cell size posters are scaled against. Posters are scaled to that size, so a wrong one has the terminal resampling the image. 10×20px is the only reading that is ambiguous — it is both a real answer (Windows Terminal replies exactly that) and textual-image's fallback when nothing replies. If your cells are not that size, set TEXTUAL_CELL_WIDTH and TEXTUAL_CELL_HEIGHT to the real one.
📺 Two anime commands Installed with two managers. where.exe anime or which -a anime finds both; remove the one you do not want.

🛠️ Develop

git clone https://github.com/Anime123450/anime-sh.git && cd anime-sh
uv sync --extra dev --extra tui
uv run pytest -q          # the full suite
uv run lint-imports       # layering contracts
uv run anime

The architecture is layered, and the layering is enforced rather than aspirational: cli > tui > app > domain, with infra, providers and resolvers as adapters. uv run lint-imports fails the build when a layer reaches somewhere it should not.

Providers and resolvers are found through entry points (anime_sh.providers, anime_sh.resolvers), so a new one is just a package that declares one.

A nightly canary plays a real episode through every provider and opens an issue when one breaks. It fails the run only when nothing can play, because a single provider dying is the normal operating state here, and an alert that fires every night is one nobody reads.

📄 Architecture · Writing a plugin · Engineering standards · Contributing · Packaging

The engineering standards are worth a read even if you never contribute — every rule names the bug that caused it.


anime-sh is a client, not a content library. It bundles no media, mirrors nothing, and bypasses no DRM. Providers read public pages and are expected to break; a broken provider is a degraded experience rather than an outage, and provider plugins are separable from the core, so the project outlives any one of them.

mpv and ffmpeg are declared as dependencies and never redistributed. Both are GPL-licensed, and shipping their binaries inside an MIT release would carry obligations that depending on them does not.

Not affiliated with AniList, mpv, or any provider.


Metadata

Release files for anime-sh 0.2.92

For a detailed explanation of source distributions (sdists) and built distributions (wheels), please see the package formats documentation.

Source distribution (sdist)

Source distribution for anime-sh 0.2.92
File Size Uploaded
anime_sh-0.2.92.tar.gz 236.1 kB Details

Built distribution (wheel)

Table of built distributions (wheels) for anime-sh 0.2.92
File Interpreter ABI Platform
anime_sh-0.2.92-py3-none-any.whl Python 3 none any Details

Total release size: 516.5 kB

Release files / anime_sh-0.2.92.tar.gz

Download URL anime_sh-0.2.92.tar.gz
Size 236.1 kB
Tags Source
SHA-256 checksum
How to use checksums
7665e744b571cd32608d6121fa59d68452435c161a3ee97c303484e80b3c6e80
BLAKE2b-256 checksum
How to use checksums
690a8bb53f0bbea5e97f7dd5540aee1936275c4f151829efadfe22744cb115fb
Upload date
Uploaded using Trusted Publishing?
What is trusted publishing?
Yes
Uploaded via twine/7.0.0 CPython/3.13.14

Provenance

Provenance describes where a file came from. On PyPI, provenance is shared via attestations, which provide a verifiable record of the build or publishing details. View details, limitations and caveats.

PyPI Publish Attestation

PyPI verified that this artifact, at this checksum, originated from the publisher listed below.

Signed by GitHub Actions, verified by PyPI on Oct 4, 2026.

Transparency log

Release files / anime_sh-0.2.92-py3-none-any.whl

Download URL anime_sh-0.2.92-py3-none-any.whl
Size 280.4 kB
Tags Python 3
SHA-256 checksum
How to use checksums
6fbc867be7b33b52752cfe13bae42e2f1027f96c4473c1da23c506e63596a01d
BLAKE2b-256 checksum
How to use checksums
cfb721ba7feba1cc220aa7704b17409142bfe14bae68b03de331f676e6bc6669
Upload date
Uploaded using Trusted Publishing?
What is trusted publishing?
Yes
Uploaded via twine/7.0.0 CPython/3.13.14

Provenance

Provenance describes where a file came from. On PyPI, provenance is shared via attestations, which provide a verifiable record of the build or publishing details. View details, limitations and caveats.

PyPI Publish Attestation

PyPI verified that this artifact, at this checksum, originated from the publisher listed below.

Signed by GitHub Actions, verified by PyPI on Oct 4, 2026.

Transparency log

Release history Release notifications | RSS feed

This release

0.2.92 This release

2 release files

0.2.84

2 release files

0.2.83

2 release files

0.2.82

2 release files

0.2.81

2 release files

0.2.68

2 release files

0.2.67

2 release files

0.2.66

2 release files

0.2.65

2 release files

0.2.64

2 release files

0.2.63

2 release files

0.2.61

2 release files

0.2.60

2 release files

0.2.59

2 release files

0.2.58

2 release files

0.2.57

2 release files

0.2.56

2 release files

0.2.55

2 release files

0.2.54

2 release files

0.2.53

2 release files

0.2.52

2 release files

0.2.51

2 release files

0.2.50

2 release files

0.2.49

2 release files

0.2.48

2 release files

0.2.47

2 release files

0.2.46

2 release files

0.2.45

2 release files

0.2.44

2 release files

0.2.43

2 release files

0.2.34

2 release files

0.2.33

2 release files

0.2.32

2 release files

0.2.31

2 release files

0.2.30

2 release files

0.2.29

2 release files

0.2.28

2 release files

0.2.27

2 release files

0.2.26

2 release files

0.2.25

2 release files

0.2.24

2 release files

0.2.23

2 release files

0.2.22

2 release files

0.2.21

2 release files

0.2.20

2 release files

0.2.19

2 release files

0.2.18

2 release files

0.2.17

2 release files

0.2.16

2 release files

0.2.15

2 release files

0.2.14

2 release files

0.2.13

2 release files

0.2.12

2 release files

0.2.11

2 release files

0.2.10

2 release files

0.2.9

2 release files

0.2.8

2 release files

0.2.7

2 release files

0.2.6

2 release files

0.2.5

2 release files

0.2.4

2 release files

0.2.3

2 release files

0.2.2

2 release files

0.2.1

2 release files

0.2.0

2 release files

Anthropic, PBC Visionary sponsor Bloomberg Visionary sponsor Hudson River Trading Visionary sponsor Meta Visionary sponsor NVIDIA Visionary sponsor Microsoft Sustainability sponsor Depot Continuous Integration AWS Cloud computing and Security Sponsor Datadog Monitoring Fastly CDN Google Download Analytics Sentry Error logging StatusPage Status page