Compare commits

...

5 Commits

912
Cargo.lock generated

File diff suppressed because it is too large Load Diff

@ -1,6 +1,6 @@
[package]
name = "hydrus-utils"
version = "0.4.2"
version = "0.5.1"
edition = "2021"
license = "Apache-2.0"
description = "Automatically tag hydrus file by using pixiv and saucenao"
@ -12,22 +12,22 @@ repository = "https://github.com/Trivernis/hydrus-pixiv-tagger"
[dependencies]
pixiv-rs = "0.1.0"
hydrus-api = { version = "0.9.3", default-features = false, features = ["cbor"] }
hydrus-api = { version = "0.9.3", default-features = false, features = ["json"] }
rustnao = "0.2.1"
tempdir = "0.3.7"
thiserror = "1.0.32"
tracing-subscriber = { version = "0.3.15", features = ["env-filter"] }
tracing = "0.1.36"
clap = { version = "3.2.17", features = ["derive", "env"] }
serde = { version = "1.0.143", features = ["derive"] }
reqwest = { version = "0.11.11", features = ["json"] }
serde_json = "1.0.83"
config = "0.13.2"
thiserror = "1.0.38"
tracing-subscriber = { version = "0.3.16", features = ["env-filter"] }
tracing = "0.1.37"
clap = { version = "4.1.6", features = ["derive", "env"] }
serde = { version = "1.0.152", features = ["derive"] }
reqwest = { version = "0.11.14", features = ["json"] }
serde_json = "1.0.93"
config = "0.13.3"
directories = "4.0.1"
color-eyre = "0.6.2"
egg-mode = "0.16.0"
lazy-regex = "2.3.0"
egg-mode = "0.16.1"
lazy-regex = "2.4.1"
[dependencies.tokio]
version = "1.20.1"
version = "1.25.0"
features = ["macros", "rt", "time", "fs"]

@ -23,10 +23,6 @@ pub enum Command {
#[clap(name = "import-reddit-posts")]
ImportRedditPosts(ImportUrlsOptions),
/// Looks up and imports tweets
#[clap(name = "import-tweets")]
ImportTweets(ImportUrlsOptions),
/// Looks up a list of urls and imports media found for them
#[clap(name = "import-urls")]
ImportUrls(ImportUrlsOptions),

@ -55,10 +55,4 @@ impl Config {
self.saucenao
.expect("No saucenao key configured. Please add one to the config file.")
}
/// REturns the twitter api configuration or panics if nothing is configured
pub fn into_twitter_cfg(self) -> TwitterConfig {
self.twitter
.expect("No twitter api credentials configured. Please add them to the config file.")
}
}

@ -6,7 +6,6 @@ pub mod utils;
use crate::config::Config;
use crate::config::SauceNaoConfig;
use crate::config::TwitterConfig;
use crate::error::Result;
use crate::operations::find_and_send_tags::find_and_send_tags;
use crate::operations::find_and_send_urls::find_and_send_urls;
@ -16,7 +15,6 @@ use hydrus_api::wrapper::service::ServiceName;
use hydrus_api::wrapper::tag::Tag;
use hydrus_api::{Client, Hydrus};
use operations::find_and_send_reddit_posts::find_and_send_reddit_posts;
use operations::find_and_send_twitter_posts::find_and_send_twitter_posts;
use pixiv_rs::PixivClient;
use rustnao::{Handler, HandlerBuilder};
use std::str::FromStr;
@ -46,8 +44,7 @@ async fn main() {
send_tags_or_urls(opt, config.into_saucenao(), hydrus, false).await
}
Command::ImportRedditPosts(opt) => import_reddit_posts(opt, hydrus).await,
Command::ImportTweets(opt) => import_tweets(opt, config.into_twitter_cfg(), hydrus).await,
Command::ImportUrls(opt) => import_urls(opt, config, hydrus).await,
Command::ImportUrls(opt) => import_urls(opt, hydrus).await,
}
.expect("Failed to send tags or urls");
}
@ -124,26 +121,14 @@ async fn import_reddit_posts(opt: ImportUrlsOptions, hydrus: Hydrus) -> Result<(
find_and_send_reddit_posts(&hydrus, urls).await
}
#[tracing::instrument(level = "debug", skip(hydrus))]
async fn import_tweets(
opt: ImportUrlsOptions,
twitter_cfg: TwitterConfig,
hydrus: Hydrus,
) -> Result<()> {
let urls = get_urls_from_args(opt).await?;
find_and_send_twitter_posts(&hydrus, twitter_cfg, urls).await
}
async fn import_urls(opt: ImportUrlsOptions, cfg: Config, hydrus: Hydrus) -> Result<()> {
async fn import_urls(opt: ImportUrlsOptions, hydrus: Hydrus) -> Result<()> {
let urls = get_urls_from_args(opt).await?;
let mut reddit_urls = Vec::new();
let mut twitter_urls = Vec::new();
let mut unknown_urls = Vec::new();
for url in urls {
match find_url_type(&url) {
UrlType::Reddit => reddit_urls.push(url),
UrlType::Twitter => twitter_urls.push(url),
UrlType::Other => {
tracing::warn!("Unknown url type {url}");
unknown_urls.push(url)
@ -153,9 +138,6 @@ async fn import_urls(opt: ImportUrlsOptions, cfg: Config, hydrus: Hydrus) -> Res
tracing::info!("Importing reddit posts...");
find_and_send_reddit_posts(&hydrus, reddit_urls).await?;
tracing::info!("Importing twitter posts...");
find_and_send_twitter_posts(&hydrus, cfg.into_twitter_cfg(), twitter_urls).await?;
tracing::info!("Importing unknown urls...");
for url in unknown_urls {

@ -1,42 +0,0 @@
use egg_mode::Token;
use hydrus_api::Hydrus;
use crate::config::TwitterConfig;
use crate::error::Result;
use crate::utils::twitter::{get_token, get_tweet_media};
#[tracing::instrument(level = "debug", skip(hydrus))]
pub async fn find_and_send_twitter_posts(
hydrus: &Hydrus,
twitter_cfg: TwitterConfig,
post_urls: Vec<String>,
) -> Result<()> {
let token = get_token(twitter_cfg).await?;
let total_posts = post_urls.len();
for (index, post) in post_urls.into_iter().enumerate() {
tracing::info!("Importing post {} of {}", index + 1, total_posts);
if let Err(e) = import_post(&post, hydrus, &token).await {
tracing::error!("Failed to import {}: {}", post, e);
}
}
Ok(())
}
#[tracing::instrument(level = "debug", skip(hydrus))]
async fn import_post(post_url: &str, hydrus: &Hydrus, token: &Token) -> Result<()> {
tracing::debug!("Tweet {}", post_url);
let images = get_tweet_media(post_url, token).await?;
tracing::info!("Found {} images for tweet {}", images.len(), post_url);
for url in images {
let mut entry = hydrus.import().url(url).run().await?;
let files = entry.files().await?;
for mut file in files {
file.associate_urls(vec![post_url.to_string()]).await?;
}
}
Ok(())
}

@ -1,4 +1,3 @@
pub mod find_and_send_reddit_posts;
pub mod find_and_send_tags;
pub mod find_and_send_twitter_posts;
pub mod find_and_send_urls;

@ -1,6 +1,5 @@
pub mod pixiv;
pub mod reddit;
pub mod twitter;
pub mod urls;
use crate::error::Result;
use directories::ProjectDirs;

@ -1,60 +0,0 @@
use std::borrow::Cow;
use crate::{config::TwitterConfig, error::Result};
use egg_mode::auth::Token;
/// Returns the token that
/// can be used for twitter api requests
#[tracing::instrument(level = "debug")]
pub async fn get_token(config: TwitterConfig) -> Result<Token> {
let con_token = egg_mode::KeyPair::new(
Cow::from(config.consumer_key),
Cow::from(config.consumer_secret),
);
let token = egg_mode::auth::bearer_token(&con_token).await?;
Ok(token)
}
/// Returns the media urls for a given tweet
#[tracing::instrument(level = "debug", skip(token))]
pub async fn get_tweet_media(url: &str, token: &Token) -> Result<Vec<String>> {
let id = get_tweet_id(url)?;
let tweet = egg_mode::tweet::show(id, token).await?.response;
if let Some(entities) = tweet.extended_entities {
let media = entities.media;
let urls: Vec<String> = media
.into_iter()
.map(|m| {
if let Some(video_info) = m.video_info {
video_info.variants.into_iter().next().unwrap().url
} else {
m.media_url_https
}
})
.collect();
Ok(urls)
} else {
Ok(Vec::new())
}
}
/// Returns the tweet ID for a given twitter url
#[tracing::instrument(level = "debug")]
fn get_tweet_id(url: &str) -> Result<u64> {
let mut url = url;
if let Some((left, _right)) = url.split_once('?') {
url = left;
}
let id = url
.rsplit('/')
.filter(|s| !s.is_empty())
.next()
.ok_or("No Tweet ID in twitter url")?;
let id = id
.parse::<u64>()
.map_err(|_| "Tweet ID cannot be parsed as u64")?;
Ok(id)
}

@ -2,15 +2,12 @@ use lazy_regex::regex;
pub enum UrlType {
Reddit,
Twitter,
Other,
}
pub fn find_url_type(url: &str) -> UrlType {
if is_reddit_url(url) {
UrlType::Reddit
} else if is_twitter_url(url) {
UrlType::Twitter
} else {
UrlType::Other
}
@ -20,8 +17,3 @@ fn is_reddit_url(url: &str) -> bool {
let r = regex!(r#"^http(s)?://(www\.)?(reddit\.com|redd\.it|reddit\.app\.link).*$"#i);
r.is_match(url)
}
fn is_twitter_url(url: &str) -> bool {
let r = regex!(r#"^http(s)?://(www\.)?twitter\.com.*$"#);
r.is_match(url)
}

Loading…
Cancel
Save