Add retrieval of metadata to the file wrapper

Signed-off-by: trivernis <trivernis@protonmail.com>
pull/1/head
trivernis 3 years ago
parent 9ca1715177
commit deccbee806
Signed by: Trivernis
GPG Key ID: DFFFCC2C7A02DB45

@ -14,6 +14,7 @@ repository = "https://github.com/trivernis/hydrus-api-rs"
serde = {version = "^1.0", features = ["derive"]} serde = {version = "^1.0", features = ["derive"]}
reqwest = {version = "0.11.4", features = ["json"]} reqwest = {version = "0.11.4", features = ["json"]}
log = "0.4.14" log = "0.4.14"
mime = "0.3.16"
[dev-dependencies] [dev-dependencies]
env_logger = "0.8.4" env_logger = "0.8.4"

@ -22,7 +22,7 @@ pub struct FileMetadataInfo {
pub height: Option<u32>, pub height: Option<u32>,
pub duration: Option<u64>, pub duration: Option<u64>,
pub has_audio: Option<bool>, pub has_audio: Option<bool>,
pub num_frames: Option<u16>, pub num_frames: Option<u64>,
pub num_words: Option<u64>, pub num_words: Option<u64>,
pub is_inbox: bool, pub is_inbox: bool,
pub is_local: bool, pub is_local: bool,

@ -12,6 +12,7 @@ pub enum Error {
ImportVetoed(String), ImportVetoed(String),
ImportFailed(String), ImportFailed(String),
FileNotFound(FileIdentifier), FileNotFound(FileIdentifier),
InvalidMime(String),
} }
impl fmt::Display for Error { impl fmt::Display for Error {
@ -25,6 +26,7 @@ impl fmt::Display for Error {
Self::ImportFailed(msg) => write!(f, "File import failed: {}", msg), Self::ImportFailed(msg) => write!(f, "File import failed: {}", msg),
Self::ImportVetoed(msg) => write!(f, "File import vetoed: {}", msg), Self::ImportVetoed(msg) => write!(f, "File import vetoed: {}", msg),
Self::FileNotFound(id) => write!(f, "File {:?} not found", id), Self::FileNotFound(id) => write!(f, "File {:?} not found", id),
Self::InvalidMime(mime) => write!(f, "Failed to parse invalid mime {}", mime),
} }
} }
} }

@ -1,10 +1,11 @@
use crate::endpoints::adding_tags::{AddTagsRequestBuilder, TagAction}; use crate::endpoints::adding_tags::{AddTagsRequestBuilder, TagAction};
use crate::endpoints::common::{FileIdentifier, FileMetadataInfo, FileRecord}; use crate::endpoints::common::{FileIdentifier, FileMetadataInfo, FileRecord};
use crate::error::Result; use crate::error::{Error, Result};
use crate::service::ServiceName; use crate::service::ServiceName;
use crate::tag::Tag; use crate::tag::Tag;
use crate::utils::tag_list_to_string_list; use crate::utils::tag_list_to_string_list;
use crate::Client; use crate::Client;
use mime::Mime;
use std::collections::HashMap; use std::collections::HashMap;
#[derive(Clone, Debug, PartialOrd, PartialEq)] #[derive(Clone, Debug, PartialOrd, PartialEq)]
@ -77,25 +78,6 @@ impl HydrusFile {
Ok(()) Ok(())
} }
/// Returns the metadata for the given file
/// if there's already known metadata about the file it uses that
async fn metadata(&mut self) -> Result<&FileMetadataInfo> {
if self.metadata.is_none() {
let metadata = self
.client
.get_file_metadata_by_identifier(self.id.clone())
.await?;
self.status = if metadata.is_trashed {
FileStatus::Deleted
} else {
FileStatus::InDatabase
};
self.metadata = Some(metadata);
}
Ok(self.metadata.as_ref().unwrap())
}
/// Returns the hash of the file /// Returns the hash of the file
/// if the file identifier is an id it calls hydrus to resolve the file /// if the file identifier is an id it calls hydrus to resolve the file
pub async fn hash(&mut self) -> Result<String> { pub async fn hash(&mut self) -> Result<String> {
@ -108,6 +90,84 @@ impl HydrusFile {
} }
} }
/// Returns the file size in bytes
pub async fn size(&mut self) -> Result<Option<u64>> {
let metadata = self.metadata().await?;
Ok(metadata.size.clone())
}
/// Returns the mime of the file
pub async fn mime(&mut self) -> Result<Mime> {
let metadata = self.metadata().await?;
let mime = metadata
.mime
.as_str()
.parse()
.map_err(|_| Error::InvalidMime(metadata.mime.clone()))?;
Ok(mime)
}
/// Return the file extension
pub async fn ext(&mut self) -> Result<String> {
let metadata = self.metadata().await?;
Ok(metadata.ext.clone())
}
/// Returns the dimensions of the file in pixels
pub async fn dimensions(&mut self) -> Result<Option<(u32, u32)>> {
let metadata = self.metadata().await?;
if let (Some(width), Some(height)) = (&metadata.width, &metadata.height) {
Ok(Some((*width, *height)))
} else {
Ok(None)
}
}
/// Returns the duration of the file in seconds if it's a video
pub async fn duration(&mut self) -> Result<Option<u64>> {
let metadata = self.metadata().await?;
Ok(metadata.duration.clone())
}
/// Returns the number of frames of the file if it's a video
pub async fn num_frames(&mut self) -> Result<Option<u64>> {
let metadata = self.metadata().await?;
Ok(metadata.num_frames.clone())
}
/// Returns if the file has audio
pub async fn has_audio(&mut self) -> Result<bool> {
let metadata = self.metadata().await?;
Ok(metadata.has_audio.unwrap_or(false))
}
/// Returns if the file is currently in the inbox
pub async fn in_inbox(&mut self) -> Result<bool> {
let metadata = self.metadata().await?;
Ok(metadata.is_inbox)
}
/// Returns if the file is stored locally
pub async fn stored_locally(&mut self) -> Result<bool> {
let metadata = self.metadata().await?;
Ok(metadata.is_local)
}
/// Returns if the file has been moved to the trash
pub async fn moved_to_trashed(&mut self) -> Result<bool> {
let metadata = self.metadata().await?;
Ok(metadata.is_trashed)
}
/// Associates the file with a list of urls /// Associates the file with a list of urls
pub async fn associate_urls(&mut self, urls: Vec<String>) -> Result<()> { pub async fn associate_urls(&mut self, urls: Vec<String>) -> Result<()> {
let hash = self.hash().await?; let hash = self.hash().await?;
@ -182,4 +242,23 @@ impl HydrusFile {
pub async fn retrieve(&self) -> Result<FileRecord> { pub async fn retrieve(&self) -> Result<FileRecord> {
self.client.get_file(self.id.clone()).await self.client.get_file(self.id.clone()).await
} }
/// Returns the metadata for the given file
/// if there's already known metadata about the file it uses that
async fn metadata(&mut self) -> Result<&FileMetadataInfo> {
if self.metadata.is_none() {
let metadata = self
.client
.get_file_metadata_by_identifier(self.id.clone())
.await?;
self.status = if metadata.is_trashed {
FileStatus::Deleted
} else {
FileStatus::InDatabase
};
self.metadata = Some(metadata);
}
Ok(self.metadata.as_ref().unwrap())
}
} }

@ -80,3 +80,11 @@ async fn it_retrieves_content() {
assert!(file.bytes.len() > 0) // assuming it exists assert!(file.bytes.len() > 0) // assuming it exists
} }
#[tokio::test]
async fn it_retrieves_metadata() {
let mut file = get_file().await;
assert!(file.dimensions().await.unwrap().is_some());
assert!(file.stored_locally().await.unwrap());
assert!(file.duration().await.unwrap().is_none());
}

Loading…
Cancel
Save