# MangaDex API

Unofficial Rust client/wrapper for the MangaDex API.
This also includes some conveniences that are not provided from the API directly such as logging in.

*Warning:
This is still in the **early development stage**.
Some breaking API changes may occur as the project matures.
Consequently, this code is not yet ready for use in production.*

# Table of Contents

* [Requirements][readme-section-requirements]
* [Features][readme-section-features]
* [Optional Features][readme-section-optional-features]
* [Examples][readme-section-examples]
* [Running Examples][readme-section-running-examples]
* [License][readme-section-license]
* [Contribution][readme-section-contribution]
* [Contributing][readme-section-contributing]

# Requirements

[Back to top][readme-section-toc]

* [Rust 1.47+][rust-homepage]

# Features

[Back to top][readme-section-toc]

* [v2 support][mangadex-v2-api-index]
    * [OpenAPI Document (Unofficial)][mangadex-v2-openapi-spec]

# Optional Features

[Back to top][readme-section-toc]

* `time` - Use [Chrono][chrono-docs] for the timestamps instead of integers and arbitrary strings. 
  Included by default.

# Examples

[Back to top][readme-section-toc]

### Fetch manga by ID

```rust
use mangadex_api::v2::{responses::ResponseType, MangaDexV2};

#[tokio::main]
async fn main() -> Result<(), reqwest::Error> {
    let mangadex_client = MangaDexV2::default();

    let manga  = mangadex_client
        .manga(1)
        .send()
        .await?
        .ok()
        .unwrap();

    // Fields are hidden behind getter methods to prevent field mutation.
    // The getters return a referenced value so comparisons require de-referencing.
    assert_eq!(*manga.data().id(), 1);

    Ok(())
}
```

### Logging in

Some features on MangaDex are restricted to registered users such as searching by manga title.

In order to use these features, you must log in first and the [`Reqwest` library][reqwest-library]
will store the session cookie in the client. Once that's done, you can use call the other endpoints
normally and get the data you need.

```rust
use std::io;

use mangadex_api::v2::MangaDexV2;
use mangadex_api::web_scrape::responses::LoginAjaxResponseType;

#[tokio::main]
async fn main() -> Result<(), reqwest::Error> {
    let mangadex_client = MangaDexV2::default();

    let mut username = String::new();
    println!("Enter your MangaDex username:");
    io::stdin()
        .read_line(&mut username)
        .expect("Failed to read username");

    let mut password = String::new();
    println!("Enter your MangaDex password:");
    io::stdin()
        .read_line(&mut password)
        .expect("Failed to read password");

    // If you know that you need a 2-factor authentication code, you can add it directly before
    // sending the first login attempt and not check the `TwoFactorAuthenticationRequired` variant.
    match mangadex_client
        .login_ajax(&username, &password)
        .send()
        .await?
    {
        LoginAjaxResponseType::Ok => {
            println!("Login successful!")
        }
        LoginAjaxResponseType::TwoFactorAuthenticationRequired => {
            let mut two_factor = String::new();
            loop {
                println!("Enter your 2FA code:");
                io::stdin()
                    .read_line(&mut two_factor)
                    .expect("Failed to read 2FA code");

                match mangadex_client
                    .login_ajax(&username, &password)
                    .two_factor(&two_factor)
                    .send()
                    .await?
                {
                    LoginAjaxResponseType::Ok => {
                        println!("Login successful!");
                        break;
                    }
                    LoginAjaxResponseType::IncorrectTwoFactorCodeLength
                    | LoginAjaxResponseType::FailedTwoFactorVerification => {
                        println!("Incorrect 2FA code")
                    }
                    _ => panic!("There was an error submitting the 2FA code"),
                }
            }
        }
        _ => panic!("There was an error logging in."),
    }

    Ok(())
}
```

# Running Examples

[Back to top][readme-section-toc]

The examples can be run with the following:

```
cargo run --example [example_name]
```

More details about the examples can be found in the [examples README][examples-readme] file.

# Changelog

[Back to top][readme-section-toc]

The changelog can be found [here][changelog].

Changes are added manually to keep the changelog human-readable with summaries of the changes from each version.

# License

[Back to top][readme-section-toc]

Licensed under either of

 * Apache License, Version 2.0
   ([LICENSE-APACHE][license-apache] or http://www.apache.org/licenses/LICENSE-2.0)
 * MIT license
   ([LICENSE-MIT][license-mit] or http://opensource.org/licenses/MIT)

at your option.

## Contribution

[Back to top][readme-section-toc]

Unless you explicitly state otherwise, any contribution intentionally submitted
for inclusion in the work by you, as defined in the Apache-2.0 license, shall be
dual licensed as above, without any additional terms or conditions.

# Contributing

[Back to top][readme-section-toc]

We welcome contributions from everyone. There are many ways to contribute and the
[CONTRIBUTING.md][contributing] document explains how you can contribute and get started.

[changelog]: CHANGELOG.md
[chrono-docs]: https://docs.rs/chrono
[contributing]: CONTRIBUTING.md
[examples-readme]: examples/README.md
[license-apache]: LICENSE-APACHE
[license-mit]: LICENSE-MIT
[mangadex-v2-api-index]: https://mangadex.org/api/v2
[mangadex-v2-openapi-spec]: src/v2/openapi.yaml
[readme-section-contributing]: #contributing
[readme-section-contribution]: #contribution
[readme-section-examples]: #examples
[readme-section-features]: #features
[readme-section-license]: #license
[readme-section-requirements]: #requirements
[readme-section-running-examples]: #running-examples
[readme-section-optional-features]: #optional-features
[readme-requirements]: #requirements
[readme-section-toc]: #table-of-contents
[reqwest-library]: https://crates.io/crates/reqwest
[rust-homepage]: https://rust-lang.org
