zantetsu-vecdb 0.2.0

Canonical anime title matching via Kitsu dumps or remote endpoints
Documentation
# zantetsu-vecdb

Canonical anime title matching via local Kitsu dumps or remote GraphQL endpoints.

Part of the [zantetsu](https://crates.io/crates/zantetsu) crate family.

## What it does

After a filename is parsed by [`zantetsu-core`](https://crates.io/crates/zantetsu-core),
you have a raw title string like `"Frieren - Beyond Journeys End"`. `zantetsu-vecdb`
resolves that raw string to a canonical title and cross-references it against
Kitsu/AniList/MAL identifiers.

Two backends are supported:

| Backend | When to use |
|---|---|
| **Local Kitsu dump** | Self-hosted installs with a `latest.sql` or `latest.sql.gz` file |
| **Remote GraphQL** | Any GraphQL endpoint that speaks the expected anime search schema |

## Install

```toml
[dependencies]
zantetsu-vecdb = "0.2"
```

Requires Rust 1.85+.

## Quick start — local Kitsu dump

Download the Kitsu SQL dump and point `TitleMatcher` at the directory:

```rust,no_run
use zantetsu_vecdb::{MatchSource, TitleMatcher};

let matcher = TitleMatcher::new(
    MatchSource::kitsu_dump("/home/user/.local/share/zantetsu/kitsu-dumps"),
)
.unwrap();

if let Some(hit) = matcher.match_title("Sousou no Frieren").unwrap() {
    println!("canonical title : {}", hit.canonical_title);
    println!("similarity score: {:.2}", hit.score);
    println!("kitsu id        : {:?}", hit.ids.kitsu);
    println!("anilist id      : {:?}", hit.ids.anilist);
}
```

The expected dump location on each platform:

| Platform | Default path |
|---|---|
| Linux | `~/.local/share/zantetsu/kitsu-dumps/` |
| macOS | `~/Library/Application Support/zantetsu/kitsu-dumps/` |
| Windows | `%APPDATA%\zantetsu\kitsu-dumps\` |

Use `default_kitsu_dump_dir()` to get this path at runtime.

## Quick start — remote GraphQL endpoint

```rust,no_run
use zantetsu_vecdb::{MatchSource, TitleMatcher};

let matcher = TitleMatcher::new(
    MatchSource::remote_endpoint("https://graphql.anilist.co"),
)
.unwrap();

if let Some(hit) = matcher.match_title("Spy x Family").unwrap() {
    println!("{} (score {:.2})", hit.canonical_title, hit.score);
}
```

## API overview

| Item | Description |
|---|---|
| `TitleMatcher` | Main entry point — create once, reuse for many lookups |
| `MatchSource` | Backend selector: `MatchSource::kitsu_dump(path)` or `MatchSource::remote_endpoint(url)` |
| `AnimeTitleMatch` | Match result: canonical title, similarity score, IDs, all known aliases |
| `AnimeIds` | Cross-reference IDs: `kitsu`, `anilist`, `mal` |
| `MatchProvider` | Which backend produced the result (`KitsuDump` or `RemoteEndpoint`) |
| `default_kitsu_dump_dir()` | Returns the platform default dump directory |

## Matching algorithm

Similarity is computed with [Jaro–Winkler](https://en.wikipedia.org/wiki/Jaro%E2%80%93Winkler_distance)
over all known title aliases (canonical, romanized, English, native). The
alias with the highest score is returned, along with the canonical title for
that entry. A configurable threshold filters out low-confidence matches.

## Error handling

All fallible functions return `MatchResult<T>` (`Result<T, MatcherError>`).
`MatcherError` implements `std::error::Error` via `thiserror`.

## Related crates

| Crate | Purpose |
|---|---|
| [`zantetsu`]https://crates.io/crates/zantetsu | Unified façade — start here |
| [`zantetsu-core`]https://crates.io/crates/zantetsu-core | Heuristic filename parser |

## License

MIT