Architecture
MovieBox-Tui is a terminal client (ratatui + crossterm + tokio) for streaming movies, series and TV channels from multiple providers. This document describes the shape of the code and how data flows through it.
System Architecture & Data Flow
┌────────────────────────────────────────────────────────┐
│ Terminal User Input & Events │
│ Crossterm KeyPress / MouseClick / WindowResize / Tick│
└───────────────────────────┬────────────────────────────┘
│
▼
┌────────────────────────────────────────────────────────┐
│ EventHandler Channel (mpsc::channel) │
│ Dispatches serialized Action messages │
└───────────────────────────┬────────────────────────────┘
│
▼
┌────────────────────────────────────────────────────────┐
│ App Event Loop & State Machine (Single Thread) │
│ src/tui/app/run.rs ─── Mutates AppState atomically │
└──────────────┬───────────────────────────┬─────────────┘
│ │
UI Render Pass │ Async IO Tasks │ Background Workers
▼ ▼
┌───────────────────────────┐ ┌───────────────────────────────────┐
│ Ratatui Terminal Frame │ │ Tokio Multi-Thread Runtime │
│ Screens / Widgets / Toast │ │ tokio::spawn / spawn_blocking │
└───────────────────────────┘ └─┬───────────────┬───────────────┬─┘
│ │ │
▼ ▼ ▼
┌────────────────┐┌─────────────┐┌─────────────────┐
│ Scrapers & Net ││ Disk Cache ││ Media Players & │
│ Providers & TV ││ MessagePack ││ Loopback Proxy │
└────────────────┘└─────────────┘└─────────────────┘
Subsystem Breakdown & Module Tree
src/
├── main.rs # Application entrypoint & CLI dispatcher
├── lib.rs # Crate root and module declarations
│
├── Core Engine & Networking
│ ├── models.rs # Domain entities (CatalogItem, MediaDetails, Release)
│ ├── service.rs # Central multi-provider facade & aggregation engine
│ ├── net.rs # Hickory DNS fallback resolver & HTTP client builders
│ ├── logging.rs # Rotating file logger with path/URL privacy sanitization
│ └── proxy.rs # Detached loopback HTTP proxy & DASH manifest rewriter
│
├── Storage & Persistence
│ ├── cache.rs # Binary MessagePack cache (MBC1 header) with atomic writes
│ ├── config.rs # User configuration schema & atomic persistence (config.json)
│ ├── favorites.rs # Bookmark storage & deduplication (favorites.json)
│ ├── history.rs # Watch progress, latched resume, & state reconciliation
│ └── download.rs # Chunked multi-segment downloader with HTTP range resume
│
├── Media Providers (`src/providers/`)
│ ├── models.rs # Provider traits (Provider, ReleaseProvider) & capabilities
│ ├── moviebox/ # CloudFront signed requests, token generation, & scraper
│ ├── fourkhdhub/ # 4K releases, HTML parser, & HubCloud mirror resolver
│ ├── dramachi/ # Asian dramas and series scraper
│ ├── bdix/ # BDIX optical intranet scrapers (CircleFTP, DhakaFlix)
│ │ └── common.rs # Centralized codec, resolution, & language heuristics
│ ├── addons/ # Community Stremio HTTP addon manifest & stream aggregator
│ └── tv/ # IPTV M3U playlist parser & stream normalizer
│
├── Player & Process Supervisor
│ ├── player.rs # Player detection (mpv, IINA, VLC, Android) & command builder
│ └── player/tracker.rs # Embedded Lua tracker script (moviebox_tracker.lua)
│
├── Self-Updater (`src/updater/`)
│ ├── check.rs # GitHub release API version checker
│ ├── download.rs # Streaming release archive downloader
│ ├── verify.rs # Cryptographic SHA-256 checksum validator
│ ├── extract.rs # Tar.gz and Zip extractor with path traversal guard
│ └── apply.rs # Atomic binary replacement, path resolution, & restart helper
│
└── Presentation & TUI (`src/tui/`)
├── action.rs # Unified Action enum message bus
├── event.rs # Crossterm terminal input event listener & tick driver
├── state.rs # Centralized AppState & LRU memory caches
├── commands.rs # Slash command registry (/settings, /browse, /exit)
├── terminal.rs # Terminal capability & graphics protocol detection
├── theme.rs # Theme registry (Catppuccin, TokyoNight, Nord, etc.)
├── text.rs # Grapheme-safe input buffer & Unicode measurement
├── overlay.rs # Toasts, modals, confirmation dialogues, & picker frames
├── screens/ # Declarative renderers (home.rs, details.rs, help.rs)
├── widgets/ # Modular widgets (badge, input, modal, poster, settings)
└── app/ # State machine action handlers & event loop
├── run.rs # Main event loop (App::run) & frame drawing
├── keyboard.rs # Keyboard shortcuts & vim navigation router
├── mouse.rs # Mouse click hit-testing & drag coordinates
├── navigation.rs # Grid steps, pagination, & screen transitions
├── requests.rs # Async metadata & stream request dispatchers
├── playback.rs # Player process launching & crash supervision
├── download.rs # Download queue manager & progress bar updates
├── search.rs # Search input handler & poster prefetching
├── favorites.rs # Favorite bookmarks handler
├── tv.rs # IPTV channel manager & playlist actions
├── addons.rs # Stremio addon manager actions
└── system.rs # Terminal resize, theme switching, & self-update UI
The event loop
App::run (in app/run.rs) owns the only loop:
- If
clear_terminal_before_drawis set, the terminal buffer is cleared. - If
state.dirty, the screen is drawn (App::draw). tokio::select!waits for either:- an
Actionfrom theEventHandler(keyboard/mouse/focus/resize/tick), or - an
Actionpushed by a background task (network results, downloads, posters).
- an
EventHandler (event.rs) spawns one task that reads crossterm events and a Tick
interval, forwarding them into the action channel (capacity 128).
Async model
- The tokio runtime is multi-threaded (
rt-multi-thread). - State is single-threaded: all mutations to
AppStatehappen insidehandle_action, which is driven by the single event-loop task. Actions are serialized through the channel, so there are no data races on UI state. - Network uses async
reqwestclients (one per provider) plus per-provider signing. - Blocking work (disk cache reads/writes, image decoding, M3U parsing, watch-history
save, log cleanup) runs on
tokio::task::spawn_blockingso the event loop is never blocked. - Background tasks send
Actionmessages back (e.g.SearchSuccess,EpisodeStreamsReady,DownloadCompleted), whichhandle_actionconsumes.
Data flow: a typical search
- User types a query; the
Keyhandler updatessearch_queryand sendsAction::Search. handle_actionresolves the active provider, dispatches to the provider client (async), and spawns the request in a background task.- On success the task sends
Action::SearchSuccess;handle_actionstoressearch_results, marksdirty, and writes the provider search cache. - Posters for result rows are fetched by background tasks and delivered via
SearchPosterLoaded/PosterSuccess; image protocols are cached per terminal. App::drawrenders the results;dirtyis cleared.
Playback flow
- User selects a result →
Action::PlayStream(moviebox) or 4KHDHub/BDIX resolve. - The provider resolves a
PlaybackSource(url + optional headers/subtitle). launch_playerbuilds the player command (player.rs), optionally downloads the subtitle to a temp file, and spawns the player in a detached OS session (setsid/DETACHED_PROCESS) with null stdin/stdout and file-backed stderr logging; a blocking task waits and reports crashes while the TUI remains open.
Configuration and persistence
config.json: settings (mode persistence, mode toggles, theme, provider, auto-update,default_player, download directory, BDIX) in the config dir.addons_config.json: installed HTTP community addons in the config dir.tv_config.json: user M3U playlist sources (URLs or file paths) in the config dir.history.json: watch history in the system data dir.favorites.json: starred titles in the system data dir, independent ofhistory.json.playback/: temporary playback states for session crash/kill reconciliation in the system data dir.scripts/: bundled player scripts (moviebox_tracker.lua) in the system data dir.- Cache lives under the system cache dir, keyed per provider.
- Logs live under the system data dir with rotation.
See config.md and logging.md for exact locations and formats.