Files
anishio/plan.md
T
2026-04-16 09:46:22 +02:00

8.2 KiB

Project Plan: Anime (Rust GUI)

A cross-platform (Arch Linux + Windows) GUI application for searching, browsing, and watching anime. Inspired by ani-cli.

Features

Core (MVP)

  • Search anime by name via the AllAnime GraphQL API
  • Display search results in a list
  • Select an anime and view its available episodes
  • Select an episode to play in the OS default media player
  • Watch history -- track what you've watched, resume from where you left off

Extended

  • Download episodes (mp4 direct download via reqwest, m3u8 via yt-dlp/ffmpeg subprocess)
  • Download progress bar
  • Sub/Dub toggle
  • Quality selection
  • Episode range selection for batch downloads

Tech Stack

GUI Framework

egui / eframe

  • Immediate-mode GPU-rendered GUI
  • Single binary, no runtime dependencies
  • Native look on both Linux and Windows
  • Easy to iterate on, good for list-based UIs

Crates

Crate Version Purpose
eframe latest Window management, OpenGL/wgpu backend for egui
egui latest Immediate-mode UI widgets (comes with eframe)
reqwest latest HTTP client for GraphQL API calls and mp4 downloads
tokio latest Async runtime (required by reqwest, keeps GUI responsive)
serde latest Serialization framework
serde_json latest JSON parsing for GraphQL responses
open latest Open video URL in OS default player (xdg-open on Linux, start on Windows)
directories latest Cross-platform paths for config/state (history file)
anyhow latest Ergonomic error handling with context
indicatif latest Progress bars for downloads (can integrate into egui)

Standard Library (no extra crate needed)

Module Purpose
std::process::Command Shell out to yt-dlp / ffmpeg for m3u8 downloads
std::fs Read/write history file

External Tools (runtime, not compile-time)

Tool Required? Purpose
mpv / vlc / system default Yes (any player) Video playback
yt-dlp For m3u8 downloads HLS stream downloading
ffmpeg Fallback for m3u8 HLS stream downloading (if yt-dlp unavailable)

Architecture

src/
├── main.rs              -- App entry, eframe::run_native() setup
├── app.rs               -- Main App struct implementing eframe::App
│                           Holds app state, routes between views
├── views/
│   ├── mod.rs
│   ├── search.rs        -- Search input + results list view
│   ├── episodes.rs      -- Episode list view for a selected anime
│   └── player.rs        -- "Now playing" view (current episode, next/prev controls)
├── api/
│   ├── mod.rs
│   ├── client.rs        -- Shared reqwest::Client setup (user-agent, referer)
│   ├── search.rs        -- search_anime() -- GraphQL search query
│   ├── episodes.rs      -- episodes_list() -- GraphQL episodes query
│   ├── sources.rs       -- get_episode_url() -- GraphQL embed query + provider decoding
│   ├── providers.rs     -- Provider-specific link extraction (wixmp, hianime, etc.)
│   └── cipher.rs        -- Hex substitution cipher for decoding provider URLs
├── download.rs          -- Download logic: direct mp4 via reqwest, m3u8 via subprocess
├── history.rs           -- Read/write watch history to local state file
└── player.rs            -- Launch video in OS default player via `open` crate

Data Flow

┌──────────────────────────────────────────────────────────────┐
│                         GUI (egui)                           │
│                                                              │
│  ┌─────────┐    ┌────────────┐    ┌────────────────────┐    │
│  │ Search  │───>│  Episodes  │───>│  Play / Download   │    │
│  │  View   │    │    View    │    │       View         │    │
│  └─────────┘    └────────────┘    └────────────────────┘    │
│       │               │                  │         │        │
└───────┼───────────────┼──────────────────┼─────────┼────────┘
        │               │                  │         │
        v               v                  v         v
   search_anime()  episodes_list()  get_episode_url()│
        │               │                  │         │
        └───────┬───────┘                  │    ┌────┘
                v                          v    v
        AllAnime GraphQL API         ┌──────────────┐
        (api.allanime.day)           │   Playback   │
                                     ├──────────────┤
                                     │ open crate   │ -> OS default player
                                     │ reqwest      │ -> direct mp4 download
                                     │ yt-dlp/ffmpeg│ -> m3u8 download
                                     └──────────────┘

API Details

See ani-cli.md for full documentation of:

  • GraphQL queries and variables
  • Hex substitution cipher mapping
  • Provider-specific link extraction
  • Video source formats (mp4 vs m3u8)

Key Constants

const USER_AGENT: &str = "Mozilla/5.0 (Windows NT 10.0; Win64; x64; rv:109.0) Gecko/20100101 Firefox/121.0";
const ALLANIME_REFERER: &str = "https://allmanga.to";
const ALLANIME_API: &str = "https://api.allanime.day";
const ALLANIME_BASE: &str = "allanime.day";

History File

  • Linux: ~/.local/state/anime/history.json
  • Windows: C:\Users\<user>\AppData\Local\anime\state\history.json
  • Resolved via the directories crate (ProjectDirs::from("", "", "anime"))

Format (JSON for easy serde):

[
  {
    "show_id": "abc123",
    "title": "Cyberpunk Edgerunners",
    "episode": "5",
    "mode": "sub",
    "last_watched": "2026-04-14T12:00:00Z"
  }
]

Download Strategy

  • Use reqwest to stream the response body to a file
  • Show progress via content-length header + bytes received
  • No external tools needed

m3u8 / HLS streams

  • Shell out to yt-dlp (preferred) or ffmpeg (fallback) via std::process::Command
  • Pass referrer header as argument
  • Capture stdout/stderr for progress reporting
  • This avoids reimplementing HLS segment fetching, concatenation, and remuxing

Download directory

  • Default: current working directory (or configurable)
  • File naming: <anime_title> Episode <number>.mp4

Build Targets

Platform Target Triple Notes
Arch Linux x86_64-unknown-linux-gnu Primary dev target
Windows x86_64-pc-windows-msvc Cross-platform support

Both are tier 1 Rust targets with full support.


Implementation Order

  1. Project setup -- Add dependencies to Cargo.toml, basic eframe window
  2. API client -- reqwest client with correct headers, test connectivity
  3. Cipher -- Implement hex substitution decoder
  4. Search -- GraphQL search query, parse results
  5. Episodes -- GraphQL episode list query, parse results
  6. Sources -- GraphQL embed query, decode providers, extract video links
  7. Playback -- Open video URL in default player via open crate
  8. GUI: Search view -- Text input, results list, selection
  9. GUI: Episodes view -- Episode list, selection, play button
  10. GUI: Now playing view -- Current episode info, next/prev/replay controls
  11. History -- Read/write history file, continue watching flow
  12. Downloads -- Direct mp4 download, m3u8 via subprocess, progress reporting
  13. Polish -- Error handling, loading states, quality selection, sub/dub toggle