Releases: tonymushah/mangadex-api
mangadex v3.2.0 minor changes
mangadex-api v3.2 is here
Hello everyone!
I'm here to give you some changes logs about this realease:
derive_builder
upgraded to v0.20 #172- Added
JP
lang (it's already published on the0.7.2
patch) #180 - Fixed Serialization for
IncludeFuturePages
,IncludeExternalUrl
,IncludeFuturePublishAt
,IncludeFutureUpdates
which will serialize to1
for includes and0
for excludes
Quick crate version overview
Crate | Version |
---|---|
mangadex-api |
3.2 |
mangadex-api-types-rust |
0.8 |
mangadex-api-schema-rust |
0.8 |
mangadex-api-input-types |
0.4 |
That's it!
Have a nice day everyone!
mangadex v3.0.1 Patches
mangadex-api-types-rust v0.6.1
- Added
Language::get_langs
to get an array of all local language - Added
Tag::get_all_tags
to get an array of all local tags
mangadex-api-schema-rust v0.6.1
- Added
mangadex-api-types-rust::Tag
conversion toApiObjectNoRelationship<TagAttributes>
- Fixed
Relationship
conversion handler forArtist
,Creator
,Member
,Leader
mangadex-api v3.0.1
- Implemented
send()
toUnFollowCustomListBuilder
Happy Christmas everyone! π
π
I hope you're enjoying your Christmas Eve well.
`mangadex-api` v3 is here π₯³
Hello everyone,
I'm very happy and excited to announce to you:
The Release of mangadex-api
v3
along with mangadex-api-types/schema-rust
v0.6
First,
As mentioned in v3 annoucement, 3/4 (or maybe half) of the feature goal was added.
1- The custom_list_v2
feature for mangadex-api
:
It's the support of the subscription system, announced in August 2023. (Ref: here).
There might be some missing endpoint in this feature (like /subscription
,...) because it's not deployed yet on api.mangadex.org
but on api.mangadex.dev
(their public dev environment).
Even if it's not deployed yet, i want to make it stable in v3.1, so stay tuned for that.
2- The upload
stabilization :
A days ago, i got the time to try and test the upload endpoints.
It works and the chapter chapter got uploaded to the Official "Test" Manga
(the uploaded chapter is here), but it somehow contains some bugs (ref here)
Some discord note
![image](https://github.com/tonymushah/mangadex-api/assets/95529016/813a762d-0be1-4a3a-9314-947711cfad28)The test/example code is available in mangadex-api/examples/upload.rs
3- mangadex_api_schema_rust::v5::Relationship
can now convert to mangadex_api_schema_rust::ApiObjectNoRelationships
I added some TryFrom
implementation to Relationship
.
This allow you to not add a lot of boilerplate code that does the same thing (converting a relationship to ApiObject π΅βπ«)
Note: This converstion only support :
- ApiObjectNoRelationships<AuthorAttributes>
- ApiObjectNoRelationships<ChapterAttributes>
- ApiObjectNoRelationships<CoverAttributes>
- ApiObjectNoRelationships<CustomListAttributes>
- ApiObjectNoRelationships<MangaAttributes>
- ApiObjectNoRelationships<ScanlationGroupAttributes>`
- ApiObjectNoRelationships<TagAttributes>
- ApiObjectNoRelationships<UserAttributes>
4- tokio-multi-thread
and rw-mutli-thread
feature for mangadex-api
Sometimes, in a really big project, you often need a good concurent program.
To satisfy this demand, I added the rw-mutli-thread
feature. Instead of using the futures::lock::Mutex
in the multi-thread
, it'll use tokio::sync::RwLock
.
Note that all invoked requests the client data. Only login
and refresh_token
(for both legacy-auth
and oauth
) write the client data.
And tokio-multi-thread
is just use tokio::sync::Mutex
instead of
5- oauth
feature (enabled by default)
A few weeks ago, Mangadex introduced personal-clients
, the official (and also simple π) way for 3rd party software and SDK to support authentification with the OAuth introduced last year.
There is a simple demo on the README
but there is also a few examples at mangadex-api/examples
:
6- the new syntax
As mentioned in the v3 annoucement, the SDK will got the breaking change feature.
Quick reminder:
if we have an endpoint like this:
PUT /manga/{id}
parameters
title: LocalizedString
version: int
authors: string[] (uuid)
year: int
the invocation should be like this:
/// I assume that you already declared a `MangaDexClient` somewhere.
client.
// /manga/{id}
.manga()
.id(/* Some manga Id here */)
// the HTTP method
.put()
// Parameters
.version(3_u32)
.title(/* some LocalizedString here */)
.year(2023)
.authors(vec![Uuid::new_v4()])
// Send the request
.send()
.await?
In previous versions, you often need to build the request first, but now it's not required.
7- utils
feature
The type alias DownloadElement
have been changed from (String, Option<Bytes>)
to (String, Result<Bytes>)
where the String
is for the filename and the Result<Bytes>
is for the image bytes.
I also added a new module upload
for upload utilities.
8- RateLimit
handling
Please refer to #26 for more details
That's (maybe) it! π
If you want to use the new mangadex-api
v3,
Just update your Cargo.toml
# ...
# Types and schemas are always required
mangadex-api-types-rust = "0.6"
mangadex-api-schema-rust = "0.6"
mangadex-api = { version = "3.0.0", feature = ["mutli-thread"]}
# Please note that `oauth` is enabled by default
Thanks for your amazing support
See you in next versions.
@tonymushah
`utils` features Annoucement (MangadexApi 2.1.0)
Hello everybody,
After the realease of special-eureka
, i made some testing (mostly reading π
) but i had some limitations that annoys me when using this SDK.
The first thing is the (non serialization of the types and schemas) but now it`s fixed :
mangadex-api-types-rust 0.3.4
has two feature flags :non_exhaustive
(enabled by default) that enable#[non_exhaustive]
for enums andspecta
for thespecta
. Useful for the ones who is building a typesafetauri
app.mangadex-api-schema 0.3.2
has three features flags :non_exhaustive
(enabled by default) that enable#[non_exhaustive]
for structs and schemas ,specta
for thespecta
, andserialize
that enable serde serialization
The second thing is the new features flags :
legacy-auth
andlegacy-account
for the old Mangadex login system. Since 5.9.0, Mangadex switched to OAuth for their login system. These involve theMangaDexClient::auth()
andMangaDexClient::account()
removed by default.utils
for some utilities that i already imagined.
The utils
features
For now, this allows you to download chapters and cover much faster.
I mean code
faster.
When enabled, this unlock the new function in the client : MangaDexClient::download()
allows you to download chapters and cover images
Examples :
Retrieving chapter pages
Old way
// 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(())
# }
The new way
use crate::{utils::download::chapter::DownloadMode, MangaDexClient};
use anyhow::{Ok, Result};
/// used for file exporting
use std::{
fs::{create_dir_all, File},
io::Write,
};
/// It's from this manga called [`The Grim Reaper Falls In Love With A Human`](https://mangadex.org/title/be2efc56-1669-4e42-9f27-3bd232bca8ea/the-grim-reaper-falls-in-love-with-a-human)
///
/// [Chapter 1 English](https://mangadex.org/chapter/2b4e39a5-fba0-4055-a176-8b7e19faacdb) by [`Kredim`](https://mangadex.org/group/0b870e54-c75f-4d2e-8068-c40f939135fd/kredim)
#[tokio::main]
async fn main() -> Result<()> {
let output_dir = "your-output-dir";
let client = MangaDexClient::default();
let chapter_id = uuid::Uuid::parse_str("32b229f6-e9bf-41a0-9694-63c11191704c")?;
let chapter_files = client
/// We use the download builder
.download()
/// Chapter id (accept uuid::Uuid)
.chapter(chapter_id)
/// You also use `DownloadMode::Normal` if you want some the original quality
///
/// Default : Normal
.mode(DownloadMode::DataSaver)
/// Enable the [`The MangaDex@Home report`](https://api.mangadex.org/docs/retrieving-chapter/#the-mangadexhome-report-endpoint) if true
///
/// Default : false
.report(true)
/// Something that i don`t really know about
///
/// More details at : https://api.mangadex.org/docs/retrieving-chapter/#basics
.force_port_443(false)
.build()?
.execute()
.await?;
create_dir_all(format!("{}{}", output_dir, chapter_id))?;
for (filename, bytes) in chapter_files {
let mut file: File =
File::create(format!("{}{}/{}", output_dir, chapter_id, filename))?;
file.write_all(&bytes)?;
}
Ok(())
}
Much more cleaner !
Retrieving cover image
Old way
// 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(())
# }
The new way
Via a cover id.
use anyhow::Result;
use uuid::Uuid;
use crate::MangaDexClient;
use std::{io::Write, fs::File};
/// Download the volume 2 cover of [Lycoris Recoil](https://mangadex.org/title/9c21fbcd-e22e-4e6d-8258-7d580df9fc45/lycoris-recoil)
#[tokio::main]
async fn main() -> Result<()>{
let cover_id : Uuid = Uuid::parse_str("0bc12ff4-3cec-4244-8582-965b8be496ea")?;
let client : MangaDexClient = MangaDexClient::default();
let (filename, bytes) = client.download().cover().build()?.via_cover_id(cover_id).await?;
let mut file = File::create(format!("{}/{}", "your-output-dir", filename))?;
file.write_all(&bytes)?;
Ok(())
}
Via a manga id.
use anyhow::Result;
use uuid::Uuid;
use crate::MangaDexClient;
use std::{io::Write, fs::File};
/// Download the [Kimi tte Watashi no Koto Suki Nandesho?](https://mangadex.org/title/f75c2845-0241-4e69-87c7-b93575b532dd/kimi-tte-watashi-no-koto-suki-nandesho) cover
///
/// For test... of course :3
#[tokio::main]
async fn main() -> Result<()>{
let manga_id : Uuid = Uuid::parse_str("f75c2845-0241-4e69-87c7-b93575b532dd")?;
let client : MangaDexClient = MangaDexClient::default();
let (filename, bytes) = client
.download()
.cover()
/// you can use
///
/// ```rust
/// .quality(CoverQuality::Size512)
/// ``` for 512
/// or
/// ```rust
/// .quality(CoverQuality::Size256)
/// ``` for 256
.build()?.via_manga_id(manga_id).await?;
let mut file = File::create(format!("{}/{}", "test-outputs/covers", filename))?;
file.write_all(&bytes)?;
Ok(())
}
Much more cleaner this way.
That's all for today.
If you have a suggestion or a request, just open an issue.