diff --git a/src/bin/auracite/main.rs b/src/bin/auracite/main.rs index 42b5e4f..a27ed0f 100644 --- a/src/bin/auracite/main.rs +++ b/src/bin/auracite/main.rs @@ -1,4 +1,4 @@ -use auracite::{ArchiveError, archive_character}; +use auracite::{ArchiveError, archive_character, search_character}; use cxx_kde_frameworks::kcoreaddons::{KAboutData, KAboutPerson, License}; use cxx_kde_frameworks::ki18n::{KLocalizedContext, KLocalizedString, i18n, i18nc}; use cxx_qt_lib::{ @@ -21,7 +21,11 @@ fn archive_character_blocking( .build() .map_err(|_| ArchiveError::UnknownError)?; - let inner = rt.block_on(archive_character(&character_name.to_string(), use_dalamud))?; + let id = rt + .block_on(search_character(&character_name.to_string())) + .expect("Character not found!"); + + let inner = rt.block_on(archive_character(id, use_dalamud))?; write(filename, inner)?; Ok(()) diff --git a/src/lib.rs b/src/lib.rs index 79246b2..5e409c4 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -13,6 +13,7 @@ use base64::prelude::*; use data::{Appearance, Currencies}; use package::Package; use physis::race::{Gender, Race, Tribe}; +use regex::Regex; use reqwest::Url; use serde::Deserialize; use std::io::Write; @@ -82,11 +83,8 @@ impl From for JsValue { } } -/// Archives the character named `character_name` and gives a ZIP file as bytes that can be written to disk. -pub async fn archive_character( - character_name: &str, - use_dalamud: bool, -) -> Result, ArchiveError> { +/// Searches for the character by their name. +pub async fn search_character(character_name: &str) -> Option { let lodestone_host = if cfg!(target_family = "wasm") { LODESTONE_TUNNEL_HOST } else { @@ -97,19 +95,37 @@ pub async fn archive_character( &format!("{lodestone_host}/lodestone/character?"), &[("q", character_name)], ) - .map_err(|_| ArchiveError::UnknownError)?; + .map_err(|_| ArchiveError::UnknownError) + .ok()?; let search_page = download(&search_url) .await - .map_err(|_| ArchiveError::DownloadFailed(search_url.to_string()))?; - let search_page = String::from_utf8(search_page).map_err(|_| ArchiveError::ParsingError)?; + .map_err(|_| ArchiveError::DownloadFailed(search_url.to_string())) + .ok()?; + let search_page = String::from_utf8(search_page) + .map_err(|_| ArchiveError::ParsingError) + .ok()?; let href = parse_search(&search_page); if href.is_empty() { - return Err(ArchiveError::CharacterNotFound); + return None; } - let char_page_url = - Url::parse(&format!("{lodestone_host}{}", href)).map_err(|_| ArchiveError::UnknownError)?; + let re = Regex::new(r"\/lodestone\/character\/(\d+)").ok()?; + let captures = re.captures(&href)?; + + captures.get(1)?.as_str().parse().ok() +} + +/// Archives the character named `character_name` and gives a ZIP file as bytes that can be written to disk. +pub async fn archive_character(id: u64, use_dalamud: bool) -> Result, ArchiveError> { + let lodestone_host = if cfg!(target_family = "wasm") { + LODESTONE_TUNNEL_HOST + } else { + LODESTONE_HOST + }; + + let char_page_url = Url::parse(&format!("{lodestone_host}/lodestone/character/{}/", id)) + .map_err(|_| ArchiveError::UnknownError)?; let char_page = download(&char_page_url) .await .map_err(|_| ArchiveError::DownloadFailed(char_page_url.to_string()))?; @@ -361,17 +377,17 @@ pub async fn archive_character( Ok(buf) } -/// Archives the character named `character_name` and converts the ZIP file to Base64. Useful for downloading via data URIs. +/// Archives the character `id` and converts the ZIP file to Base64. Useful for downloading via data URIs. #[cfg(target_family = "wasm")] #[wasm_bindgen] pub async extern "C" fn archive_character_base64( - character_name: &str, + id: u64, use_dalamud: bool, ) -> Result { #[cfg(feature = "debug")] console_error_panic_hook::set_once(); - let buf: String = archive_character(character_name, use_dalamud) + let buf: String = archive_character(id, use_dalamud) .await .map(|x| BASE64_STANDARD.encode(x))?; return Ok(format!("data:application/octet-stream;charset=utf-16le;base64,{buf}").into());