1 个版本 (0 个不稳定版本)

2.0.0-rc.12023 年 3 月 3 日

网页开发 中排名第 2375

Download history 3/week @ 2024-03-09 1/week @ 2024-03-16 17/week @ 2024-03-30 5/week @ 2024-04-06

每月下载量 56

MIT/Apache

1MB
18K SLoC

mangadex-api

重要

这个 git 仓库只是从 gondolyr/mangadex-api 分支出来的,但由于项目已经下架,所以现在将维护这个 crate 以支持 special-eurekaeureka-manager

mangadex-api crate 为 MangaDex API 提供了一个方便的、高级的包装 客户端,用 Rust 编写。

它涵盖了 他们的文档 中涵盖的所有公共端点。

文档 (docs.rs)

文档 (项目 main 分支)

请注意,由于 MangaDex 仍在测试阶段,此 SDK 可能会突然发生重大变化。

免责声明

mangadex-apiMangaDex 无关。

目录

需求

回到顶部

如何安装

回到顶部

mangadex-api 添加到您的依赖项

[dependencies]
# ...
mangadex-api = "2.0.0-rc.1"

如果您正在使用 cargo-edit,请运行

cargo add mangadex-api

依赖项理由

依赖项 用于 包含
anyhow 捕获意外错误。 always
clap 展示库功能的示例 dev 构建
derive_builder 方便地为 API 端点构建器生成设置器。 always
fake 为单元测试生成随机数据。 dev 构建
期货 异步请求处理。 always
reqwest MangaDex API发送HTTP请求。 always
serde 将HTTP响应体序列化为结构体。 always
serde_json 为单元测试创建JSON对象。 dev 构建
serde_qs HTTP请求的查询字符串序列化。 always
thiserror 自定义错误处理。 always
time 处理时间字段的便利类型。 always
tokio 异步运行时,用于在示例中处理futures(不是库)。 dev 构建
url 方便的Url类型,用于验证和包含URL。 always
uuid 方便的Uuid类型,用于验证和包含请求和响应的UUID。也用于测试中随机生成UUID。 always
wiremock HTTP模拟以测试MangaDex API dev 构建

功能

回到顶部

默认情况下不包括所有功能。要启用它们,请将以下任何一个添加到项目的Cargo.toml文件中。

  • multi-thread

    启用MangaDexClient的线程安全,但会稍微增加操作成本。

例如,要启用multi-thread功能,请将以下内容添加到您的Cargo.toml文件中

mangadex-api = { version = "2.0.0-rc.1", features = ["multi-thread"] }

HTTP 客户端

回到顶部

mangadex_api::MangaDexClient是异步的,使用reqwest作为HTTP客户端。

响应结构体

回到顶部

响应结构体可以在schemas模块中找到,并包含JSON响应中的字段。

入门

回到顶部

此示例演示了如何获取一本随机漫画。

use mangadex_api::v5::MangaDexClient;

#[tokio::main]
async fn main() -> anyhow::Result<()> {
    let client = MangaDexClient::default();

    let random_manga = client
        .manga()
        .random()
        .build()?
        .send()
        .await?;

    println!("{:?}", random_manga);

    Ok(())
}

使用自定义 reqwest 客户端

回到顶部

默认情况下,mangadex_api::MangaDexClient将使用默认的reqwest::Client设置。

您可以为自定义选项(如请求超时)提供自己的reqwest::Client

use reqwest::Client;

use mangadex_api::v5::MangaDexClient;

# async fn run() -> anyhow::Result<()> {
let reqwest_client = Client::builder()
    .timeout(std::time::Duration::from_secs(10))
    .build()?;

let client = MangaDexClient::new(reqwest_client);
# Ok(())
# }

通过标题搜索漫画

回到顶部

参考:https://api.mangadex.org/swagger.html#/Manga/get-search-manga

use mangadex_api::v5::MangaDexClient;

# async fn run() -> anyhow::Result<()> {
let client = MangaDexClient::default();

let manga_results = client
    .manga()
    .search()
    .title("full metal")
    .build()?
    .send()
    .await?;

println!("manga results = {:?}", manga_results);
# Ok(())
# }

使用参考扩展通过标题搜索漫画

回到顶部

每次获取都会包括所有关系,但只包含最小信息,如关系类型和ID。参考扩展将在请求中添加的类型的结果中包含完整的JSON对象。

在下面的示例中,列表中的任何关联作者都将提供详细的信息,如作者姓名、传记和网站。

参考

use mangadex_api::types::{ReferenceExpansionResource, RelationshipType};
use mangadex_api::v5::schema::RelatedAttributes;
use mangadex_api::v5::MangaDexClient;

# async fn run() -> anyhow::Result<()> {
let client = MangaDexClient::default();

let manga_results = client
    .manga()
    .search()
    .title("full metal")
    .include(&ReferenceExpansionResource::Author)
    .build()?
    .send()
    .await?;

println!("manga results = {:?}", manga_results);

let authors = manga_results.data.iter().filter_map(|manga| {
    for rel in &manga.relationships {
        if rel.type_ == RelationshipType::Author {
            return Some(rel);
        }
    }

    None
});

for author in authors {
    if let Some(RelatedAttributes::Author(author_attributes)) = &author.attributes {
        println!("{} - {}", author.id, author_attributes.name);
    }
}
# Ok(())
# }

下载章节页面

回到顶部

参考:https://api.mangadex.org/docs/reading-chapter/

// Imports used for downloading the pages to a file.
// They are not used because we're just printing the raw bytes.
// use std::fs::File;
// use std::io::Write;

use reqwest::Url;
use uuid::Uuid;

use mangadex_api::v5::MangaDexClient;

# async fn run() -> anyhow::Result<()> {
let client = MangaDexClient::default();

let chapter_id = Uuid::new_v4();

let at_home = client
    .at_home()
    .server()
    .chapter_id(&chapter_id)
    .build()?
    .send()
    .await?;

let http_client = reqwest::Client::new();

// Original quality. Use `.data.attributes.data_saver` for smaller, compressed images.
let page_filenames = at_home.chapter.data;
for filename in page_filenames {
    // If using the data-saver option, use "/data-saver/" instead of "/data/" in the URL.
    let page_url = at_home
        .base_url
        .join(&format!(
            "/{quality_mode}/{chapter_hash}/{page_filename}",
            quality_mode = "data",
            chapter_hash = at_home.chapter.hash,
            page_filename = filename
        ))
        .unwrap();

    let res = http_client.get(page_url).send().await?;
    // The data should be streamed rather than downloading the data all at once.
    let bytes = res.bytes().await?;

    // This is where you would download the file but for this example,
    // we're just printing the raw data.
    // let mut file = File::create(&filename)?;
    // let _ = file.write_all(&bytes);
    println!("Chunk: {:?}", bytes);
}

# Ok(())
# }

下载漫画的主要封面图像

回到顶部

虽然此示例可以直接通过传递封面ID来获取封面信息,但通常不会手头有ID,因此最常见的方法是从漫画结果中获取。

如果您想获取某部漫画的所有封面图片,您需要使用封面列表端点,并使用manga[]查询参数。

// Imports used for downloading the cover to a file.
// They are not used because we're just printing the raw bytes.
// use std::fs::File;
// use std::io::Write;

use reqwest::Url;
use uuid::Uuid;

use mangadex_api::types::RelationshipType;
use mangadex_api::v5::MangaDexClient;
use mangadex_api::CDN_URL;

# async fn run() -> anyhow::Result<()> {
let client = MangaDexClient::default();

let manga_id = Uuid::new_v4();
let manga = client
    .manga()
    .get()
    .manga_id(&manga_id)
    .build()?
    .send()
    .await?;

let cover_id = manga
    .data
    .relationships
    .iter()
    .find(|related| related.type_ == RelationshipType::CoverArt)
    .expect("no cover art found for manga")
    .id;
let cover = client
    .cover()
    .get()
    .cover_id(&cover_id)
    .build()?
    .send()
    .await?;

// This uses the best quality image.
// To use smaller, thumbnail-sized images, append any of the following:
//
// - .512.jpg
// - .256.jpg
//
// For example, "https://uploads.mangadex.org/covers/8f3e1818-a015-491d-bd81-3addc4d7d56a/4113e972-d228-4172-a885-cb30baffff97.jpg.512.jpg"
let cover_url = Url::parse(&format!(
        "{}/covers/{}/{}",
        CDN_URL, manga_id, cover.data.attributes.file_name
    ))
    .unwrap();

let http_client = reqwest::Client::new();

let res = http_client.get(cover_url).send().await?;
// The data should be streamed rather than downloading the data all at once.
let bytes = res.bytes().await?;

// This is where you would download the file but for this example, we're just printing the raw data.
// let mut file = File::create(&filename)?;
// let _ = file.write_all(&bytes);
println!("Chunk: {:?}", bytes);
# Ok(())
# }

变更日志

回到顶部

变更日志可以在这里找到。

手动添加变更以保持变更日志易于阅读,包含每个版本变更的摘要。

许可证

回到顶部

根据您的选择,许可协议为以下之一:

贡献

回到顶部

除非您明确说明,否则根据Apache-2.0许可证定义的,您有意提交以包含在作品中的任何贡献,将按照上述方式双许可,不附加任何额外的条款或条件。

贡献

回到顶部

我们欢迎所有人的贡献。有许多贡献的方式,CONTRIBUTING.md文档解释了您可以如何贡献以及如何开始。

依赖项

~6–21MB
~299K SLoC