Skip to content

Commit

Permalink
feat: add support to search: anime, manga and user
Browse files Browse the repository at this point in the history
  • Loading branch information
AndrielFR committed Jan 3, 2025
1 parent b0c98d7 commit f679496
Show file tree
Hide file tree
Showing 7 changed files with 439 additions and 77 deletions.
21 changes: 21 additions & 0 deletions queries/search_anime.graphql
Original file line number Diff line number Diff line change
@@ -0,0 +1,21 @@
# SPDX-License-Identifier: MIT
# Copyright (c) 2022-2025 Andriel Ferreira <https://github.com/AndrielFR>

query($search: String, $page: Int = 1, $per_page: Int = 10) {
Page(page: $page, perPage: $per_page) {
pageInfo {
total
currentPage
lastPage
}
media(search: $search, type: ANIME, sort: POPULARITY_DESC) {
id
title {
romaji
english
native
}
siteUrl
}
}
}
21 changes: 21 additions & 0 deletions queries/search_manga.graphql
Original file line number Diff line number Diff line change
@@ -0,0 +1,21 @@
# SPDX-License-Identifier: MIT
# Copyright (c) 2022-2025 Andriel Ferreira <https://github.com/AndrielFR>

query($search: String, $page: Int = 1, $per_page: Int = 10) {
Page(page: $page, perPage: $per_page) {
pageInfo {
total
currentPage
lastPage
}
media(search: $search, type: MANGA, sort: POPULARITY_DESC) {
id
title {
romaji
english
native
}
siteUrl
}
}
}
20 changes: 20 additions & 0 deletions queries/search_user.graphql
Original file line number Diff line number Diff line change
@@ -0,0 +1,20 @@
# SPDX-License-Identifier: MIT
# Copyright (c) 2022-2025 Andriel Ferreira <https://github.com/AndrielFR>

query($search: String, $page: Int = 1, $per_page: Int = 10) {
Page(page: $page, perPage: $per_page) {
pageInfo {
total
currentPage
lastPage
}
users(search: $search, sort: SEARCH_MATCH) {
id
name
avatar {
large
medium
}
}
}
}
165 changes: 156 additions & 9 deletions src/client.rs
Original file line number Diff line number Diff line change
@@ -1,9 +1,10 @@
// SPDX-License-Identifier: MIT
// Copyright (c) 2022-2025 Andriel Ferreira <https://github.com/AndrielFR>

use std::io::Write;
use std::time::Duration;

use serde::Deserialize;

use crate::models::{Anime, Character, Manga, Person, User};
use crate::Result;

Expand Down Expand Up @@ -281,20 +282,166 @@ impl Client {
}
}

/// Search for anime.
/// Search for animes.
///
/// # Arguments
///
/// * `title` - The title of the anime to search.
/// * `page` - The page number to get.
/// * `limit` - The number of animes to get per page.
///
/// # Errors
///
/// Returns an error if the request fails.
///
/// # Example
///
/// ```
/// # async fn f(client: rust_anilist::Client) -> rust_anilist::Result<()> {
/// let animes = client.search_anime("Naruto", 1, 10).await.unwrap();
///
/// # Ok(())
/// # }
/// ```
pub async fn search_anime(
&self,
variables: serde_json::Value,
title: &str,
page: u16,
limit: u16,
) -> Option<Vec<crate::models::Anime>> {
let result = self
.request(MediaType::Anime, Action::Search, variables)
.request(
MediaType::Anime,
Action::Search,
serde_json::json!({ "search": title, "page": page, "per_page": limit, }),
)
.await
.unwrap();
let mut _models = Vec::<crate::models::Anime>::new();
unimplemented!()

if let Some(medias) = result["data"]["Page"]["media"].as_array() {
let mut animes = Vec::new();

for media in medias.iter() {
let mut anime = crate::models::Anime::default();
anime.id = media["id"].as_i64().unwrap();

Check failure on line 326 in src/client.rs

View workflow job for this annotation

GitHub Actions / lint

field assignment outside of initializer for an instance created with Default::default()
anime.title = crate::models::Title::deserialize(&media["title"]).unwrap();
anime.url = media["siteUrl"].as_str().unwrap().to_string();

animes.push(anime);
}

return Some(animes);
}

None
}

/// Search for mangas.
///
/// # Arguments
///
/// * `title` - The title of the manga to search.
/// * `page` - The page number to get.
/// * `limit` - The number of mangas to get per page.
///
/// # Errors
///
/// Returns an error if the request fails.
///
/// # Example
///
/// ```
/// # async fn f(client: rust_anilist::Client) -> rust_anilist::Result<()> {
/// let mangas = client.search_manga("Naruto", 1, 10).await.unwrap();
///
/// # Ok(())
/// # }
/// ```
pub async fn search_manga(
&self,
title: &str,
page: u16,
limit: u16,
) -> Option<Vec<crate::models::Manga>> {
let result = self
.request(
MediaType::Manga,
Action::Search,
serde_json::json!({ "search": title, "page": page, "per_page": limit, }),
)
.await
.unwrap();

if let Some(medias) = result["data"]["Page"]["media"].as_array() {
let mut mangas = Vec::new();

for media in medias.iter() {
let mut manga = crate::models::Manga::default();
manga.id = media["id"].as_i64().unwrap();

Check failure on line 380 in src/client.rs

View workflow job for this annotation

GitHub Actions / lint

field assignment outside of initializer for an instance created with Default::default()
manga.title = crate::models::Title::deserialize(&media["title"]).unwrap();
manga.url = media["siteUrl"].as_str().unwrap().to_string();

mangas.push(manga);
}

return Some(mangas);
}

None
}

/// Search for users.
///
/// # Arguments
///
/// * `name` - The name of the user to search.
/// * `page` - The page number to get.
/// * `limit` - The number of users to get per page.
///
/// # Errors
///
/// Returns an error if the request fails.
///
/// # Example
///
/// ```
/// # async fn f(client: rust_anilist::Client) -> rust_anilist::Result<()> {
/// let users = client.search_user("andrielfr", 1, 10).await.unwrap();
///
/// # Ok(())
/// # }
/// ```
pub async fn search_user(
&self,
name: &str,
page: u16,
limit: u16,
) -> Option<Vec<crate::models::User>> {
let result = self
.request(
MediaType::User,
Action::Search,
serde_json::json!({ "search": name, "page": page, "per_page": limit, }),
)
.await
.unwrap();

if let Some(users) = result["data"]["Page"]["users"].as_array() {
let mut vec = Vec::new();

for user in users.iter() {
let mut u = crate::models::User::default();
u.id = user["id"].as_i64().unwrap() as i32;

Check failure on line 434 in src/client.rs

View workflow job for this annotation

GitHub Actions / lint

field assignment outside of initializer for an instance created with Default::default()
u.name = user["name"].as_str().unwrap().to_string();
u.avatar = crate::models::Image::deserialize(&user["avatar"]).ok();

vec.push(u);
}

return Some(vec);
}

None
}

/// Send a request to the AniList API.
Expand Down Expand Up @@ -359,12 +506,12 @@ impl Client {
}
Action::Search => {
match media_type {
// MediaType::Anime => include_str!("../queries/search_anime.graphql").to_string(),
// MediaType::Manga => include_str!("../queries/search_manga.graphql").to_string(),
MediaType::Anime => include_str!("../queries/search_anime.graphql").to_string(),
MediaType::Manga => include_str!("../queries/search_manga.graphql").to_string(),
// MediaType::Character => {
// include_str!("../queries/search_character.graphql").to_string()
// }
// MediaType::User => include_str!("../queries/search_user.graphql").to_string(),
MediaType::User => include_str!("../queries/search_user.graphql").to_string(),
// MediaType::Person => {
// include_str!("../queries/search_person.graphql").to_string()
// }
Expand Down
Loading

0 comments on commit f679496

Please sign in to comment.