Add importing to hydrus wrapper
Signed-off-by: trivernis <trivernis@protonmail.com>pull/1/head
parent
ef8d998efb
commit
798e37141e
@ -0,0 +1,158 @@
|
|||||||
|
use crate::endpoints::adding_files::{STATUS_IMPORT_FAILED, STATUS_IMPORT_VETOED};
|
||||||
|
use crate::endpoints::adding_urls::AddUrlRequestBuilder;
|
||||||
|
use crate::endpoints::common::FileIdentifier;
|
||||||
|
use crate::error::{Error, Result};
|
||||||
|
use crate::hydrus_file::HydrusFile;
|
||||||
|
use crate::models::url::Url;
|
||||||
|
use crate::page::PageIdentifier;
|
||||||
|
use crate::service::ServiceName;
|
||||||
|
use crate::tag::Tag;
|
||||||
|
use crate::utils::tag_list_to_string_list;
|
||||||
|
use crate::Client;
|
||||||
|
use std::collections::HashMap;
|
||||||
|
use std::io::Read;
|
||||||
|
|
||||||
|
pub struct ImportBuilder {
|
||||||
|
pub(crate) client: Client,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl ImportBuilder {
|
||||||
|
pub fn file(self, file: FileImport) -> FileImportBuilder {
|
||||||
|
FileImportBuilder {
|
||||||
|
client: self.client,
|
||||||
|
file,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn url<S: ToString>(self, url: S) -> UrlImportBuilder {
|
||||||
|
UrlImportBuilder {
|
||||||
|
client: self.client,
|
||||||
|
url: url.to_string(),
|
||||||
|
page: None,
|
||||||
|
show_page: false,
|
||||||
|
filter_tags: vec![],
|
||||||
|
service_tag_mappings: Default::default(),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
pub enum FileImport {
|
||||||
|
Path(String),
|
||||||
|
Binary(Vec<u8>),
|
||||||
|
}
|
||||||
|
|
||||||
|
impl FileImport {
|
||||||
|
pub fn path<S: ToString>(path: S) -> Self {
|
||||||
|
Self::Path(path.to_string())
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn binary<R: Read>(reader: &mut R) -> Self {
|
||||||
|
let mut bytes = Vec::new();
|
||||||
|
let _ = reader.read_to_end(&mut bytes);
|
||||||
|
Self::Binary(bytes)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
pub struct FileImportBuilder {
|
||||||
|
client: Client,
|
||||||
|
file: FileImport,
|
||||||
|
}
|
||||||
|
|
||||||
|
pub struct UrlImportBuilder {
|
||||||
|
client: Client,
|
||||||
|
url: String,
|
||||||
|
page: Option<PageIdentifier>,
|
||||||
|
show_page: bool,
|
||||||
|
filter_tags: Vec<Tag>,
|
||||||
|
service_tag_mappings: HashMap<String, Vec<Tag>>,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl FileImportBuilder {
|
||||||
|
pub async fn run(mut self) -> Result<HydrusFile> {
|
||||||
|
let response = match self.file {
|
||||||
|
FileImport::Path(path) => self.client.add_file(path).await?,
|
||||||
|
FileImport::Binary(b) => self.client.add_binary_file(b).await?,
|
||||||
|
};
|
||||||
|
|
||||||
|
if response.status == STATUS_IMPORT_FAILED {
|
||||||
|
Err(Error::ImportFailed(response.note))
|
||||||
|
} else if response.status == STATUS_IMPORT_VETOED {
|
||||||
|
Err(Error::ImportVetoed(response.note))
|
||||||
|
} else {
|
||||||
|
Ok(HydrusFile {
|
||||||
|
client: self.client,
|
||||||
|
id: FileIdentifier::Hash(response.hash),
|
||||||
|
})
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl UrlImportBuilder {
|
||||||
|
/// Sets the destination page of the import
|
||||||
|
pub fn set_page(mut self, page: PageIdentifier) -> Self {
|
||||||
|
self.page = Some(page);
|
||||||
|
|
||||||
|
self
|
||||||
|
}
|
||||||
|
|
||||||
|
/// If the destination page of the import should be focussed
|
||||||
|
pub fn show_page(mut self, show: bool) -> Self {
|
||||||
|
self.show_page = show;
|
||||||
|
|
||||||
|
self
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Adds a tag that should be filtered
|
||||||
|
pub fn add_filter_tag(mut self, tag: Tag) -> Self {
|
||||||
|
self.filter_tags.push(tag);
|
||||||
|
|
||||||
|
self
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Adds multiple tags that should be filtered
|
||||||
|
pub fn add_filter_tags(mut self, mut tags: Vec<Tag>) -> Self {
|
||||||
|
self.filter_tags.append(&mut tags);
|
||||||
|
|
||||||
|
self
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Adds an additional tag for the imported file
|
||||||
|
pub fn add_additional_tag(self, service: ServiceName, tag: Tag) -> Self {
|
||||||
|
self.add_additional_tags(service, vec![tag])
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Adds multiple additional tags for the import
|
||||||
|
pub fn add_additional_tags(mut self, service: ServiceName, mut tags: Vec<Tag>) -> Self {
|
||||||
|
if let Some(service_tags) = self.service_tag_mappings.get_mut(&service.0) {
|
||||||
|
service_tags.append(&mut tags);
|
||||||
|
} else {
|
||||||
|
self.service_tag_mappings.insert(service.0, tags);
|
||||||
|
}
|
||||||
|
|
||||||
|
self
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Imports the URL
|
||||||
|
pub async fn run(mut self) -> Result<Url> {
|
||||||
|
let mut request = AddUrlRequestBuilder::default().url(self.url.clone());
|
||||||
|
|
||||||
|
for (service, tags) in self.service_tag_mappings {
|
||||||
|
request = request.add_tags(service, tag_list_to_string_list(tags));
|
||||||
|
}
|
||||||
|
request = request.add_filter_tags(tag_list_to_string_list(self.filter_tags));
|
||||||
|
if let Some(page) = self.page {
|
||||||
|
request = match page {
|
||||||
|
PageIdentifier::Name(n) => request.destination_page_name(n),
|
||||||
|
PageIdentifier::Key(k) => request.destination_page_key(k),
|
||||||
|
};
|
||||||
|
}
|
||||||
|
request = request.show_destination_page(self.show_page);
|
||||||
|
|
||||||
|
let response = self.client.add_url(request.build()).await?;
|
||||||
|
|
||||||
|
Ok(Url {
|
||||||
|
url: self.url,
|
||||||
|
normalised_url: Some(response.normalised_url),
|
||||||
|
})
|
||||||
|
}
|
||||||
|
}
|
@ -0,0 +1 @@
|
|||||||
|
pub mod import_builder;
|
@ -0,0 +1,8 @@
|
|||||||
|
use crate::endpoints::common::FileIdentifier;
|
||||||
|
use crate::Client;
|
||||||
|
|
||||||
|
#[derive(Clone)]
|
||||||
|
pub struct HydrusFile {
|
||||||
|
pub(crate) client: Client,
|
||||||
|
pub id: FileIdentifier,
|
||||||
|
}
|
@ -1,4 +1,8 @@
|
|||||||
pub mod builders;
|
pub mod builders;
|
||||||
pub mod hydrus;
|
pub mod hydrus;
|
||||||
|
pub mod hydrus_file;
|
||||||
|
pub mod page;
|
||||||
pub mod service;
|
pub mod service;
|
||||||
|
pub mod tag;
|
||||||
|
pub mod url;
|
||||||
pub mod version;
|
pub mod version;
|
||||||
|
@ -0,0 +1,20 @@
|
|||||||
|
#[derive(Clone)]
|
||||||
|
pub struct HydrusPage {
|
||||||
|
pub id: PageIdentifier,
|
||||||
|
}
|
||||||
|
|
||||||
|
#[derive(Clone)]
|
||||||
|
pub enum PageIdentifier {
|
||||||
|
Name(String),
|
||||||
|
Key(String),
|
||||||
|
}
|
||||||
|
|
||||||
|
impl PageIdentifier {
|
||||||
|
pub fn name<S: ToString>(name: S) -> Self {
|
||||||
|
Self::Name(name.to_string())
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn key<S: ToString>(key: S) -> Self {
|
||||||
|
Self::Key(key.to_string())
|
||||||
|
}
|
||||||
|
}
|
@ -0,0 +1,35 @@
|
|||||||
|
#[derive(Clone, Debug)]
|
||||||
|
pub struct Tag {
|
||||||
|
pub name: String,
|
||||||
|
pub namespace: Option<String>,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl<S> From<S> for Tag
|
||||||
|
where
|
||||||
|
S: AsRef<str>,
|
||||||
|
{
|
||||||
|
fn from(value: S) -> Self {
|
||||||
|
let value = value.as_ref();
|
||||||
|
if let Some((namespace, tag)) = value.split_once(":") {
|
||||||
|
Self {
|
||||||
|
namespace: Some(namespace.to_string()),
|
||||||
|
name: tag.to_string(),
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
Self {
|
||||||
|
name: value.to_string(),
|
||||||
|
namespace: None,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl ToString for Tag {
|
||||||
|
fn to_string(&self) -> String {
|
||||||
|
if let Some(namespace) = &self.namespace {
|
||||||
|
format!("{}:{}", namespace, self.name)
|
||||||
|
} else {
|
||||||
|
self.name.clone()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
@ -0,0 +1,5 @@
|
|||||||
|
#[derive(Clone)]
|
||||||
|
pub struct Url {
|
||||||
|
pub url: String,
|
||||||
|
pub normalised_url: Option<String>,
|
||||||
|
}
|
@ -1 +1,2 @@
|
|||||||
mod test_hydrus;
|
mod test_hydrus;
|
||||||
|
mod test_import;
|
||||||
|
@ -0,0 +1,48 @@
|
|||||||
|
use super::super::common;
|
||||||
|
use hydrus_api::builders::import_builder::FileImport;
|
||||||
|
use hydrus_api::page::PageIdentifier;
|
||||||
|
use hydrus_api::service::ServiceName;
|
||||||
|
use hydrus_api::tag::Tag;
|
||||||
|
|
||||||
|
#[tokio::test]
|
||||||
|
async fn it_imports_file_paths() {
|
||||||
|
let mut hydrus = common::get_hydrus();
|
||||||
|
let result = hydrus
|
||||||
|
.import()
|
||||||
|
.file(FileImport::path("/does/not/exist/sadly"))
|
||||||
|
.run()
|
||||||
|
.await;
|
||||||
|
|
||||||
|
assert!(result.is_err()) // file does not exist
|
||||||
|
}
|
||||||
|
|
||||||
|
#[tokio::test]
|
||||||
|
async fn it_imports_binary_files() {
|
||||||
|
let mut hydrus = common::get_hydrus();
|
||||||
|
let bytes = [0u8, 0u8, 0u8, 0u8];
|
||||||
|
let result = hydrus
|
||||||
|
.import()
|
||||||
|
.file(FileImport::binary(&mut &bytes[..]))
|
||||||
|
.run()
|
||||||
|
.await;
|
||||||
|
|
||||||
|
assert!(result.is_err()) // return status should be 4
|
||||||
|
}
|
||||||
|
|
||||||
|
#[tokio::test]
|
||||||
|
async fn it_imports_urls() {
|
||||||
|
let mut hydrus = common::get_hydrus();
|
||||||
|
|
||||||
|
let result = hydrus
|
||||||
|
.import()
|
||||||
|
.url("https://www.pixiv.net/member_illust.php?illust_id=83406361&mode=medium")
|
||||||
|
.set_page(PageIdentifier::name("Rusty Import"))
|
||||||
|
.show_page(true)
|
||||||
|
.add_additional_tag(ServiceName::my_tags(), Tag::from("ark mage"))
|
||||||
|
.add_additional_tag(ServiceName::my_tags(), Tag::from("character:megumin"))
|
||||||
|
.run()
|
||||||
|
.await
|
||||||
|
.unwrap();
|
||||||
|
|
||||||
|
assert!(result.normalised_url.is_some()) // because it's returned by the import
|
||||||
|
}
|
Loading…
Reference in New Issue