A blazing-fast, beautiful terminal UI for searching, streaming, and downloading movies and TV shows directly from your command line.
Note: This entire project was 100% vibe coded. We didn't write massive design docs or overthink the architecture; we just caught a wave of momentum, relied on intuition, and built something awesome. 🌊
- Unified Search: Instantly query TMDB for both Movies and TV Shows.
- Smart Resolver: Uses headless browser automation (Playwright) to sniff out hidden
.m3u8streams and subtitle tracks from HLS manifests. - Multi-Source Subtitles: Extracts embedded VTT/SRT/ASS subtitles from streams, parses HLS
#EXT-X-MEDIAtags, and falls back to OpenSubtitles API when nothing is found. - Subtitle Download: Subtitles are saved alongside video files when downloading.
- Zero-Dependency HTTP: Uses
curlsubprocess calls instead ofrequests— no Python HTTP library needed. - Beautiful UI: Powered by
richfor animated spinners, colorful tables, and interactive terminal menus. - Built-in Watchlist & History: Save shows for later, and mark them as watched to build your personal streaming diary right in your terminal.
- Data Hoarder Mode: Pass the
-dflag to intercept the stream and download it straight to your drive usingyt-dlp, with subtitles bundled alongside.
mpv(The media player)yt-dlp(For resolving and downloading)curl(For API calls and subtitle downloads)- Python 3.8+
-
Clone the repository:
git clone https://github.com/dumbL4d/movie-cli.git cd movie-cli -
Install the required Python libraries:
pip install rich playwright
-
Install the Playwright browser engine (required for bypassing stream protections):
playwright install chromium
-
Set up your API keys:
cp .env.example .env
Then edit
.envwith your keys from TMDB and OpenSubtitles.
This CLI uses TMDB for metadata and optionally OpenSubtitles for subtitle fallback.
Create a .env file in the project root:
TMDB_API_KEY=your_tmdb_api_key
OPENSUBTITLES_API_KEY=your_opensubtitles_api_keySearch for a movie or TV show:
python main.py the matrixOpen your Watchlist:
python main.py -wView your Watched History:
python main.py -HForce Download Mode directly from search:
python main.py interstellar -dflowchart TD
A["`python main.py <query>`"] --> B["Search TMDB via curl"]
B --> C{"User selects result"}
C --> D["Movie?"]
D -->|Yes| E["Get stream URL from VidKing"]
D -->|No| F["Prompt season/episode"]
F --> E
E --> G["Playwright: open stream page"]
G --> H["Intercept requests/responses"]
H --> I{"Found .m3u8 stream?"}
I -->|No| J["Error: failed to resolve"]
I -->|Yes| K["Parse HLS for subtitles"]
K --> L{"Subtitles found?"}
L -->|No| M["Fallback to OpenSubtitles API"]
L -->|Yes| N["Subtitle URLs from manifest"]
M --> O["Download .srt to cache"]
N --> P{"User action?"}
O --> P
P -->|Play| Q["Launch mpv with subtitles"]
P -->|Download| R["yt-dlp video + curl/copy subtitles"]
.
├── main.py # Entry point — loads .env, runs CLI
├── cli.py # Argument parsing, search, watchlist, dispatch
├── core/
│ ├── dotenv.py # Zero-dependency .env loader
│ ├── cineby_api.py # TMDB search + VidKing URL builder via curl
│ ├── resolver.py # Playwright-based stream & subtitle resolver
│ ├── player.py # mpv launcher with subtitle support
│ ├── downloader.py # yt-dlp wrapper with subtitle download
│ ├── subtitles.py # OpenSubtitles API client via curl
│ └── storage.py # JSON-based watchlist/history persistence
├── .env.example # Template for API keys
└── .gitignore