use std::path::PathBuf; use serde::{Deserialize, Serialize}; use serde_repr::{Deserialize_repr, Serialize_repr}; use thiserror::Error; /// Error wrapper #[derive(Error, Debug)] pub enum HydrusError { #[error("failed to connect to Hydrus")] NetworkError(reqwest::Error), #[error("failed to encode/Deserialize data")] DeserializeError(serde_json::Error), #[error("io error")] IOError(std::io::Error), #[error("api or session key needed")] KeyNotSupplied, } impl From for HydrusError { fn from(value: serde_json::Error) -> Self { HydrusError::DeserializeError(value) } } impl From for HydrusError { fn from(value: std::io::Error) -> Self { HydrusError::IOError(value) } } impl From for HydrusError { fn from(value: reqwest::Error) -> Self { HydrusError::NetworkError(value) } } /// Hydrus serivce permissions object #[derive(PartialEq, Debug, Clone, Serialize_repr, Deserialize_repr)] #[repr(u8)] pub enum HydrusPermissions { ImportAndEditURLs = 0, ImportAndEditFiles, EditFileTags, SearchAndFetchFiles, ManagePages, ManageCookiesAndHeaders, ManageDatabase, EditFileNotes, EditFileRelationships, EditFileRatings, ManagePopups, EditFileTimes, CommitPending, SeeLocalPaths, Null = 255, } /// Hydrus key information struct #[derive(Deserialize, Debug)] pub struct KeyInfo { pub name: String, pub permits_everything: bool, pub basic_permissions: Vec, pub human_permissions: String, } /// Hydrus service type object #[derive(PartialEq, Debug, Clone, Serialize_repr, Deserialize_repr)] #[repr(u8)] pub enum ServiceType { TagRepository = 0, FileRepository, LocalFileDomain, LocalTagDomain = 5, NumericalRating, BoolRating, AllKnownTags = 10, AllKnownFiles, LocalBooru, IPFS, Trash, AllLocalFiles, FileNotes = 17, ClientAPI, DeletedFromAnywhere, LocalUpdates, AllMyFiles, IncDecRating, ServerAdmin = 99, Null = 255, } /// Hydrus service struct #[derive(Deserialize, Debug, Clone)] pub struct Service { pub name: String, #[serde(default)] pub service_key: String, pub r#type: ServiceType, pub type_pretty: String, #[serde(default)] pub star_shape: Option, #[serde(default)] pub min_stars: Option, #[serde(default)] pub max_stars: Option, } /// Hydrus file domains pub enum FileDomain { FileServiceKey(String), FileServiceKeys(Vec), DeletedFileServiceKey(String), DeletedFileServiceKeys(Vec), } /// Payload for importing a file via providing a local path #[derive(Serialize, Debug, Default)] pub struct AddFileRequest { pub path: PathBuf, #[serde(skip_serializing_if = "Option::is_none")] pub delete_after_successful_import: Option, #[serde(skip_serializing_if = "Option::is_none")] pub file_service_key: Option, #[serde(skip_serializing_if = "Option::is_none")] pub file_service_keys: Option>, #[serde(skip_serializing_if = "Option::is_none")] pub deleted_file_service_key: Option, #[serde(skip_serializing_if = "Option::is_none")] pub deleted_file_service_keys: Option>, } /// File importing status #[derive(PartialEq, Debug, Clone, Serialize_repr, Deserialize_repr)] #[repr(u8)] pub enum AddFileStatus { SuccessfulImport = 1, AlreadyInDatabase, PreviouslyDeleted, FailedToImport, FileVetoed = 7, } /// File importing api response #[derive(Deserialize)] pub struct AddFileResponse { pub status: AddFileStatus, pub hash: String, pub note: String, } /// Hydrus file object #[derive(Debug, Clone, Serialize)] pub enum HydrusFile { #[serde(rename(serialize = "file_id"))] FileId(String), #[serde(rename(serialize = "file_ids"))] FileIds(Vec), #[serde(rename(serialize = "hash"))] Hash(String), #[serde(rename(serialize = "hashes"))] Hashes(Vec), } impl Default for HydrusFile { fn default() -> Self { Self::FileId(String::from("")) } } /// Payload for various file-related requests #[derive(Debug, Default)] pub struct FileRequest { pub file: HydrusFile, pub delete_after_successful_import: Option, pub file_service_key: Option, pub file_service_keys: Option>, pub deleted_file_service_key: Option, pub deleted_file_service_keys: Option>, pub reason: Option, } impl Serialize for FileRequest { fn serialize(&self, serializer: S) -> Result where S: serde::Serializer, { use serde::ser::SerializeMap; let mut map = serializer.serialize_map(Some(1))?; match &self.file { HydrusFile::FileId(id) => map.serialize_entry("file_id", &id)?, HydrusFile::FileIds(ids) => map.serialize_entry("file_ids", &ids)?, HydrusFile::Hash(hash) => map.serialize_entry("hash", &hash)?, HydrusFile::Hashes(hashes) => map.serialize_entry("hashes", &hashes)?, } if let Some(val) = &self.reason { map.serialize_entry("reason", &val)?; } if let Some(val) = &self.file_service_key { map.serialize_entry("file_service_key", &val)?; } if let Some(val) = &self.file_service_keys { map.serialize_entry("file_service_keys", &val)?; } if let Some(val) = &self.deleted_file_service_key { map.serialize_entry("deleted_file_service_key", &val)?; } if let Some(val) = &self.deleted_file_service_keys { map.serialize_entry("deleted_file_service_keys", &val)?; } map.end() } } #[derive(Debug, Deserialize)] pub struct HashResponse { pub hash: String, #[serde(default)] pub perceptual_hashes: Option>, #[serde(default)] pub pixel_hash: Option, }