Addd Tag and System Tag builder
This change also removes the Search location type. With the System Tag Builder all expressions for searching for tags with the system predicate can be build. Signed-off-by: trivernis <trivernis@protonmail.com>pull/4/head
parent
72dfe76172
commit
f1a423f721
@ -1,2 +1,3 @@
|
|||||||
pub mod import_builder;
|
pub mod import_builder;
|
||||||
pub mod tagging_builder;
|
pub mod tagging_builder;
|
||||||
|
pub mod tag_builder;
|
||||||
|
@ -0,0 +1,479 @@
|
|||||||
|
use crate::utils::{format_datetime, format_duration};
|
||||||
|
use crate::wrapper::service::ServiceName;
|
||||||
|
use crate::wrapper::tag::Tag;
|
||||||
|
use chrono::{Datelike, Duration};
|
||||||
|
use mime::Mime;
|
||||||
|
use std::fmt::{Display, Formatter};
|
||||||
|
|
||||||
|
#[derive(Clone, Debug)]
|
||||||
|
pub struct TagBuilder {
|
||||||
|
negated: bool,
|
||||||
|
name: String,
|
||||||
|
namespace: Option<String>,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl TagBuilder {
|
||||||
|
pub fn new<S: ToString>(name: S) -> Self {
|
||||||
|
Self {
|
||||||
|
negated: false,
|
||||||
|
name: name.to_string(),
|
||||||
|
namespace: None,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Set a namespace for the tag
|
||||||
|
pub fn namespace<S: ToString>(mut self, namespace: S) -> Self {
|
||||||
|
self.namespace = Some(namespace.to_string());
|
||||||
|
|
||||||
|
self
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Converts the builder into a system tag builder
|
||||||
|
pub fn system(self) -> SystemTagBuilder {
|
||||||
|
SystemTagBuilder {
|
||||||
|
negated: false,
|
||||||
|
name: self.name,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Negates the tag.
|
||||||
|
/// if it has already been negated it will be positive again
|
||||||
|
pub fn negate(mut self) -> Self {
|
||||||
|
self.negated = !self.negated;
|
||||||
|
|
||||||
|
self
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn build(self) -> Tag {
|
||||||
|
Tag {
|
||||||
|
negated: self.negated,
|
||||||
|
name: self.name,
|
||||||
|
namespace: self.namespace,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
#[derive(Clone, Debug)]
|
||||||
|
pub struct SystemTagBuilder {
|
||||||
|
name: String,
|
||||||
|
negated: bool,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl SystemTagBuilder {
|
||||||
|
pub fn new() -> SystemTagBuilder {
|
||||||
|
SystemTagBuilder {
|
||||||
|
name: String::new(),
|
||||||
|
negated: false,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn build(self) -> Tag {
|
||||||
|
Tag {
|
||||||
|
negated: self.negated,
|
||||||
|
name: self.name,
|
||||||
|
namespace: Some(String::from("system")),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Negates the tag.
|
||||||
|
/// if it has already been negated it will be positive again
|
||||||
|
pub fn negate(mut self) -> Self {
|
||||||
|
self.negated = !self.negated;
|
||||||
|
|
||||||
|
self
|
||||||
|
}
|
||||||
|
|
||||||
|
/// All files stored in the client
|
||||||
|
pub fn everything(self) -> Self {
|
||||||
|
self.change_name("everything")
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Files stored in the inbox
|
||||||
|
pub fn inbox(self) -> Self {
|
||||||
|
self.change_name("inbox")
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Archived files
|
||||||
|
pub fn archive(self) -> Self {
|
||||||
|
self.change_name("archive")
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Files that have a duration (e.g. videos)
|
||||||
|
pub fn has_duration(self) -> Self {
|
||||||
|
self.change_name("has duration")
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Files that don't have a duration
|
||||||
|
pub fn no_duration(self) -> Self {
|
||||||
|
self.change_name("no duration")
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Files with a specific duration
|
||||||
|
pub fn duration(self, comparator: Comparator, value: u64, unit: DurationUnit) -> Self {
|
||||||
|
self.change_name(format!("duration {} {} {}", comparator, value, unit))
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Files that have the best quality in their duplicate group
|
||||||
|
pub fn best_duplicate_quality(self) -> Self {
|
||||||
|
self.change_name("best quality of group")
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Files that don't have the best quality in their duplicate group
|
||||||
|
pub fn not_best_duplicate_quality(self) -> Self {
|
||||||
|
self.change_name("isn't best quality of group")
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Files with audio
|
||||||
|
pub fn has_audio(self) -> Self {
|
||||||
|
self.change_name("has audio")
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Files without audio
|
||||||
|
pub fn no_audio(self) -> Self {
|
||||||
|
self.change_name("no audio")
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Files with tags
|
||||||
|
pub fn has_tags(self) -> Self {
|
||||||
|
self.change_name("has tags")
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Files without tags
|
||||||
|
pub fn no_tags(self) -> Self {
|
||||||
|
self.change_name("no tags")
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Untagged files
|
||||||
|
pub fn untagged(self) -> Self {
|
||||||
|
self.change_name("untagged")
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Files with a specific number of tags
|
||||||
|
pub fn number_of_tags(self, comparator: Comparator, value: u64) -> Self {
|
||||||
|
self.change_name(format!("number of tags {} {}", comparator, value))
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Files with a specific height
|
||||||
|
pub fn height(self, comparator: Comparator, value: u64) -> Self {
|
||||||
|
self.change_name(format!("height {} {}", comparator, value))
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Files with a specific width
|
||||||
|
pub fn width(self, comparator: Comparator, value: u64) -> Self {
|
||||||
|
self.change_name(format!("width {} {}", comparator, value))
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Files with a specific filesize
|
||||||
|
pub fn filesize(self, comparator: Comparator, value: u64, unit: FileSizeUnit) -> Self {
|
||||||
|
self.change_name(format!("filesize {} {} {}", comparator, value, unit))
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Files that are similar to a list of other files with a specific [hamming distance](https://en.wikipedia.org/wiki/Hamming_distance)
|
||||||
|
pub fn similar_to(self, hashes: Vec<String>, distance: u32) -> Self {
|
||||||
|
self.change_name(format!(
|
||||||
|
"similar to {} with distance {}",
|
||||||
|
hashes.join(", "),
|
||||||
|
distance
|
||||||
|
))
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Limit the number of returned files
|
||||||
|
pub fn limit(self, value: u64) -> Self {
|
||||||
|
self.change_name(format!("limit = {}", value))
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Files with a specific mimetype
|
||||||
|
pub fn filetype(self, mimes: Vec<Mime>) -> Self {
|
||||||
|
self.change_name(format!(
|
||||||
|
"filetype = {}",
|
||||||
|
mimes
|
||||||
|
.into_iter()
|
||||||
|
.map(|m| m.to_string())
|
||||||
|
.collect::<Vec<String>>()
|
||||||
|
.join(", ")
|
||||||
|
))
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Files with a specific hash
|
||||||
|
pub fn hash(self, hashes: Vec<String>) -> Self {
|
||||||
|
self.change_name(format!("hash = {}", hashes.join(" ")))
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Files that have been modified before / after / at / around a specific date and time
|
||||||
|
pub fn date_modified<D: Datelike>(self, comparator: Comparator, datetime: D) -> Self {
|
||||||
|
self.change_name(format!(
|
||||||
|
"modified date {} {}",
|
||||||
|
comparator,
|
||||||
|
format_datetime(datetime)
|
||||||
|
))
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Files with a specific import time
|
||||||
|
pub fn time_imported<D: Datelike>(self, comparator: Comparator, datetime: D) -> Self {
|
||||||
|
self.change_name(format!(
|
||||||
|
"time imported {} {}",
|
||||||
|
comparator,
|
||||||
|
format_datetime(datetime)
|
||||||
|
))
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Files that are in a file service or pending to it
|
||||||
|
pub fn file_service(
|
||||||
|
self,
|
||||||
|
comparator: IsComparator,
|
||||||
|
cur_pen: CurrentlyOrPending,
|
||||||
|
service: ServiceName,
|
||||||
|
) -> Self {
|
||||||
|
self.change_name(format!(
|
||||||
|
"file service {} {} {}",
|
||||||
|
comparator, cur_pen, service
|
||||||
|
))
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Files that have a specific number of relationships
|
||||||
|
pub fn number_of_relationships(
|
||||||
|
self,
|
||||||
|
comparator: Comparator,
|
||||||
|
value: u64,
|
||||||
|
relationship: FileRelationshipType,
|
||||||
|
) -> Self {
|
||||||
|
self.change_name(format!(
|
||||||
|
"num file relationships {} {} {}",
|
||||||
|
comparator, value, relationship
|
||||||
|
))
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Files with a specific aspect ratio
|
||||||
|
pub fn ratio(self, wte: WiderTallerEqual, value: (u64, u64)) -> Self {
|
||||||
|
self.change_name(format!("ratio {} {}:{}", wte, value.0, value.1))
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Files with a specific number of pixels
|
||||||
|
pub fn number_of_pixels(self, comparator: Comparator, value: u64, unit: PixelUnit) -> Self {
|
||||||
|
self.change_name(format!("num pixels {} {} {}", comparator, value, unit))
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Files that have been viewed a specific number of times
|
||||||
|
pub fn views(self, view_type: ViewType, comparator: Comparator, value: u64) -> Self {
|
||||||
|
self.change_name(format!("{} views {} {}", view_type, comparator, value))
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Files that have been viewed for a specific number of times
|
||||||
|
pub fn viewtime(self, view_type: ViewType, comparator: Comparator, duration: Duration) -> Self {
|
||||||
|
self.change_name(format!(
|
||||||
|
"{} viewtime {} {}",
|
||||||
|
view_type,
|
||||||
|
comparator,
|
||||||
|
format_duration(duration)
|
||||||
|
))
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Files that have associated urls that match a defined regex
|
||||||
|
pub fn has_url_matching_regex<S: Display>(self, regex: S) -> Self {
|
||||||
|
self.change_name(format!("has url matching regex {}", regex))
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Files that don't have an url that matches a defined regex
|
||||||
|
pub fn does_not_have_url_matching_regex<S: Display>(self, regex: S) -> Self {
|
||||||
|
self.change_name(format!("does not have url matching regex {}", regex))
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Files that have an url that matches a class (e.g. 'safebooru file page')
|
||||||
|
pub fn has_url_with_class<S: Display>(self, class: S) -> Self {
|
||||||
|
self.change_name(format!("has url with class {}", class))
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Files that don't have an url that matches a class (e.g. 'safebooru file page')
|
||||||
|
pub fn does_not_have_url_with_class<S: Display>(self, class: S) -> Self {
|
||||||
|
self.change_name(format!("does not have url with class {}", class))
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Converts a tag namespace (e.g. 'page') into a number and compares it
|
||||||
|
pub fn tag_namespace_as_number<S: Display>(
|
||||||
|
self,
|
||||||
|
namespace: S,
|
||||||
|
comparator: Comparator,
|
||||||
|
value: u64,
|
||||||
|
) -> Self {
|
||||||
|
self.change_name(format!(
|
||||||
|
"tag as number {} {} {}",
|
||||||
|
namespace, comparator, value
|
||||||
|
))
|
||||||
|
}
|
||||||
|
|
||||||
|
fn change_name<S: ToString>(mut self, value: S) -> Self {
|
||||||
|
self.name = value.to_string();
|
||||||
|
|
||||||
|
self
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
#[derive(Clone, Debug, PartialOrd, PartialEq)]
|
||||||
|
pub enum Comparator {
|
||||||
|
/// rhs > lhs
|
||||||
|
Greater,
|
||||||
|
/// rhs < lhs
|
||||||
|
Less,
|
||||||
|
/// rhs == lhs
|
||||||
|
Equal,
|
||||||
|
/// If the rhs is in a +-15% range of the lhs
|
||||||
|
Approximate,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl Display for Comparator {
|
||||||
|
fn fmt(&self, f: &mut Formatter<'_>) -> std::fmt::Result {
|
||||||
|
let symbol = match self {
|
||||||
|
Comparator::Greater => ">",
|
||||||
|
Comparator::Less => "<",
|
||||||
|
Comparator::Equal => "=",
|
||||||
|
Comparator::Approximate => "~=",
|
||||||
|
};
|
||||||
|
symbol.fmt(f)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
#[derive(Clone, Debug, PartialOrd, PartialEq)]
|
||||||
|
pub enum FileSizeUnit {
|
||||||
|
Bytes,
|
||||||
|
Kilobytes,
|
||||||
|
Megabytes,
|
||||||
|
Gigabytes,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl Display for FileSizeUnit {
|
||||||
|
fn fmt(&self, f: &mut Formatter<'_>) -> std::fmt::Result {
|
||||||
|
let name = match self {
|
||||||
|
FileSizeUnit::Bytes => "B",
|
||||||
|
FileSizeUnit::Kilobytes => "KB",
|
||||||
|
FileSizeUnit::Megabytes => "MB",
|
||||||
|
FileSizeUnit::Gigabytes => "GB",
|
||||||
|
};
|
||||||
|
name.fmt(f)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
#[derive(Clone, Debug, PartialOrd, PartialEq)]
|
||||||
|
pub enum DurationUnit {
|
||||||
|
Hours,
|
||||||
|
Minutes,
|
||||||
|
Seconds,
|
||||||
|
Milliseconds,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl Display for DurationUnit {
|
||||||
|
fn fmt(&self, f: &mut Formatter<'_>) -> std::fmt::Result {
|
||||||
|
let name = match self {
|
||||||
|
DurationUnit::Hours => "hours",
|
||||||
|
DurationUnit::Minutes => "minutes",
|
||||||
|
DurationUnit::Seconds => "seconds",
|
||||||
|
DurationUnit::Milliseconds => "milliseconds",
|
||||||
|
};
|
||||||
|
name.fmt(f)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
#[derive(Clone, Debug, PartialOrd, PartialEq)]
|
||||||
|
pub enum IsComparator {
|
||||||
|
Is,
|
||||||
|
IsNot,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl Display for IsComparator {
|
||||||
|
fn fmt(&self, f: &mut Formatter<'_>) -> std::fmt::Result {
|
||||||
|
let name = match self {
|
||||||
|
IsComparator::Is => "is",
|
||||||
|
IsComparator::IsNot => "is not",
|
||||||
|
};
|
||||||
|
name.fmt(f)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
#[derive(Clone, Debug, PartialOrd, PartialEq)]
|
||||||
|
pub enum CurrentlyOrPending {
|
||||||
|
CurrentlyIn,
|
||||||
|
PendingTo,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl Display for CurrentlyOrPending {
|
||||||
|
fn fmt(&self, f: &mut Formatter<'_>) -> std::fmt::Result {
|
||||||
|
let name = match self {
|
||||||
|
CurrentlyOrPending::CurrentlyIn => "currently in",
|
||||||
|
CurrentlyOrPending::PendingTo => "pending to",
|
||||||
|
};
|
||||||
|
name.fmt(f)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
#[derive(Clone, Debug, PartialOrd, PartialEq)]
|
||||||
|
pub enum WiderTallerEqual {
|
||||||
|
Wider,
|
||||||
|
Taller,
|
||||||
|
Equal,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl Display for WiderTallerEqual {
|
||||||
|
fn fmt(&self, f: &mut Formatter<'_>) -> std::fmt::Result {
|
||||||
|
let name = match self {
|
||||||
|
WiderTallerEqual::Wider => "wider than",
|
||||||
|
WiderTallerEqual::Taller => "taller than",
|
||||||
|
WiderTallerEqual::Equal => "is",
|
||||||
|
};
|
||||||
|
name.fmt(f)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
#[derive(Clone, Debug, PartialOrd, PartialEq)]
|
||||||
|
pub enum PixelUnit {
|
||||||
|
Pixels,
|
||||||
|
Kilopixels,
|
||||||
|
Megapixels,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl Display for PixelUnit {
|
||||||
|
fn fmt(&self, f: &mut Formatter<'_>) -> std::fmt::Result {
|
||||||
|
let name = match self {
|
||||||
|
PixelUnit::Pixels => "pixels",
|
||||||
|
PixelUnit::Kilopixels => "kilopixels",
|
||||||
|
PixelUnit::Megapixels => "megapixels",
|
||||||
|
};
|
||||||
|
name.fmt(f)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
#[derive(Clone, Debug, PartialOrd, PartialEq)]
|
||||||
|
pub enum ViewType {
|
||||||
|
Media,
|
||||||
|
Preview,
|
||||||
|
All,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl Display for ViewType {
|
||||||
|
fn fmt(&self, f: &mut Formatter<'_>) -> std::fmt::Result {
|
||||||
|
let name = match self {
|
||||||
|
ViewType::Media => "media",
|
||||||
|
ViewType::Preview => "preview",
|
||||||
|
ViewType::All => "all",
|
||||||
|
};
|
||||||
|
name.fmt(f)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
#[derive(Clone, Debug, PartialOrd, PartialEq)]
|
||||||
|
pub enum FileRelationshipType {
|
||||||
|
Alternates,
|
||||||
|
FalsePositives,
|
||||||
|
Duplicates,
|
||||||
|
PotentialDuplicates,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl Display for FileRelationshipType {
|
||||||
|
fn fmt(&self, f: &mut Formatter<'_>) -> std::fmt::Result {
|
||||||
|
let name = match self {
|
||||||
|
FileRelationshipType::Alternates => "alternates",
|
||||||
|
FileRelationshipType::FalsePositives => "false positives",
|
||||||
|
FileRelationshipType::Duplicates => "duplicates",
|
||||||
|
FileRelationshipType::PotentialDuplicates => "potential duplicates",
|
||||||
|
};
|
||||||
|
name.fmt(f)
|
||||||
|
}
|
||||||
|
}
|
@ -0,0 +1,407 @@
|
|||||||
|
use super::super::common;
|
||||||
|
use chrono::{Duration, Local};
|
||||||
|
use hydrus_api::error::Result;
|
||||||
|
use hydrus_api::wrapper::builders::tag_builder::{
|
||||||
|
Comparator, CurrentlyOrPending, FileRelationshipType, FileSizeUnit, IsComparator, PixelUnit,
|
||||||
|
SystemTagBuilder, ViewType, WiderTallerEqual,
|
||||||
|
};
|
||||||
|
use hydrus_api::wrapper::service::ServiceName;
|
||||||
|
use hydrus_api::wrapper::tag::Tag;
|
||||||
|
|
||||||
|
async fn retrieve_single_tag(tag: Tag) -> Result<()> {
|
||||||
|
let hydrus = common::get_hydrus();
|
||||||
|
hydrus.search(vec![tag]).await?;
|
||||||
|
|
||||||
|
Ok(())
|
||||||
|
}
|
||||||
|
|
||||||
|
#[tokio::test]
|
||||||
|
async fn it_returns_everything() {
|
||||||
|
let tag = SystemTagBuilder::new().everything().build();
|
||||||
|
retrieve_single_tag(tag).await.unwrap();
|
||||||
|
}
|
||||||
|
|
||||||
|
#[tokio::test]
|
||||||
|
async fn it_returns_the_inbox() {
|
||||||
|
let tag = SystemTagBuilder::new().inbox().build();
|
||||||
|
retrieve_single_tag(tag).await.unwrap();
|
||||||
|
}
|
||||||
|
|
||||||
|
#[tokio::test]
|
||||||
|
async fn it_returns_archived_files() {
|
||||||
|
let tag = SystemTagBuilder::new().archive().build();
|
||||||
|
retrieve_single_tag(tag).await.unwrap();
|
||||||
|
}
|
||||||
|
|
||||||
|
#[tokio::test]
|
||||||
|
async fn it_returns_files_with_duration() {
|
||||||
|
let tag = SystemTagBuilder::new().has_duration().build();
|
||||||
|
retrieve_single_tag(tag).await.unwrap();
|
||||||
|
}
|
||||||
|
|
||||||
|
#[tokio::test]
|
||||||
|
async fn it_returns_files_without_duration() {
|
||||||
|
let tag = SystemTagBuilder::new().no_duration().build();
|
||||||
|
retrieve_single_tag(tag).await.unwrap();
|
||||||
|
}
|
||||||
|
|
||||||
|
#[tokio::test]
|
||||||
|
async fn it_returns_the_best_from_duplicates() {
|
||||||
|
let tag = SystemTagBuilder::new().best_duplicate_quality().build();
|
||||||
|
retrieve_single_tag(tag).await.unwrap();
|
||||||
|
}
|
||||||
|
|
||||||
|
#[tokio::test]
|
||||||
|
async fn it_returns_worse_duplicates() {
|
||||||
|
let tag = SystemTagBuilder::new().not_best_duplicate_quality().build();
|
||||||
|
retrieve_single_tag(tag).await.unwrap();
|
||||||
|
}
|
||||||
|
|
||||||
|
#[tokio::test]
|
||||||
|
async fn it_returns_files_with_audio() {
|
||||||
|
let tag = SystemTagBuilder::new().has_audio().build();
|
||||||
|
retrieve_single_tag(tag).await.unwrap();
|
||||||
|
}
|
||||||
|
|
||||||
|
#[tokio::test]
|
||||||
|
async fn it_returns_files_without_audio() {
|
||||||
|
let tag = SystemTagBuilder::new().no_audio().build();
|
||||||
|
retrieve_single_tag(tag).await.unwrap();
|
||||||
|
}
|
||||||
|
|
||||||
|
#[tokio::test]
|
||||||
|
async fn it_returns_files_with_tags() {
|
||||||
|
let tag = SystemTagBuilder::new().has_tags().build();
|
||||||
|
retrieve_single_tag(tag).await.unwrap();
|
||||||
|
}
|
||||||
|
|
||||||
|
#[tokio::test]
|
||||||
|
async fn it_returns_files_without_tags() {
|
||||||
|
let tag = SystemTagBuilder::new().no_tags().build();
|
||||||
|
retrieve_single_tag(tag).await.unwrap();
|
||||||
|
}
|
||||||
|
|
||||||
|
#[tokio::test]
|
||||||
|
async fn it_returns_untagged_files() {
|
||||||
|
let tag = SystemTagBuilder::new().untagged().build();
|
||||||
|
retrieve_single_tag(tag).await.unwrap();
|
||||||
|
}
|
||||||
|
|
||||||
|
#[tokio::test]
|
||||||
|
async fn it_returns_files_with_a_specific_number_of_tags() {
|
||||||
|
let tag = SystemTagBuilder::new()
|
||||||
|
.number_of_tags(Comparator::Greater, 12)
|
||||||
|
.build();
|
||||||
|
retrieve_single_tag(tag).await.unwrap();
|
||||||
|
}
|
||||||
|
|
||||||
|
#[tokio::test]
|
||||||
|
async fn it_returns_files_with_a_specific_height() {
|
||||||
|
let tag = SystemTagBuilder::new()
|
||||||
|
.height(Comparator::Approximate, 200)
|
||||||
|
.build();
|
||||||
|
retrieve_single_tag(tag).await.unwrap();
|
||||||
|
}
|
||||||
|
|
||||||
|
#[tokio::test]
|
||||||
|
async fn it_returns_files_with_a_specific_width() {
|
||||||
|
let tag = SystemTagBuilder::new()
|
||||||
|
.width(Comparator::Equal, 200)
|
||||||
|
.build();
|
||||||
|
retrieve_single_tag(tag).await.unwrap();
|
||||||
|
}
|
||||||
|
|
||||||
|
#[tokio::test]
|
||||||
|
async fn it_returns_files_with_a_specific_size_in_gigabytes() {
|
||||||
|
let tag = SystemTagBuilder::new()
|
||||||
|
.filesize(Comparator::Less, 200, FileSizeUnit::Gigabytes)
|
||||||
|
.build();
|
||||||
|
retrieve_single_tag(tag).await.unwrap();
|
||||||
|
}
|
||||||
|
|
||||||
|
#[tokio::test]
|
||||||
|
async fn it_returns_files_with_a_specific_size_in_megabytes() {
|
||||||
|
let tag = SystemTagBuilder::new()
|
||||||
|
.filesize(Comparator::Less, 200, FileSizeUnit::Megabytes)
|
||||||
|
.build();
|
||||||
|
retrieve_single_tag(tag).await.unwrap();
|
||||||
|
}
|
||||||
|
|
||||||
|
#[tokio::test]
|
||||||
|
async fn it_returns_files_with_a_specific_size_in_kilobytes() {
|
||||||
|
let tag = SystemTagBuilder::new()
|
||||||
|
.filesize(Comparator::Less, 200, FileSizeUnit::Kilobytes)
|
||||||
|
.build();
|
||||||
|
retrieve_single_tag(tag).await.unwrap();
|
||||||
|
}
|
||||||
|
|
||||||
|
#[tokio::test]
|
||||||
|
async fn it_returns_files_with_a_specific_size_in_bytes() {
|
||||||
|
let tag = SystemTagBuilder::new()
|
||||||
|
.filesize(Comparator::Less, 200, FileSizeUnit::Bytes)
|
||||||
|
.build();
|
||||||
|
retrieve_single_tag(tag).await.unwrap();
|
||||||
|
}
|
||||||
|
|
||||||
|
#[tokio::test]
|
||||||
|
async fn it_returns_files_that_are_similar_to_others() {
|
||||||
|
let tag = SystemTagBuilder::new()
|
||||||
|
.similar_to(
|
||||||
|
vec![String::from(
|
||||||
|
"0000000000000000000000000000000000000000000000000000000000000000",
|
||||||
|
)],
|
||||||
|
20,
|
||||||
|
)
|
||||||
|
.build();
|
||||||
|
retrieve_single_tag(tag).await.unwrap();
|
||||||
|
}
|
||||||
|
|
||||||
|
#[tokio::test]
|
||||||
|
async fn it_limits_results() {
|
||||||
|
let tag = SystemTagBuilder::new().limit(50).build();
|
||||||
|
retrieve_single_tag(tag).await.unwrap();
|
||||||
|
}
|
||||||
|
|
||||||
|
#[tokio::test]
|
||||||
|
async fn it_returns_files_with_a_specific_modification_date() {
|
||||||
|
let tag = SystemTagBuilder::new()
|
||||||
|
.date_modified(Comparator::Greater, Local::now())
|
||||||
|
.build();
|
||||||
|
retrieve_single_tag(tag).await.unwrap();
|
||||||
|
}
|
||||||
|
|
||||||
|
#[tokio::test]
|
||||||
|
async fn it_returns_files_with_a_specific_import_time() {
|
||||||
|
let tag = SystemTagBuilder::new()
|
||||||
|
.time_imported(Comparator::Less, Local::now())
|
||||||
|
.build();
|
||||||
|
retrieve_single_tag(tag).await.unwrap();
|
||||||
|
}
|
||||||
|
|
||||||
|
#[tokio::test]
|
||||||
|
async fn it_returns_files_of_a_service() {
|
||||||
|
let tag = SystemTagBuilder::new()
|
||||||
|
.file_service(
|
||||||
|
IsComparator::Is,
|
||||||
|
CurrentlyOrPending::CurrentlyIn,
|
||||||
|
ServiceName::my_files(),
|
||||||
|
)
|
||||||
|
.build();
|
||||||
|
retrieve_single_tag(tag).await.unwrap();
|
||||||
|
}
|
||||||
|
|
||||||
|
#[tokio::test]
|
||||||
|
async fn it_returns_files_that_are_not_of_a_service() {
|
||||||
|
let tag = SystemTagBuilder::new()
|
||||||
|
.file_service(
|
||||||
|
IsComparator::IsNot,
|
||||||
|
CurrentlyOrPending::CurrentlyIn,
|
||||||
|
ServiceName::my_files(),
|
||||||
|
)
|
||||||
|
.build();
|
||||||
|
retrieve_single_tag(tag).await.unwrap();
|
||||||
|
}
|
||||||
|
|
||||||
|
#[tokio::test]
|
||||||
|
async fn it_returns_files_pending_to_service() {
|
||||||
|
let tag = SystemTagBuilder::new()
|
||||||
|
.file_service(
|
||||||
|
IsComparator::Is,
|
||||||
|
CurrentlyOrPending::PendingTo,
|
||||||
|
ServiceName::my_files(),
|
||||||
|
)
|
||||||
|
.build();
|
||||||
|
retrieve_single_tag(tag).await.unwrap();
|
||||||
|
}
|
||||||
|
|
||||||
|
#[tokio::test]
|
||||||
|
async fn it_returns_files_not_pending_to_service() {
|
||||||
|
let tag = SystemTagBuilder::new()
|
||||||
|
.file_service(
|
||||||
|
IsComparator::IsNot,
|
||||||
|
CurrentlyOrPending::PendingTo,
|
||||||
|
ServiceName::my_files(),
|
||||||
|
)
|
||||||
|
.build();
|
||||||
|
retrieve_single_tag(tag).await.unwrap();
|
||||||
|
}
|
||||||
|
|
||||||
|
#[tokio::test]
|
||||||
|
async fn it_returns_files_with_a_specific_number_of_alternate_relationships() {
|
||||||
|
let tag = SystemTagBuilder::new()
|
||||||
|
.number_of_relationships(Comparator::Approximate, 3, FileRelationshipType::Alternates)
|
||||||
|
.build();
|
||||||
|
retrieve_single_tag(tag).await.unwrap();
|
||||||
|
}
|
||||||
|
|
||||||
|
#[tokio::test]
|
||||||
|
async fn it_returns_files_with_a_specific_number_of_duplicate_relationships() {
|
||||||
|
let tag = SystemTagBuilder::new()
|
||||||
|
.number_of_relationships(Comparator::Approximate, 3, FileRelationshipType::Duplicates)
|
||||||
|
.build();
|
||||||
|
retrieve_single_tag(tag).await.unwrap();
|
||||||
|
}
|
||||||
|
|
||||||
|
#[tokio::test]
|
||||||
|
async fn it_returns_files_with_a_specific_number_of_false_positive_relationships() {
|
||||||
|
let tag = SystemTagBuilder::new()
|
||||||
|
.number_of_relationships(
|
||||||
|
Comparator::Approximate,
|
||||||
|
3,
|
||||||
|
FileRelationshipType::FalsePositives,
|
||||||
|
)
|
||||||
|
.build();
|
||||||
|
retrieve_single_tag(tag).await.unwrap();
|
||||||
|
}
|
||||||
|
|
||||||
|
#[tokio::test]
|
||||||
|
async fn it_returns_files_with_a_specific_number_of_potential_duplicate_relationships() {
|
||||||
|
let tag = SystemTagBuilder::new()
|
||||||
|
.number_of_relationships(
|
||||||
|
Comparator::Approximate,
|
||||||
|
3,
|
||||||
|
FileRelationshipType::PotentialDuplicates,
|
||||||
|
)
|
||||||
|
.build();
|
||||||
|
retrieve_single_tag(tag).await.unwrap();
|
||||||
|
}
|
||||||
|
|
||||||
|
#[tokio::test]
|
||||||
|
async fn it_returns_files_wider_than_a_specific_ratio() {
|
||||||
|
let tag = SystemTagBuilder::new()
|
||||||
|
.ratio(WiderTallerEqual::Wider, (40, 50))
|
||||||
|
.build();
|
||||||
|
retrieve_single_tag(tag).await.unwrap();
|
||||||
|
}
|
||||||
|
|
||||||
|
#[tokio::test]
|
||||||
|
async fn it_returns_files_taller_than_a_specific_ratio() {
|
||||||
|
let tag = SystemTagBuilder::new()
|
||||||
|
.ratio(WiderTallerEqual::Taller, (40, 50))
|
||||||
|
.build();
|
||||||
|
retrieve_single_tag(tag).await.unwrap();
|
||||||
|
}
|
||||||
|
|
||||||
|
#[tokio::test]
|
||||||
|
async fn it_returns_files_taller_with_specific_ratio() {
|
||||||
|
let tag = SystemTagBuilder::new()
|
||||||
|
.ratio(WiderTallerEqual::Equal, (40, 50))
|
||||||
|
.build();
|
||||||
|
retrieve_single_tag(tag).await.unwrap();
|
||||||
|
}
|
||||||
|
|
||||||
|
#[tokio::test]
|
||||||
|
async fn it_returns_files_with_a_specific_number_of_megapixels() {
|
||||||
|
let tag = SystemTagBuilder::new()
|
||||||
|
.number_of_pixels(Comparator::Less, 50, PixelUnit::Megapixels)
|
||||||
|
.build();
|
||||||
|
retrieve_single_tag(tag).await.unwrap();
|
||||||
|
}
|
||||||
|
|
||||||
|
#[tokio::test]
|
||||||
|
async fn it_returns_files_with_a_specific_number_of_kilopixels() {
|
||||||
|
let tag = SystemTagBuilder::new()
|
||||||
|
.number_of_pixels(Comparator::Equal, 50, PixelUnit::Kilopixels)
|
||||||
|
.build();
|
||||||
|
retrieve_single_tag(tag).await.unwrap();
|
||||||
|
}
|
||||||
|
|
||||||
|
#[tokio::test]
|
||||||
|
async fn it_returns_files_with_a_specific_number_of_pixels() {
|
||||||
|
let tag = SystemTagBuilder::new()
|
||||||
|
.number_of_pixels(Comparator::Greater, 50, PixelUnit::Pixels)
|
||||||
|
.build();
|
||||||
|
retrieve_single_tag(tag).await.unwrap();
|
||||||
|
}
|
||||||
|
|
||||||
|
#[tokio::test]
|
||||||
|
async fn it_returns_files_with_a_specific_number_of_views() {
|
||||||
|
let tag = SystemTagBuilder::new()
|
||||||
|
.views(ViewType::All, Comparator::Less, 1000)
|
||||||
|
.build();
|
||||||
|
retrieve_single_tag(tag).await.unwrap();
|
||||||
|
}
|
||||||
|
|
||||||
|
#[tokio::test]
|
||||||
|
async fn it_returns_files_with_a_specific_number_of_preview_views() {
|
||||||
|
let tag = SystemTagBuilder::new()
|
||||||
|
.views(ViewType::Preview, Comparator::Equal, 1000)
|
||||||
|
.build();
|
||||||
|
retrieve_single_tag(tag).await.unwrap();
|
||||||
|
}
|
||||||
|
|
||||||
|
#[tokio::test]
|
||||||
|
async fn it_returns_files_with_a_specific_number_of_media_views() {
|
||||||
|
let tag = SystemTagBuilder::new()
|
||||||
|
.views(ViewType::Media, Comparator::Greater, 1000)
|
||||||
|
.build();
|
||||||
|
retrieve_single_tag(tag).await.unwrap();
|
||||||
|
}
|
||||||
|
|
||||||
|
#[tokio::test]
|
||||||
|
async fn it_returns_files_with_a_specific_preview_viewtime() {
|
||||||
|
let tag = SystemTagBuilder::new()
|
||||||
|
.viewtime(
|
||||||
|
ViewType::Preview,
|
||||||
|
Comparator::Greater,
|
||||||
|
Duration::minutes(10),
|
||||||
|
)
|
||||||
|
.build();
|
||||||
|
retrieve_single_tag(tag).await.unwrap();
|
||||||
|
}
|
||||||
|
|
||||||
|
#[tokio::test]
|
||||||
|
async fn it_returns_files_with_a_specific_media_viewtime() {
|
||||||
|
let tag = SystemTagBuilder::new()
|
||||||
|
.viewtime(ViewType::Media, Comparator::Equal, Duration::minutes(10))
|
||||||
|
.build();
|
||||||
|
retrieve_single_tag(tag).await.unwrap();
|
||||||
|
}
|
||||||
|
|
||||||
|
#[tokio::test]
|
||||||
|
async fn it_returns_files_with_a_specific_viewtime() {
|
||||||
|
let tag = SystemTagBuilder::new()
|
||||||
|
.viewtime(ViewType::All, Comparator::Less, Duration::hours(10))
|
||||||
|
.build();
|
||||||
|
retrieve_single_tag(tag).await.unwrap();
|
||||||
|
}
|
||||||
|
|
||||||
|
#[tokio::test]
|
||||||
|
async fn it_returns_files_with_urls_matching_a_regex() {
|
||||||
|
let tag = SystemTagBuilder::new()
|
||||||
|
.has_url_matching_regex(".*pixiv.net.*")
|
||||||
|
.build();
|
||||||
|
retrieve_single_tag(tag).await.unwrap();
|
||||||
|
}
|
||||||
|
|
||||||
|
#[tokio::test]
|
||||||
|
async fn it_returns_files_with_urls_not_matching_a_regex() {
|
||||||
|
let tag = SystemTagBuilder::new()
|
||||||
|
.does_not_have_url_matching_regex(".*pixiv.net.*")
|
||||||
|
.build();
|
||||||
|
retrieve_single_tag(tag).await.unwrap();
|
||||||
|
}
|
||||||
|
|
||||||
|
#[tokio::test]
|
||||||
|
async fn it_returns_files_with_urls_matching_a_class() {
|
||||||
|
let tag = SystemTagBuilder::new()
|
||||||
|
.has_url_with_class("pixiv file page")
|
||||||
|
.build();
|
||||||
|
retrieve_single_tag(tag).await.unwrap();
|
||||||
|
}
|
||||||
|
|
||||||
|
#[tokio::test]
|
||||||
|
async fn it_returns_files_with_urls_not_matching_a_class() {
|
||||||
|
let tag = SystemTagBuilder::new()
|
||||||
|
.does_not_have_url_with_class("pixiv file page")
|
||||||
|
.build();
|
||||||
|
retrieve_single_tag(tag).await.unwrap();
|
||||||
|
}
|
||||||
|
|
||||||
|
#[tokio::test]
|
||||||
|
async fn it_returns_files_with_namespace_properties() {
|
||||||
|
let tag = SystemTagBuilder::new()
|
||||||
|
.tag_namespace_as_number("page", Comparator::Approximate, 5)
|
||||||
|
.build();
|
||||||
|
retrieve_single_tag(tag).await.unwrap();
|
||||||
|
}
|
Loading…
Reference in New Issue