Merge pull request #5 from Trivernis/feature/client-api-19

Feature/client api 19
pull/6/head
Julius Riegel 3 years ago committed by GitHub
commit b82ecbef75
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23

@ -21,7 +21,8 @@ use crate::api_core::managing_pages::{
GetPages, GetPagesResponse, GetPages, GetPagesResponse,
}; };
use crate::api_core::searching_and_fetching_files::{ use crate::api_core::searching_and_fetching_files::{
FileMetadata, FileMetadataResponse, GetFile, SearchFiles, SearchFilesResponse, FileMetadata, FileMetadataResponse, FileSearchOptions, GetFile, SearchFiles,
SearchFilesResponse,
}; };
use crate::api_core::Endpoint; use crate::api_core::Endpoint;
use crate::error::{Error, Result}; use crate::error::{Error, Result};
@ -222,13 +223,16 @@ impl Client {
} }
/// Searches for files in the inbox, the archive or both /// Searches for files in the inbox, the archive or both
pub async fn search_files(&self, tags: Vec<String>) -> Result<SearchFilesResponse> { pub async fn search_files(
&self,
tags: Vec<String>,
options: FileSearchOptions,
) -> Result<SearchFilesResponse> {
log::trace!("Searching for files with tags {:?}", tags); log::trace!("Searching for files with tags {:?}", tags);
self.get_and_parse::<SearchFiles, [(&str, String)]>(&[( let mut args = options.into_query_args();
"tags", args.push(("tags", string_list_to_json_array(tags)));
string_list_to_json_array(tags), self.get_and_parse::<SearchFiles, [(&str, String)]>(&args)
)]) .await
.await
} }
/// Returns the metadata for a given list of file_ids or hashes /// Returns the metadata for a given list of file_ids or hashes

@ -10,6 +10,7 @@ pub mod common;
pub mod managing_cookies_and_http_headers; pub mod managing_cookies_and_http_headers;
pub mod managing_pages; pub mod managing_pages;
pub mod searching_and_fetching_files; pub mod searching_and_fetching_files;
pub use searching_and_fetching_files::file_sort_type;
pub(crate) trait Endpoint { pub(crate) trait Endpoint {
type Request: Serialize; type Request: Serialize;

@ -1,6 +1,101 @@
use crate::api_core::common::FileMetadataInfo; use crate::api_core::common::FileMetadataInfo;
use crate::api_core::Endpoint; use crate::api_core::Endpoint;
pub mod file_sort_type {
pub const SORT_FILE_SIZE: u8 = 0;
pub const SORT_FILE_DURATION: u8 = 1;
pub const SORT_FILE_IMPORT_TIME: u8 = 2;
pub const SORT_FILE_TYPE: u8 = 3;
pub const SORT_FILE_RANDOM: u8 = 4;
pub const SORT_FILE_WIDTH: u8 = 5;
pub const SORT_FILE_HEIGHT: u8 = 6;
pub const SORT_FILE_RATIO: u8 = 7;
pub const SORT_FILE_PIXEL_COUNT: u8 = 8;
pub const SORT_FILE_TAG_COUNT: u8 = 9;
pub const SORT_FILE_MEDIA_VIEWS: u8 = 10;
pub const SORT_FILE_MEDIA_VIEWTIME: u8 = 11;
pub const SORT_FILE_BITRATE: u8 = 12;
pub const SORT_FILE_HAS_AUDIO: u8 = 13;
pub const SORT_FILE_MODIFIED_TIME: u8 = 14;
pub const SORT_FILE_FRAMERATE: u8 = 15;
pub const SORT_FILE_FRAME_COUNT: u8 = 16;
}
#[derive(Clone, Debug, Default)]
pub struct FileSearchOptions {
file_service_name: Option<String>,
file_service_key: Option<String>,
tag_service_name: Option<String>,
tag_service_key: Option<String>,
file_sort_type: Option<u8>,
file_sort_asc: Option<bool>,
}
impl FileSearchOptions {
pub fn new() -> Self {
Self::default()
}
pub fn file_service_name<S: ToString>(mut self, name: S) -> Self {
self.file_service_name = Some(name.to_string());
self
}
pub fn file_service_key<S: ToString>(mut self, key: S) -> Self {
self.file_service_key = Some(key.to_string());
self
}
pub fn tag_service_name<S: ToString>(mut self, name: S) -> Self {
self.tag_service_name = Some(name.to_string());
self
}
pub fn tag_service_key<S: ToString>(mut self, key: S) -> Self {
self.tag_service_key = Some(key.to_string());
self
}
pub fn sort_type(mut self, sort_type: u8) -> Self {
self.file_sort_type = Some(sort_type);
self
}
pub fn asc(mut self) -> Self {
self.file_sort_asc = Some(true);
self
}
pub fn desc(mut self) -> Self {
self.file_sort_asc = Some(false);
self
}
pub(crate) fn into_query_args(self) -> Vec<(&'static str, String)> {
let mut args = Vec::new();
if let Some(sort) = self.file_sort_type {
args.push(("file_sort_type", sort.to_string()));
}
if let Some(file_service_name) = self.file_service_name {
args.push(("file_service_name", file_service_name));
}
if let Some(file_service_key) = self.file_service_key {
args.push(("file_service_key", file_service_key));
}
if let Some(tag_service_name) = self.tag_service_name {
args.push(("tag_service_name", tag_service_name))
}
if let Some(tag_service_key) = self.tag_service_key {
args.push(("tag_service_key", tag_service_key));
}
if let Some(sort_asc) = self.file_sort_asc {
args.push(("file_sort_asc", sort_asc.to_string()))
}
args
}
}
#[derive(Debug, Clone, Deserialize)] #[derive(Debug, Clone, Deserialize)]
pub struct SearchFilesResponse { pub struct SearchFilesResponse {
pub file_ids: Vec<u64>, pub file_ids: Vec<u64>,

@ -1,3 +1,4 @@
pub mod import_builder; pub mod import_builder;
pub mod tagging_builder; pub mod tagging_builder;
pub mod tag_builder; pub mod tag_builder;
pub mod search_builder;

@ -0,0 +1,115 @@
use crate::api_core::searching_and_fetching_files::FileSearchOptions;
use crate::error::Result;
use crate::utils::tag_list_to_string_list;
use crate::wrapper::hydrus_file::HydrusFile;
use crate::wrapper::service::ServiceName;
use crate::wrapper::tag::Tag;
use crate::Client;
pub enum SortType {
FileSize,
Duration,
ImportTime,
FileType,
Random,
Width,
Height,
Ratio,
NumberOfPixels,
NumberOfTags,
NumberOfMediaViewers,
MediaViewTime,
Bitrate,
HasAudio,
ModifiedTime,
Framerate,
NumberOfFrames,
}
#[derive(Clone, Debug)]
pub struct SearchBuilder {
client: Client,
tags: Vec<Tag>,
options: FileSearchOptions,
}
impl SearchBuilder {
pub(crate) fn new(client: Client) -> Self {
Self {
client,
tags: Vec::new(),
options: FileSearchOptions::new(),
}
}
/// Add multiple tags to filter by
pub fn add_tags(mut self, mut tags: Vec<Tag>) -> Self {
self.tags.append(&mut tags);
self
}
/// Add a tag to filter by
pub fn add_tag(mut self, tag: Tag) -> Self {
self.tags.push(tag);
self
}
/// Sets the sort type
pub fn sort_by(mut self, sort_type: SortType) -> Self {
self.options = self.options.sort_type(sort_type as u8);
self
}
/// Sorts descending
pub fn sort_descending(mut self) -> Self {
self.options = self.options.desc();
self
}
/// Sorts ascending
pub fn sort_ascending(mut self) -> Self {
self.options = self.options.asc();
self
}
/// Sets the file service name to search in
pub fn file_service_name(mut self, service: ServiceName) -> Self {
self.options = self.options.file_service_name(service);
self
}
/// Sets the tag service to search by
pub fn tag_service_name(mut self, service: ServiceName) -> Self {
self.options = self.options.tag_service_name(service);
self
}
/// Sets the file service key. This option is preferred over
/// setting it by name because it's faster
pub fn file_service_key<S: ToString>(mut self, key: S) -> Self {
self.options = self.options.file_service_key(key);
self
}
/// Sets the tag service key. This option is preferred over
/// setting it by name because it's faster
pub fn tag_service_key<S: ToString>(mut self, key: S) -> Self {
self.options = self.options.tag_service_key(key);
self
}
/// Runs the search
pub async fn run(self) -> Result<Vec<HydrusFile>> {
let client = self.client.clone();
let response = client
.search_files(tag_list_to_string_list(self.tags), self.options)
.await?;
let files = response
.file_ids
.into_iter()
.map(|id| HydrusFile::from_id(client.clone(), id))
.collect();
Ok(files)
}
}

@ -1,13 +1,12 @@
use crate::api_core::common::FileIdentifier; use crate::api_core::common::FileIdentifier;
use crate::error::Result; use crate::error::Result;
use crate::utils::tag_list_to_string_list;
use crate::wrapper::address::Address; use crate::wrapper::address::Address;
use crate::wrapper::builders::import_builder::ImportBuilder; use crate::wrapper::builders::import_builder::ImportBuilder;
use crate::wrapper::builders::search_builder::SearchBuilder;
use crate::wrapper::builders::tagging_builder::TaggingBuilder; use crate::wrapper::builders::tagging_builder::TaggingBuilder;
use crate::wrapper::hydrus_file::HydrusFile; use crate::wrapper::hydrus_file::HydrusFile;
use crate::wrapper::page::HydrusPage; use crate::wrapper::page::HydrusPage;
use crate::wrapper::service::Services; use crate::wrapper::service::Services;
use crate::wrapper::tag::Tag;
use crate::wrapper::url::Url; use crate::wrapper::url::Url;
use crate::wrapper::version::Version; use crate::wrapper::version::Version;
use crate::Client; use crate::Client;
@ -82,19 +81,9 @@ impl Hydrus {
TaggingBuilder::new(self.client.clone()) TaggingBuilder::new(self.client.clone())
} }
/// Searches for files that have the given tags and returns a list of hydrus files as a result /// Starts a request to search for files
pub async fn search(&self, tags: Vec<Tag>) -> Result<Vec<HydrusFile>> { pub fn search(&self) -> SearchBuilder {
let search_result = self SearchBuilder::new(self.client.clone())
.client
.search_files(tag_list_to_string_list(tags))
.await?;
let files = search_result
.file_ids
.into_iter()
.map(|id| HydrusFile::from_id(self.client.clone(), id))
.collect();
Ok(files)
} }
/// Returns a hydrus page by page key /// Returns a hydrus page by page key

@ -6,6 +6,7 @@ use crate::api_core::access_management::{
}; };
use crate::error::Error; use crate::error::Error;
use crate::wrapper::builders::search_builder::SearchBuilder;
use crate::Client; use crate::Client;
use std::collections::HashMap; use std::collections::HashMap;
use std::convert::TryFrom; use std::convert::TryFrom;
@ -103,6 +104,22 @@ pub struct Service {
pub service_type: ServiceType, pub service_type: ServiceType,
} }
impl Service {
pub fn search(&self) -> SearchBuilder {
let builder = SearchBuilder::new(self.client.clone());
match self.service_type {
ServiceType::LocalTags | ServiceType::TagRepositories | ServiceType::AllKnownTags => {
builder.tag_service_key(&self.key)
}
ServiceType::LocalFiles
| ServiceType::FileRepositories
| ServiceType::AllLocalFiles
| ServiceType::AllKnownFiles
| ServiceType::Trash => builder.file_service_key(&self.key),
}
}
}
#[derive(Clone)] #[derive(Clone)]
pub struct Services { pub struct Services {
inner: HashMap<ServiceType, Vec<Service>>, inner: HashMap<ServiceType, Vec<Service>>,

@ -1,11 +1,17 @@
use super::super::common; use super::super::common;
use hydrus_api::api_core::common::FileIdentifier; use hydrus_api::api_core::common::FileIdentifier;
use hydrus_api::api_core::file_sort_type::SORT_FILE_PIXEL_COUNT;
use hydrus_api::api_core::searching_and_fetching_files::FileSearchOptions;
#[tokio::test] #[tokio::test]
async fn is_searches_files() { async fn is_searches_files() {
let client = common::get_client(); let client = common::get_client();
let options = FileSearchOptions::new()
.sort_type(SORT_FILE_PIXEL_COUNT)
.tag_service_name("public tag repository")
.file_service_name("all known files");
client client
.search_files(vec!["beach".to_string()]) .search_files(vec!["beach".to_string()], options)
.await .await
.unwrap(); .unwrap();
} }

@ -1,7 +1,8 @@
mod test_address;
mod test_files; mod test_files;
mod test_hydrus; mod test_hydrus;
mod test_import; mod test_import;
mod test_url;
mod test_page; mod test_page;
mod test_address; mod test_service;
mod test_tags; mod test_tags;
mod test_url;

@ -1,5 +1,6 @@
use super::super::common; use super::super::common;
use hydrus_api::api_core::adding_tags::TagAction; use hydrus_api::api_core::adding_tags::TagAction;
use hydrus_api::wrapper::builders::search_builder::SortType;
use hydrus_api::wrapper::service::{ServiceName, ServiceType}; use hydrus_api::wrapper::service::{ServiceName, ServiceType};
use hydrus_api::wrapper::url::UrlType; use hydrus_api::wrapper::url::UrlType;
@ -36,7 +37,10 @@ async fn it_retrieves_url_information() {
async fn it_searches() { async fn it_searches() {
let hydrus = common::get_hydrus(); let hydrus = common::get_hydrus();
hydrus hydrus
.search(vec!["character:megumin".into()]) .search()
.add_tag("character:megumin".into())
.sort_by(SortType::ModifiedTime)
.run()
.await .await
.unwrap(); .unwrap();
} }

@ -0,0 +1,27 @@
use super::super::common;
use hydrus_api::wrapper::service::{Service, ServiceType, Services};
async fn get_services() -> Services {
let hydrus = common::get_hydrus();
hydrus.services().await.unwrap()
}
async fn get_file_service() -> Service {
let services = get_services().await;
services
.get_services(ServiceType::LocalFiles)
.pop()
.unwrap()
.clone()
}
#[tokio::test]
async fn it_searches_for_files() {
let service = get_file_service().await;
service
.search()
.add_tag("character:rimuru tempest".into())
.run()
.await
.unwrap();
}

@ -10,7 +10,7 @@ use hydrus_api::wrapper::tag::Tag;
async fn retrieve_single_tag(tag: Tag) -> Result<()> { async fn retrieve_single_tag(tag: Tag) -> Result<()> {
let hydrus = common::get_hydrus(); let hydrus = common::get_hydrus();
hydrus.search(vec![tag]).await?; hydrus.search().add_tag(tag).run().await?;
Ok(()) Ok(())
} }

Loading…
Cancel
Save