# zantetsu-core
Heuristic anime metadata extraction and normalization engine.
Part of the [zantetsu](https://crates.io/crates/zantetsu) crate family.
## What it does
`zantetsu-core` parses anime release filenames into structured metadata — title,
episode number, group tag, resolution, codecs, source, and more — using a
fast regex-based heuristic engine. No machine learning, no network calls, no
runtime downloads.
## Install
```toml
[dependencies]
zantetsu-core = "0.2"
```
Requires Rust 1.85+.
## Quick start
```rust
use zantetsu_core::parser::HeuristicParser;
let parser = HeuristicParser::new().unwrap();
let result = parser
.parse("[SubsPlease] Jujutsu Kaisen - 24 (1080p) [A1B2C3D4].mkv")
.unwrap();
assert_eq!(result.title.as_deref(), Some("Jujutsu Kaisen"));
assert_eq!(result.group.as_deref(), Some("SubsPlease"));
println!("{:?}", result.resolution); // Some(Resolution::P1080)
```
## API overview
| `HeuristicParser` | Main parser — call `HeuristicParser::new()` then `.parse(filename)` |
| `Parser` | Unified wrapper around `HeuristicParser` with `ParserConfig` support |
| `ParseResult` | Structured parse output |
| `EpisodeSpec` | `Single(u32)`, `Range(u32, u32)`, `Special(f32)` |
| `Resolution` | `P480`, `P720`, `P1080`, `P2160`, `P4320` |
| `VideoCodec` | `H264`, `H265`, `AV1`, `VP9`, … |
| `AudioCodec` | `AAC`, `AC3`, `FLAC`, `Opus`, … |
| `MediaSource` | `BluRay`, `WebDL`, `HDTV`, … |
| `QualityProfile` / `QualityScores` | Score a `ParseResult` against a configurable quality profile |
## What is parsed
Given a filename like:
```
[Erai-raws] Frieren - Beyond Journey's End - 01 [1080p][HEVC][AAC][Multi-Sub].mkv
```
`zantetsu-core` extracts:
- **Group**: `Erai-raws`
- **Title**: `Frieren - Beyond Journey's End`
- **Episode**: `Single(1)`
- **Resolution**: `1080p`
- **Video codec**: `H265 (HEVC)`
- **Audio codec**: `AAC`
- **Confidence score**: `0.0–1.0`
## Error handling
All public functions return `Result<T, ZantetsuError>`. Errors are typed and
implement `std::error::Error` via `thiserror`.
```rust
use zantetsu_core::error::ZantetsuError;
match parser.parse("") {
Err(ZantetsuError::EmptyInput) => eprintln!("empty filename"),
Err(e) => eprintln!("parse error: {e}"),
Ok(r) => println!("{r:?}"),
}
```
## Related crates
| [`zantetsu`](https://crates.io/crates/zantetsu) | Unified façade — start here |
| [`zantetsu-vecdb`](https://crates.io/crates/zantetsu-vecdb) | Canonical title matching |
## License
MIT