research api next up is starting to write it
This commit is contained in:
+205
@@ -0,0 +1,205 @@
|
||||
# Project Plan: Anime (Rust GUI)
|
||||
|
||||
A cross-platform (Arch Linux + Windows) GUI application for searching, browsing, and watching anime. Inspired by [ani-cli](https://github.com/pystardust/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](./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
|
||||
|
||||
```rust
|
||||
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):
|
||||
```json
|
||||
[
|
||||
{
|
||||
"show_id": "abc123",
|
||||
"title": "Cyberpunk Edgerunners",
|
||||
"episode": "5",
|
||||
"mode": "sub",
|
||||
"last_watched": "2026-04-14T12:00:00Z"
|
||||
}
|
||||
]
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## Download Strategy
|
||||
|
||||
### Direct MP4 links
|
||||
- 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
|
||||
Reference in New Issue
Block a user