check CHANGELOG.md for a list of variables

This commit is contained in:
MedzikUser 2022-04-03 21:01:58 +02:00
parent b83847ff20
commit b1bfe52a4c
No known key found for this signature in database
GPG Key ID: A5FAC1E185C112DB
19 changed files with 274 additions and 186 deletions

View File

@ -8,6 +8,19 @@ and this project adheres to [Semantic Versioning](http://semver.org/).
<!-- next-header --> <!-- next-header -->
## [Unreleased] ## [Unreleased]
### CLI
- completions: changed type from String to Shell
- removed `&` from `cli.commands` (line 54 in [parse.rs](./src/cli/parse.rs))
### Library
- removed `.map_err(anyhow::Error::new)` when function returns error
### Added
- commands in the code
- api functions to `impl` in `ImgurClient`
### Breaking Changes
- lib: moved everything to the main package with api submodules (before `imgurs::api::ImgurClient`, after `imgurs::api::ImgurClient`)
## [0.6.0] - 2022-03-14 ## [0.6.0] - 2022-03-14
### CLI ### CLI

63
src/api/client.rs Normal file
View File

@ -0,0 +1,63 @@
macro_rules! api_url (
($path: expr) => (
format!("{}{}", "https://api.imgur.com/3/", $path)
);
);
use std::{fmt, fs, io, path::Path};
use anyhow::Error;
pub(crate) use api_url;
use reqwest::Client;
use super::*;
pub struct ImgurClient {
pub client_id: String,
pub client: Client,
}
impl fmt::Debug for ImgurClient {
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
write!(f, "ImgurClient - client_id: {}", self.client_id)
}
}
impl ImgurClient {
pub fn new(client_id: String) -> Self {
let client = Client::new();
ImgurClient { client_id, client }
}
pub async fn upload_image(&self, path: String) -> Result<ImageInfo, Error> {
let mut image: String = path.clone();
// check if the specified file exists if not then check if it is a url
if Path::new(&path).exists() {
image = fs::read_to_string(&path)
.map_err(|err| err.to_string())
.expect("read file");
} else if !validator::validate_url(&path) {
let err = io::Error::new(
io::ErrorKind::Other,
format!("{path} is not url or file path"),
);
Err(anyhow::Error::from(err))?
}
upload_image(self, image).await
}
pub async fn delete_image(&self, delete_hash: String) -> Result<(), Error> {
delete_image(self, delete_hash).await
}
pub async fn rate_limit(&self) -> Result<RateLimitInfo, Error> {
rate_limit(self).await
}
pub async fn image_info(&self, id: String) -> Result<ImageInfo, Error> {
get_image(self, id).await
}
}

View File

@ -1,28 +0,0 @@
use reqwest::Client;
use std::fmt;
macro_rules! api_url (
($path: expr) => (
format!("{}{}", "https://api.imgur.com/3/", $path)
);
);
pub(crate) use api_url;
pub struct ImgurClient {
pub client_id: String,
pub client: Client,
}
impl fmt::Debug for ImgurClient {
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
write!(f, "ImgurClient - client_id: {}", self.client_id)
}
}
impl ImgurClient {
pub fn new(client_id: String) -> Self {
let client = Client::new();
ImgurClient { client_id, client }
}
}

View File

@ -1,29 +1,35 @@
use super::send_api_request; use std::io;
use crate::api::configuration::{api_url, ImgurClient};
use anyhow::Error;
use reqwest::Method; use reqwest::Method;
use std::io::{Error, ErrorKind};
pub async fn delete_image(c: ImgurClient, delete_hash: String) -> Result<String, anyhow::Error> { use super::{client::api_url, send_api_request, ImgurClient};
pub async fn delete_image(client: &ImgurClient, delete_hash: String) -> Result<(), Error> {
// get imgur api url
let uri = api_url!(format!("image/{delete_hash}")); let uri = api_url!(format!("image/{delete_hash}"));
let res = send_api_request(&c, Method::DELETE, uri, None).await?;
// send request to imgur api
let res = send_api_request(client, Method::DELETE, uri, None).await?;
// get response http code
let status = res.status(); let status = res.status();
// check if an error has occurred
if status.is_client_error() || status.is_server_error() { if status.is_client_error() || status.is_server_error() {
let mut body = res.text().await.map_err(anyhow::Error::new)?; let mut body = res.text().await?;
if body.chars().count() > 30 { if body.chars().count() > 30 {
body = "body is too length".to_string() body = "body is too length".to_string()
} }
let err = Error::new( let err = io::Error::new(
ErrorKind::Other, io::ErrorKind::Other,
format!("server returned non-successful status code = {status}, body = {body}"), format!("server returned non-successful status code = {status}, body = {body}"),
); );
Err(anyhow::Error::from(err)) Err(err)?
} else {
Ok("If the delete hash was correct the image was deleted!".to_string())
} }
Ok(())
} }

View File

@ -1,25 +1,30 @@
use super::send_api_request; use std::io;
use crate::api::configuration::{api_url, ImgurClient};
use crate::api::ImageInfo;
use anyhow::Error;
use reqwest::Method; use reqwest::Method;
use std::io::{Error, ErrorKind};
pub async fn get_image(c: ImgurClient, image: &str) -> Result<ImageInfo, anyhow::Error> { use super::{client::api_url, send_api_request, ImageInfo, ImgurClient};
pub async fn get_image(client: &ImgurClient, image: String) -> Result<ImageInfo, Error> {
// get imgur api url
let uri = api_url!(format!("image/{image}")); let uri = api_url!(format!("image/{image}"));
let res = send_api_request(&c, Method::GET, uri, None).await?;
// send request to imgur api
let res = send_api_request(client, Method::GET, uri, None).await?;
// get response http code
let status = res.status(); let status = res.status();
// check if an error has occurred
if status.is_client_error() || status.is_server_error() { if status.is_client_error() || status.is_server_error() {
let err = Error::new( let err = io::Error::new(
ErrorKind::Other, io::ErrorKind::Other,
format!("server returned non-successful status code = {status}"), format!("server returned non-successful status code = {status}"),
); );
Err(anyhow::Error::from(err)) Err(err)?
} else { } else {
let content: ImageInfo = res.json().await.map_err(anyhow::Error::new)?; let content: ImageInfo = res.json().await?;
Ok(content) Ok(content)
} }
} }

View File

@ -1,13 +1,13 @@
use serde_derive::{Deserialize, Serialize}; use serde_derive::{Deserialize, Serialize};
#[derive(Debug, Deserialize, Serialize, Clone)] #[derive(Debug, Serialize, Deserialize, Clone)]
pub struct ImageInfo { pub struct ImageInfo {
pub data: ImageInfoData, pub data: ImageInfoData,
pub success: bool, pub success: bool,
pub status: i32, pub status: i32,
} }
#[derive(Debug, Deserialize, Serialize, Clone)] #[derive(Debug, Serialize, Deserialize, Clone)]
pub struct ImageInfoData { pub struct ImageInfoData {
pub id: String, pub id: String,
pub title: Option<String>, pub title: Option<String>,

View File

@ -1,41 +1,56 @@
mod delete_image;
mod get_image;
mod image_type; mod image_type;
mod rate_limit;
mod upload_image;
pub mod configuration; pub mod client;
pub mod delete_image;
pub mod get_image;
pub mod rate_limit;
pub mod upload_image;
pub use configuration::ImgurClient; pub use client::ImgurClient;
pub use delete_image::*;
pub use get_image::*;
pub use image_type::*; pub use image_type::*;
pub use rate_limit::*;
pub use upload_image::*;
use reqwest::Method;
use std::collections::HashMap; use std::collections::HashMap;
use reqwest::{Response, Method};
use anyhow::Error;
// send request to imgur api
pub async fn send_api_request( pub async fn send_api_request(
config: &ImgurClient, config: &ImgurClient,
method: Method, method: Method,
uri: String, uri: String,
form: Option<HashMap<&str, String>>, form: Option<HashMap<&str, String>>,
) -> Result<reqwest::Response, anyhow::Error> { ) -> Result<Response, Error> {
// get request client
let client = &config.client; let client = &config.client;
// create request buidler
let mut req = client.request(method, uri.as_str()); let mut req = client.request(method, uri.as_str());
const VERSION: Option<&str> = option_env!("CARGO_PKG_VERSION"); // get program version
let version: Option<&str> = option_env!("CARGO_PKG_VERSION");
let version = version.unwrap_or("unknown");
// add `Authorization` and `User-Agent` to request
req = req req = req
.header("Authorization", format!("Client-ID {}", config.client_id)) .header("Authorization", format!("Client-ID {}", config.client_id))
.header( .header(
"User-Agent", "User-Agent",
format!("Imgur/{:?}", VERSION.unwrap_or("unknown")), format!("Imgur/{:?}", version),
); );
// if exists add hashmap to request
if form != None { if form != None {
req = req.form(&form.unwrap()) req = req.form(&form.unwrap())
} }
// build request
let req = req.build()?; let req = req.build()?;
client.execute(req).await.map_err(anyhow::Error::from) // send request
Ok(client.execute(req).await?)
} }

View File

@ -1,9 +1,10 @@
use super::send_api_request; use std::io;
use crate::api::configuration::{api_url, ImgurClient};
use anyhow::Error;
use reqwest::Method; use reqwest::Method;
use serde_derive::{Deserialize, Serialize}; use serde::{Deserialize, Serialize};
use std::io::{Error, ErrorKind};
use super::{client::api_url, send_api_request, ImgurClient};
#[derive(Debug, Serialize, Deserialize)] #[derive(Debug, Serialize, Deserialize)]
pub struct RateLimitInfo { pub struct RateLimitInfo {
@ -26,22 +27,28 @@ pub struct RateLimitData {
pub client_remaining: i32, pub client_remaining: i32,
} }
pub async fn rate_limit(c: ImgurClient) -> Result<RateLimitInfo, anyhow::Error> { pub async fn rate_limit(client: &ImgurClient) -> Result<RateLimitInfo, Error> {
// get imgur api url
let uri = api_url!("credits"); let uri = api_url!("credits");
let res = send_api_request(&c, Method::GET, uri, None).await?;
// send request to imgur api
let res = send_api_request(client, Method::GET, uri, None).await?;
// get response http code
let status = res.status(); let status = res.status();
// check if an error has occurred
if status.is_client_error() || status.is_server_error() { if status.is_client_error() || status.is_server_error() {
let body = res.text().await.map_err(anyhow::Error::new)?; let body = res.text().await?;
let err = Error::new(
ErrorKind::Other, let err = io::Error::new(
io::ErrorKind::Other,
format!("server returned non-successful status code = {status}, body = {body}"), format!("server returned non-successful status code = {status}, body = {body}"),
); );
Err(anyhow::Error::from(err)) Err(err)?
} else { } else {
let content: RateLimitInfo = res.json().await.map_err(anyhow::Error::new)?; let content = res.json::<RateLimitInfo>().await?;
Ok(content) Ok(content)
} }
} }

View File

@ -1,40 +1,41 @@
use super::send_api_request; use std::{collections::HashMap, io};
use crate::api::{
configuration::{api_url, ImgurClient},
ImageInfo,
};
use anyhow::Error;
use reqwest::Method; use reqwest::Method;
use std::{
collections::HashMap,
io::{Error, ErrorKind},
};
pub async fn upload_image(c: ImgurClient, image: &str) -> Result<ImageInfo, anyhow::Error> { use super::{client::api_url, send_api_request, ImageInfo, ImgurClient};
pub async fn upload_image(c: &ImgurClient, image: String) -> Result<ImageInfo, Error> {
// create http form (hashmap)
let mut form = HashMap::new(); let mut form = HashMap::new();
// insert image to form
form.insert("image", image);
form.insert("image", image.to_string()); // get imgur api url
let uri = api_url!("image"); let uri = api_url!("image");
// send request to imgur api
let res = send_api_request(&c, Method::POST, uri, Some(form)).await?; let res = send_api_request(&c, Method::POST, uri, Some(form)).await?;
// get response http code
let status = res.status(); let status = res.status();
// check if an error has occurred
if status.is_client_error() || status.is_server_error() { if status.is_client_error() || status.is_server_error() {
let mut body = res.text().await.map_err(anyhow::Error::new)?; let mut body = res.text().await?;
if body.chars().count() > 30 { if body.chars().count() > 200 {
body = "body is too length".to_string() body = "server returned too long".to_string()
} }
let err = Error::new( let err = io::Error::new(
ErrorKind::Other, io::ErrorKind::Other,
format!("server returned non-successful status code = {status}, body = {body}"), format!("server returned non-successful status code = {status}, body = {body}"),
); );
Err(anyhow::Error::from(err)) Err(err)?
} else { } else {
let content: ImageInfo = res.json().await.map_err(anyhow::Error::new)?; let content: ImageInfo = res.json().await?;
Ok(content) Ok(content)
} }
} }

View File

@ -2,25 +2,20 @@
unix, unix,
not(any(target_os = "macos", target_os = "android", target_os = "emscripten")) not(any(target_os = "macos", target_os = "android", target_os = "emscripten"))
))] ))]
fn is_program_in_path(program: &str) -> bool { // use xclip (or a similar program that is installed) because the kernel deletes the clipboard after the process ends
use std::{env, fs}; pub fn set_clipboard(content: String) {
fn is_program_in_path(program: &str) -> bool {
if let Ok(path) = env::var("PATH") { if let Ok(path) = std::env::var("PATH") {
for p in path.split(':') { for p in path.split(':') {
let p_str = format!("{}/{}", p, program); let p_str = format!("{}/{}", p, program);
if fs::metadata(p_str).is_ok() { if std::fs::metadata(p_str).is_ok() {
return true; return true;
}
} }
} }
false
} }
false
}
#[cfg(all(
unix,
not(any(target_os = "macos", target_os = "android", target_os = "emscripten"))
))]
pub fn set_clipboard(content: String) {
use std::{ use std::{
io::Write, io::Write,
process::{Command, Stdio}, process::{Command, Stdio},
@ -38,6 +33,7 @@ pub fn set_clipboard(content: String) {
.stdin(Stdio::piped()) .stdin(Stdio::piped())
.spawn() .spawn()
.expect("execute command xsel") .expect("execute command xsel")
// xclip // xclip
} else if is_program_in_path("xclip") { } else if is_program_in_path("xclip") {
child = Command::new("xclip") child = Command::new("xclip")
@ -47,41 +43,43 @@ pub fn set_clipboard(content: String) {
.stdin(Stdio::piped()) .stdin(Stdio::piped())
.spawn() .spawn()
.expect("execute command xclip") .expect("execute command xclip")
// termux // termux
} else if is_program_in_path("termux-clipboard-set") { } else if is_program_in_path("termux-clipboard-set") {
child = Command::new("termux-clipboard-set") child = Command::new("termux-clipboard-set")
.stdin(Stdio::piped()) .stdin(Stdio::piped())
.spawn() .spawn()
.expect("execute command termux-clipboard-set") .expect("execute command termux-clipboard-set")
// the above programs responsible for the clipboard were not found
} else { } else {
println!( println!(
"{} {}", "{} {}",
"WARN".yellow(), "WARN".yellow(),
"command for clipboard not found".magenta() "command for clipboard not found".magenta()
); );
return;
return
} }
// copy the content (send it to stdin command)
child child
.stdin .stdin
.as_mut() .as_mut()
.unwrap() .unwrap()
.write_all(content.as_bytes()) .write_all(content.as_bytes())
.expect("execute command"); .expect("execute command");
child.wait_with_output().unwrap();
}
#[cfg(not(all( child
unix, .wait_with_output()
not(any(target_os = "macos", target_os = "android", target_os = "emscripten")) .expect("wait for clipboard command output");
)))] }
use arboard::Clipboard;
#[cfg(not(all( #[cfg(not(all(
unix, unix,
not(any(target_os = "macos", target_os = "android", target_os = "emscripten")) not(any(target_os = "macos", target_os = "android", target_os = "emscripten"))
)))] )))]
pub fn set_clipboard(content: String) { pub fn set_clipboard(content: String) {
let mut clipboard = Clipboard::new().unwrap(); let mut clipboard = arboard::Clipboard::new().unwrap();
clipboard.set_text(content).unwrap(); clipboard.set_text(content).execute(format!("set clipboard to '{content}'"));
} }

View File

@ -1,11 +1,16 @@
use chrono::{prelude::DateTime, Utc}; use chrono::{prelude::DateTime, Utc};
use colored::Colorize; use colored::Colorize;
use imgurs::api::{rate_limit::rate_limit, ImgurClient}; use imgurs::ImgurClient;
use std::time::{Duration, UNIX_EPOCH}; use std::time::{Duration, UNIX_EPOCH};
pub async fn credits(client: ImgurClient) { pub async fn credits(client: ImgurClient) {
let i = rate_limit(client).await.expect("send api request"); // get client ratelimit from imgur api
let i = client
.rate_limit()
.await
.expect("send request to imgur api");
// format image upload date
let date = UNIX_EPOCH + Duration::from_secs(i.data.user_reset.try_into().unwrap()); let date = UNIX_EPOCH + Duration::from_secs(i.data.user_reset.try_into().unwrap());
let datetime = DateTime::<Utc>::from(date); let datetime = DateTime::<Utc>::from(date);
let timestamp_str = datetime.format("%Y-%m-%d %H:%M:%S").to_string(); let timestamp_str = datetime.format("%Y-%m-%d %H:%M:%S").to_string();

View File

@ -1,11 +1,15 @@
use colored::Colorize; use colored::Colorize;
use imgurs::ImgurClient;
use imgurs::api::{delete_image::delete_image as del_img, ImgurClient};
pub async fn delete_image(client: ImgurClient, delete_hash: String) { pub async fn delete_image(client: ImgurClient, delete_hash: String) {
let i = del_img(client, delete_hash) // delete image from imgur
client
.delete_image(delete_hash)
.await .await
.expect("send api request"); .expect("send api request");
println!("{}", i.magenta()); println!(
"{}",
"If Delete Hash was correct the image was deleted!".magenta()
);
} }

View File

@ -1,8 +1,14 @@
use imgurs::api::{get_image::get_image, ImgurClient}; use imgurs::ImgurClient;
use super::print_image_info; use super::print_image_info;
pub async fn image_info(client: ImgurClient, id: &str) { pub async fn image_info(client: ImgurClient, id: String) {
let info = get_image(client, id).await.expect("send api request"); // get a image info from imgur
let info = client
.image_info(id)
.await
.expect("send request to imfur api");
// print image information from imgur
print_image_info(info); print_image_info(info);
} }

View File

@ -8,14 +8,17 @@ pub mod webhook;
use chrono::{prelude::DateTime, Utc}; use chrono::{prelude::DateTime, Utc};
use colored::Colorize; use colored::Colorize;
use imgurs::api::ImageInfo; use imgurs::ImageInfo;
use std::time::{Duration, UNIX_EPOCH}; use std::time::{Duration, UNIX_EPOCH};
// print image information from imgur
pub fn print_image_info(i: ImageInfo) { pub fn print_image_info(i: ImageInfo) {
// format image upload date
let d = UNIX_EPOCH + Duration::from_secs(i.data.datetime.try_into().unwrap()); let d = UNIX_EPOCH + Duration::from_secs(i.data.datetime.try_into().unwrap());
let datetime = DateTime::<Utc>::from(d); let datetime = DateTime::<Utc>::from(d);
let timestamp_str = datetime.format("%Y-%m-%d %H:%M:%S").to_string(); let timestamp_str = datetime.format("%Y-%m-%d %H:%M:%S").to_string();
// image title
if i.data.title != None { if i.data.title != None {
println!( println!(
"{} {}", "{} {}",
@ -26,6 +29,8 @@ pub fn print_image_info(i: ImageInfo) {
.magenta() .magenta()
); );
} }
// image description
if i.data.description != None { if i.data.description != None {
println!( println!(
"{} {}", "{} {}",
@ -36,6 +41,8 @@ pub fn print_image_info(i: ImageInfo) {
.magenta() .magenta()
); );
} }
// image deletehas
if i.data.deletehash != None { if i.data.deletehash != None {
println!( println!(
"{} {}", "{} {}",

View File

@ -1,10 +1,11 @@
use clap::{Command, IntoApp, Parser, Subcommand}; use clap::{Command, IntoApp, Parser, Subcommand};
use clap_complete::{generate, Generator, Shell}; use clap_complete::{generate, Generator, Shell};
use imgurs::api::ImgurClient; use imgurs::ImgurClient;
use std::io::{self, stdout}; use std::io::{self, stdout};
use crate::cli::{credits::*, delete_image::*, info_image::*, upload_image::*}; use crate::cli::{credits::*, delete_image::*, info_image::*, upload_image::*};
// get program name and varsion from Cargo.toml
const VERSION: Option<&str> = option_env!("CARGO_PKG_VERSION"); const VERSION: Option<&str> = option_env!("CARGO_PKG_VERSION");
const NAME: Option<&str> = option_env!("CARGO_PKG_NAME"); const NAME: Option<&str> = option_env!("CARGO_PKG_NAME");
@ -21,7 +22,7 @@ struct Cli {
#[derive(Subcommand, Debug)] #[derive(Subcommand, Debug)]
enum Commands { enum Commands {
#[clap(about = "Print API Rate Limit", display_order = 1)] #[clap(about = "Print Client Rate Limit", display_order = 1)]
Credits, Credits,
#[clap(about = "Upload image to Imgur", display_order = 2)] #[clap(about = "Upload image to Imgur", display_order = 2)]
@ -37,7 +38,7 @@ enum Commands {
about = "Generate completion file for a shell [bash, elvish, fish, powershell, zsh]", about = "Generate completion file for a shell [bash, elvish, fish, powershell, zsh]",
display_order = 5 display_order = 5
)] )]
Completions { shell: String }, Completions { shell: Shell },
#[clap(about = "Generate man page", display_order = 6)] #[clap(about = "Generate man page", display_order = 6)]
Manpage, Manpage,
@ -50,41 +51,26 @@ fn print_completions<G: Generator>(gen: G, app: &mut Command) {
pub async fn parse(client: ImgurClient) { pub async fn parse(client: ImgurClient) {
let args = Cli::parse(); let args = Cli::parse();
match &args.command { match args.command {
Commands::Credits => { Commands::Credits => credits(client).await,
credits(client).await;
}
Commands::Upload { path } => { Commands::Upload { path } => upload_image(client, path.to_string()).await,
upload_image(client, path).await;
}
Commands::Delete { delete_hash } => { Commands::Delete { delete_hash } => delete_image(client, delete_hash.to_string()).await,
delete_image(client, delete_hash.to_string()).await;
}
Commands::Info { id } => { Commands::Info { id } => image_info(client, id.to_string()).await,
image_info(client, id).await;
}
Commands::Completions { shell } => { Commands::Completions { shell } => {
let mut app = Cli::command(); let mut app = Cli::command();
match shell.as_str() { print_completions(shell, &mut app)
"bash" => print_completions(Shell::Bash, &mut app),
"elvish" => print_completions(Shell::Elvish, &mut app),
"fish" => print_completions(Shell::Fish, &mut app),
"powershell" => print_completions(Shell::PowerShell, &mut app),
"zsh" => print_completions(Shell::Zsh, &mut app),
_ => panic!("Completions to shell `{shell}`, not found!"),
}
} }
Commands::Manpage => { Commands::Manpage => {
let clap_app = Cli::command(); let clap_app = Cli::command();
let man = clap_mangen::Man::new(clap_app); let man = clap_mangen::Man::new(clap_app);
man.render(&mut io::stdout()).unwrap();
man.render(&mut io::stdout()).expect("generate manpage")
} }
} }
} }

View File

@ -1,14 +1,12 @@
use super::clipboard::set_clipboard; use super::clipboard::set_clipboard;
use imgurs::api::{upload_image::upload_image as upload_img, ImgurClient}; use imgurs::ImgurClient;
use notify_rust::Notification; use notify_rust::Notification;
use crate::{cli::webhook::send_discord_webhook, config::toml}; use crate::{cli::webhook::send_discord_webhook, config::toml};
use super::print_image_info; use super::print_image_info;
use base64::encode as base64_encode; // show notification
use std::{fs::read as fs_read, path::Path};
macro_rules! notify ( macro_rules! notify (
($notification: expr) => ( ($notification: expr) => (
if toml::parse().notification.enabled { if toml::parse().notification.enabled {
@ -17,43 +15,39 @@ macro_rules! notify (
); );
); );
pub async fn upload_image(client: ImgurClient, path: &str) { pub async fn upload_image(client: ImgurClient, path: String) {
let mut image: String = path.to_string(); // parse configuration file
let config = toml::parse(); let config = toml::parse();
if Path::new(path).exists() { // upload a image to imgur
let bytes = fs_read(path) let mut i = client.upload_image(path).await.unwrap_or_else(|err| {
.map_err(|err| err.to_string())
.expect("read file");
image = base64_encode(bytes);
} else if !validator::validate_url(path) {
panic!("{path} is not a url")
}
let mut i = upload_img(client, &image).await.unwrap_or_else(|err| {
notify!(Notification::new() notify!(Notification::new()
.summary("Error!") .summary("Error!")
.body(&format!("Error: {}", &err.to_string())) .body(&format!("Error: {}", &err.to_string()))
.appname("Imgurs")); // I don't think you can set it to error .appname("Imgurs")); // I don't think you can set it to error
panic!("{}", err) panic!("send request to imagur api: {}", err)
}); });
// change domain to proxy (to be set in config)
if config.imgur.image_cdn != "i.imgur.com" { if config.imgur.image_cdn != "i.imgur.com" {
i.data.link = i.data.link.replace("i.imgur.com", "cdn.magicuser.cf") i.data.link = i.data.link.replace("i.imgur.com", &config.imgur.image_cdn)
} }
// print image information from imgur
print_image_info(i.clone()); print_image_info(i.clone());
let body = format!("Uploaded {}", i.data.link); // send notification that the image has been uploaded
notify!(Notification::new()
notify!(Notification::new().summary("Imgurs").body(&body)); .summary("Imgurs")
.body(&format!("Uploaded {}", i.data.link)));
// if enabled copy link to clipboard
if config.clipboard.enabled { if config.clipboard.enabled {
set_clipboard(i.data.link.clone()) set_clipboard(i.data.link.clone())
} }
// if enabled send embed with link and deletehash to discord (something like logger)
if config.discord_webhook.enabled { if config.discord_webhook.enabled {
send_discord_webhook(i.data.link, i.data.deletehash.unwrap()) send_discord_webhook(i.data.link, i.data.deletehash.unwrap())
.await .await

View File

@ -3,13 +3,21 @@ use std::error::Error;
use crate::config::toml; use crate::config::toml;
// send embed with link and deletehash to discord (something like logger)
pub async fn send_discord_webhook( pub async fn send_discord_webhook(
link: String, link: String,
deletehash: String, deletehash: String,
) -> Result<bool, Box<dyn Error + Send + Sync>> { ) -> Result<(), Box<dyn Error + Send + Sync>> {
// get discord webhook uri from config
let url = toml::parse().discord_webhook.uri; let url = toml::parse().discord_webhook.uri;
// create WebhookClient
let client: WebhookClient = WebhookClient::new(&url); let client: WebhookClient = WebhookClient::new(&url);
// get program version
let version = option_env!("CARGO_PKG_VERSION").unwrap_or("unknown");
// send discord webhook
client client
.send(|message| { .send(|message| {
message.username("Imgurs").embed(|embed| { message.username("Imgurs").embed(|embed| {
@ -17,14 +25,10 @@ pub async fn send_discord_webhook(
.title(&link) .title(&link)
.description(&format!("Delete Hash ||{deletehash}||")) .description(&format!("Delete Hash ||{deletehash}||"))
.image(&link) .image(&link)
.footer( .footer(&format!("Imgurs v{version}"), None)
&format!(
"Imgurs v{}",
option_env!("CARGO_PKG_VERSION").unwrap_or("unknown")
),
None,
)
}) })
}) })
.await .await?;
Ok(())
} }

View File

@ -1 +1,3 @@
pub mod api; mod api;
pub use api::*;

View File

@ -2,7 +2,7 @@ mod cli;
mod config; mod config;
use cli::parse::parse; use cli::parse::parse;
use imgurs::api::ImgurClient; use imgurs::ImgurClient;
use simple_logger::SimpleLogger; use simple_logger::SimpleLogger;