mirror of https://github.com/MedzikUser/imgurs
Compare commits
80 Commits
Author | SHA1 | Date |
---|---|---|
M3DZIK | b6ef4241ca | |
M3DZIK | 6d6cbbd4b0 | |
M3DZIK | 723bf26dbd | |
M3DZIK | 56cbd96053 | |
Andre Julius | af0864d272 | |
M3DZIK | e782617f08 | |
dependabot[bot] | 7062046679 | |
dependabot[bot] | 9ba2233734 | |
dependabot[bot] | 044fa6525d | |
dependabot[bot] | f6d8e906fb | |
dependabot[bot] | 47b6225280 | |
Andre Julius | e9a7108f90 | |
renovate[bot] | 0398f7f675 | |
renovate[bot] | 300fa61a65 | |
renovate[bot] | 0ad55015ac | |
renovate[bot] | 965c4407f1 | |
renovate[bot] | 80292730f3 | |
MedzikUser | 304034f037 | |
Andre Julius | b6e715accf | |
renovate[bot] | d29b299a4b | |
renovate[bot] | c08e640421 | |
MedzikUser | 60119be30b | |
MedzikUser | 986a3b365c | |
MedzikUser | 25cc96774c | |
renovate[bot] | 111fef82d1 | |
renovate[bot] | 5d5beaecd8 | |
Andre Julius | 89a7969353 | |
MedzikUser | 25190ba5c1 | |
MedzikUser | 012784a352 | |
MedzikUser | 1bd632e906 | |
MedzikUser | a66fea840a | |
dependabot[bot] | dd44c5f041 | |
MedzikUser | 30a79bc8bb | |
MedzikUser | 2ac3424338 | |
MedzikUser | ecb5855e75 | |
MedzikUser | 31c737689c | |
MedzikUser | 8ddfeb3c19 | |
renovate[bot] | f5c70e4f4f | |
MedzikUser | c6b6bd1af7 | |
MedzikUser | 312d9cce19 | |
MedzikUser | ad117bf3ec | |
renovate[bot] | be73023511 | |
renovate[bot] | 0a8d4afb42 | |
renovate[bot] | bd91fb330c | |
renovate[bot] | 066cda0539 | |
renovate[bot] | b0c4dab74d | |
renovate[bot] | ac1cfc9535 | |
MedzikUser | f26170bc12 | |
MedzikUser | 71d124f435 | |
renovate[bot] | c75cad024f | |
renovate[bot] | 0eea52da89 | |
renovate[bot] | 54eea0f968 | |
renovate[bot] | 69211e9720 | |
renovate[bot] | 1d6aa51df6 | |
renovate[bot] | cfa28a2660 | |
renovate[bot] | ba494c594a | |
MedzikUser | 7081367bae | |
renovate[bot] | cc2dde74cd | |
renovate[bot] | 78dcb79b97 | |
renovate[bot] | 78c1c27332 | |
renovate[bot] | 13d9c82fcd | |
MedzikUser | 3c5507adaa | |
MedzikUser | 0bc00599e9 | |
MedzikUser | 2d1f1a4001 | |
Renovate Bot | 66551e77ad | |
Renovate Bot | d0e5367414 | |
Renovate Bot | 7446b0b420 | |
Renovate Bot | a1ca4dad9c | |
Renovate Bot | 7567d26b5b | |
Renovate Bot | feea8f8f2e | |
MedzikUser | 3f2af4f6f9 | |
MedzikUser | b396ccce19 | |
MedzikUser | 80dcd27bc1 | |
MedzikUser | 8bbee811d2 | |
MedzikUser | 831f816447 | |
Renovate Bot | 6da2dc252f | |
Renovate Bot | f935a3dddc | |
Renovate Bot | 15aa471d4f | |
MedzikUser | 9538ca5be8 | |
Renovate Bot | 5d3f5ed27b |
|
@ -1,20 +0,0 @@
|
||||||
# EditorConfig is awesome: https://EditorConfig.org
|
|
||||||
|
|
||||||
# top-most EditorConfig file
|
|
||||||
root = true
|
|
||||||
|
|
||||||
[*]
|
|
||||||
indent_style = space
|
|
||||||
indent_size = 4
|
|
||||||
end_of_line = lf
|
|
||||||
charset = utf-8
|
|
||||||
trim_trailing_whitespace = true
|
|
||||||
insert_final_newline = false
|
|
||||||
|
|
||||||
[*.yml]
|
|
||||||
indent_style = space
|
|
||||||
indent_size = 2
|
|
||||||
end_of_line = lf
|
|
||||||
charset = utf-8
|
|
||||||
trim_trailing_whitespace = true
|
|
||||||
insert_final_newline = false
|
|
|
@ -86,7 +86,7 @@ jobs:
|
||||||
uses: actions-rs/cargo@v1
|
uses: actions-rs/cargo@v1
|
||||||
with:
|
with:
|
||||||
command: build
|
command: build
|
||||||
args: --release --target=${{ matrix.target }} ${{ matrix.cargo_flags }}
|
args: --all --release --target=${{ matrix.target }} ${{ matrix.cargo_flags }}
|
||||||
use-cross: ${{ matrix.cross }}
|
use-cross: ${{ matrix.cross }}
|
||||||
|
|
||||||
- name: Compress binaries
|
- name: Compress binaries
|
||||||
|
@ -131,25 +131,3 @@ jobs:
|
||||||
asset_name: imgurs-$tag-${{ matrix.release_name }}
|
asset_name: imgurs-$tag-${{ matrix.release_name }}
|
||||||
body: ${{ steps.changelog_reader.outputs.log_entry }}
|
body: ${{ steps.changelog_reader.outputs.log_entry }}
|
||||||
if: startsWith(github.ref, 'refs/tags/v')
|
if: startsWith(github.ref, 'refs/tags/v')
|
||||||
|
|
||||||
crates:
|
|
||||||
name: Publish to crates.io
|
|
||||||
runs-on: ubuntu-latest
|
|
||||||
|
|
||||||
if: startsWith(github.ref, 'refs/tags/v')
|
|
||||||
|
|
||||||
steps:
|
|
||||||
- name: Checkout code
|
|
||||||
uses: actions/checkout@v2
|
|
||||||
|
|
||||||
- name: Setup Rust toolchain
|
|
||||||
uses: actions-rs/toolchain@v1
|
|
||||||
with:
|
|
||||||
toolchain: stable
|
|
||||||
target: ${{ matrix.target }}
|
|
||||||
|
|
||||||
- name: Publish to crates.io
|
|
||||||
uses: actions-rs/cargo@v1
|
|
||||||
with:
|
|
||||||
command: publish
|
|
||||||
args: --token ${{ secrets.CARGO_REGISTRY_TOKEN }}
|
|
||||||
|
|
|
@ -40,6 +40,7 @@ jobs:
|
||||||
uses: actions-rs/cargo@v1
|
uses: actions-rs/cargo@v1
|
||||||
with:
|
with:
|
||||||
command: build
|
command: build
|
||||||
|
args: --all
|
||||||
|
|
||||||
- name: cargo test
|
- name: cargo test
|
||||||
uses: actions-rs/cargo@v1
|
uses: actions-rs/cargo@v1
|
||||||
|
@ -52,9 +53,3 @@ jobs:
|
||||||
with:
|
with:
|
||||||
command: clippy
|
command: clippy
|
||||||
args: -- -D warnings --no-deps
|
args: -- -D warnings --no-deps
|
||||||
|
|
||||||
- name: rustfmt
|
|
||||||
uses: actions-rs/cargo@v1
|
|
||||||
with:
|
|
||||||
command: fmt
|
|
||||||
args: --all --check
|
|
||||||
|
|
54
CHANGELOG.md
54
CHANGELOG.md
|
@ -9,6 +9,49 @@ and this project adheres to [Semantic Versioning](http://semver.org/).
|
||||||
|
|
||||||
## [Unreleased]
|
## [Unreleased]
|
||||||
|
|
||||||
|
## [0.11.3] - 2024-04-11
|
||||||
|
- Updated dependencies
|
||||||
|
- Replaced url validation with url crate in imgurs-cli
|
||||||
|
|
||||||
|
## [0.11.2] - 2023-06-22
|
||||||
|
- Updated dependencies
|
||||||
|
- Fix deprecation warning of base64 crate.
|
||||||
|
|
||||||
|
## [0.11.1] - 2022-12-11
|
||||||
|
### Fixed
|
||||||
|
- `album_title` can be null, `account_id` can be null, string or number #92, thanks to @NotNorom
|
||||||
|
|
||||||
|
### Changed
|
||||||
|
- Updated dependencies
|
||||||
|
|
||||||
|
## [0.11.0] - 2022-11-07
|
||||||
|
### Added
|
||||||
|
- Added `with_http_client` method to ImgurClient #87, thanks to @NotNorom
|
||||||
|
|
||||||
|
### Changed
|
||||||
|
- Updated crate arboard to v3
|
||||||
|
- Updated crate simple_logger to v4
|
||||||
|
|
||||||
|
## [0.10.0] - 2022-10-01
|
||||||
|
- add configuration for tls (rustls-tls or native-tls)
|
||||||
|
|
||||||
|
## [0.9.1] - 2022-09-22
|
||||||
|
- delete debug info from cli in release build
|
||||||
|
|
||||||
|
## [0.9.0] - 2022-09-05
|
||||||
|
- moved cli to other crate
|
||||||
|
- added get_album function
|
||||||
|
|
||||||
|
## [0.8.1] - 2022-06-18
|
||||||
|
- fix tests
|
||||||
|
- add missing doc
|
||||||
|
- use `serde` instead of `serde_derive`
|
||||||
|
|
||||||
|
## [0.8.0] - 2022-06-13
|
||||||
|
- add custom `Error` type
|
||||||
|
- move api requests to `requests/` mod
|
||||||
|
- comment code
|
||||||
|
|
||||||
## [0.7.4] - 2022-05-18
|
## [0.7.4] - 2022-05-18
|
||||||
### HOTFIX
|
### HOTFIX
|
||||||
- fixed built on macos and windows
|
- fixed built on macos and windows
|
||||||
|
@ -119,7 +162,16 @@ and this project adheres to [Semantic Versioning](http://semver.org/).
|
||||||
- upload image
|
- upload image
|
||||||
|
|
||||||
<!-- next-url -->
|
<!-- next-url -->
|
||||||
[Unreleased]: https://github.com/MedzikUser/imgurs/compare/v0.7.4...HEAD
|
[Unreleased]: https://github.com/MedzikUser/imgurs/compare/v0.11.3...HEAD
|
||||||
|
[0.11.3]: https://github.com/MedzikUser/imgurs/commits/v0.11.3
|
||||||
|
[0.11.2]: https://github.com/MedzikUser/imgurs/commits/v0.11.2
|
||||||
|
[0.11.1]: https://github.com/MedzikUser/imgurs/commits/v0.11.1
|
||||||
|
[0.11.0]: https://github.com/MedzikUser/imgurs/commits/v0.11.0
|
||||||
|
[0.10.0]: https://github.com/MedzikUser/imgurs/commits/v0.10.0
|
||||||
|
[0.9.1]: https://github.com/MedzikUser/imgurs/commits/v0.9.1
|
||||||
|
[0.9.0]: https://github.com/MedzikUser/imgurs/commits/v0.9.0
|
||||||
|
[0.8.1]: https://github.com/MedzikUser/imgurs/commits/v0.8.1
|
||||||
|
[0.8.0]: https://github.com/MedzikUser/imgurs/commits/v0.8.0
|
||||||
[0.7.4]: https://github.com/MedzikUser/imgurs/commits/v0.7.4
|
[0.7.4]: https://github.com/MedzikUser/imgurs/commits/v0.7.4
|
||||||
[0.7.3]: https://github.com/MedzikUser/imgurs/commits/v0.7.3
|
[0.7.3]: https://github.com/MedzikUser/imgurs/commits/v0.7.3
|
||||||
[0.7.2]: https://github.com/MedzikUser/imgurs/commits/v0.7.2
|
[0.7.2]: https://github.com/MedzikUser/imgurs/commits/v0.7.2
|
||||||
|
|
File diff suppressed because it is too large
Load Diff
76
Cargo.toml
76
Cargo.toml
|
@ -1,61 +1,43 @@
|
||||||
|
[workspace]
|
||||||
|
members = ["imgurs-cli"]
|
||||||
|
resolver = "2"
|
||||||
|
|
||||||
[package]
|
[package]
|
||||||
name = "imgurs"
|
name = "imgurs"
|
||||||
version = "0.7.4"
|
version = "0.11.3"
|
||||||
description = "API and CLI for Imgur"
|
description = "API for Imgur"
|
||||||
license = "BSD-3-Clause"
|
license = "BSD-3-Clause"
|
||||||
readme = "README.md"
|
authors = ["M3DZIK <me@medzik.dev>"]
|
||||||
authors = ["MedzikUser <nivua1fn@duck.com>"]
|
homepage = "https://github.com/M3DZIK/imgurs"
|
||||||
homepage = "https://github.com/MedzikUser/imgurs"
|
repository = "https://github.com/M3DZIK/imgurs.git"
|
||||||
repository = "https://github.com/MedzikUser/imgurs.git"
|
|
||||||
keywords = ["imgur", "imgur-api", "image", "image-upload"]
|
keywords = ["imgur", "imgur-api", "image", "image-upload"]
|
||||||
categories = ["command-line-utilities"]
|
|
||||||
rust-version = "1.58"
|
|
||||||
edition = "2021"
|
edition = "2021"
|
||||||
|
|
||||||
|
[features]
|
||||||
|
default = ["imgur", "rustls-tls"]
|
||||||
|
full = ["imgur"]
|
||||||
|
rustls-tls = ["reqwest/rustls-tls"]
|
||||||
|
native-tls = ["reqwest/native-tls"]
|
||||||
|
imgur = []
|
||||||
|
|
||||||
[profile.release]
|
[profile.release]
|
||||||
lto = true
|
lto = true
|
||||||
panic = 'abort'
|
|
||||||
opt-level = 'z'
|
opt-level = 'z'
|
||||||
codegen-units = 1
|
codegen-units = 1
|
||||||
|
|
||||||
[dependencies]
|
[dependencies]
|
||||||
dirs = "4.0.0"
|
# HTTP
|
||||||
serde = "1.0.137"
|
reqwest = { version = "0.12", default-features = false, features = ["json", "multipart"] }
|
||||||
serde_derive = "1.0.137"
|
# Request
|
||||||
toml = "0.5.9"
|
base64 = "0.22"
|
||||||
serde_json = "1.0.81"
|
url = "2.5.0" # validate url address
|
||||||
chrono = "0.4.19"
|
# Response
|
||||||
base64 = "0.13.0"
|
serde = { version = "1.0", features = ["derive"] }
|
||||||
notify-rust = "4.5.8"
|
serde_json = "1.0"
|
||||||
clap_complete = "3.1.4"
|
|
||||||
anyhow = "1.0.57"
|
|
||||||
better-panic = "0.3.0"
|
|
||||||
validator = "0.15.0"
|
|
||||||
colored = "2.0.0"
|
|
||||||
clap_mangen = "0.1.6"
|
|
||||||
discord-webhook = "0.1.0"
|
|
||||||
|
|
||||||
[target.'cfg(not(all(unix, not(any(target_os="macos", target_os="android", target_os="emscripten")))))'.dependencies]
|
# Errors
|
||||||
arboard = "2.1.0"
|
thiserror = "1.0"
|
||||||
|
|
||||||
[dependencies.clap]
|
[dev-dependencies]
|
||||||
version = "3.1.18"
|
# Async tests
|
||||||
features = ["derive", "cargo", "std"]
|
tokio = { version = "1.37", features = ["macros", "rt-multi-thread"] }
|
||||||
|
|
||||||
[dependencies.log]
|
|
||||||
version = "0.4.17"
|
|
||||||
features = ["release_max_level_info", "max_level_debug"]
|
|
||||||
|
|
||||||
[dependencies.simple_logger]
|
|
||||||
version = "2.1.0"
|
|
||||||
default-features = false
|
|
||||||
features = ["colors"]
|
|
||||||
|
|
||||||
[dependencies.reqwest]
|
|
||||||
version = "0.11.10"
|
|
||||||
default-features = false
|
|
||||||
features = ["json", "rustls-tls"]
|
|
||||||
|
|
||||||
[dependencies.tokio]
|
|
||||||
version = "1.18.2"
|
|
||||||
features = ["macros", "rt-multi-thread"]
|
|
||||||
|
|
10
README.md
10
README.md
|
@ -1,8 +1,10 @@
|
||||||
|
[crates-io]: https://img.shields.io/badge/crates.io-fc8d62?style=for-the-badge&labelColor=555555&logo=rust
|
||||||
|
[docs-rs]: https://img.shields.io/badge/docs.rs-66c2a5?style=for-the-badge&labelColor=555555&logo=docs.rs
|
||||||
|
|
||||||
# Imgurs - CLI and Library for Imgur API
|
# Imgurs - CLI and Library for Imgur API
|
||||||
|
|
||||||
![](https://img.shields.io/github/license/MedzikUser/imgurs)
|
[![crates-io]](https://crates.io/crates/imgurs)
|
||||||
![](https://img.shields.io/tokei/lines/github/MedzikUser/imgurs)
|
[![docs-rs]](https://docs.rs/imgurs)
|
||||||
![](https://img.shields.io/github/languages/code-size/MedzikUser/imgurs)
|
|
||||||
|
|
||||||
## Screenshots
|
## Screenshots
|
||||||
|
|
||||||
|
@ -66,4 +68,4 @@ Download imgurs-windows.exe from [the releases page](https://github.com/MedzikUs
|
||||||
### **Compile with Cargo**
|
### **Compile with Cargo**
|
||||||
Make sure you have a recent version of Rust. Then you can run
|
Make sure you have a recent version of Rust. Then you can run
|
||||||
|
|
||||||
cargo install imgurs
|
cargo install imgurs-cli
|
||||||
|
|
|
@ -7,7 +7,3 @@ enabled = true
|
||||||
|
|
||||||
[clipboard]
|
[clipboard]
|
||||||
enabled = true
|
enabled = true
|
||||||
|
|
||||||
[discord_webhook]
|
|
||||||
enabled = false
|
|
||||||
uri = ''
|
|
||||||
|
|
|
@ -0,0 +1,46 @@
|
||||||
|
[package]
|
||||||
|
name = "imgurs-cli"
|
||||||
|
version = "0.11.3"
|
||||||
|
description = "CLI for Imgur"
|
||||||
|
license = "BSD-3-Clause"
|
||||||
|
authors = ["M3DZIK <me@medzik.dev>"]
|
||||||
|
homepage = "https://github.com/M3DZIK/imgurs"
|
||||||
|
repository = "https://github.com/M3DZIK/imgurs.git"
|
||||||
|
keywords = ["imgur", "imgur-api", "image", "image-upload"]
|
||||||
|
categories = ["command-line-utilities"]
|
||||||
|
edition = "2021"
|
||||||
|
|
||||||
|
[[bin]]
|
||||||
|
name = "imgurs"
|
||||||
|
path = "src/main.rs"
|
||||||
|
|
||||||
|
[dependencies]
|
||||||
|
# Async runtime
|
||||||
|
tokio = { version = "1.37", features = ["macros", "rt-multi-thread"] }
|
||||||
|
|
||||||
|
# CLI
|
||||||
|
clap = { version = "4.5", features = ["derive"] }
|
||||||
|
clap_complete = "4.5"
|
||||||
|
clap_mangen = "0.2"
|
||||||
|
|
||||||
|
# Errors
|
||||||
|
anyhow = "1.0"
|
||||||
|
|
||||||
|
# Logger
|
||||||
|
log = { version = "0.4", features = ["release_max_level_info"] }
|
||||||
|
simple_logger = "4.3"
|
||||||
|
colored = "2.1"
|
||||||
|
|
||||||
|
# Config
|
||||||
|
toml = "0.8"
|
||||||
|
serde = { version = "1.0", features = ["derive"] }
|
||||||
|
|
||||||
|
# Other
|
||||||
|
chrono = "0.4" # parse upload date
|
||||||
|
notify-rust = "4.11" # send notification after upload
|
||||||
|
dirs = "5.0" # get system configuration directory
|
||||||
|
|
||||||
|
imgurs = { path = "..", version = "0.11.0", features = ["full"] }
|
||||||
|
|
||||||
|
[target.'cfg(not(all(unix, not(any(target_os="macos", target_os="android", target_os="emscripten")))))'.dependencies]
|
||||||
|
arboard = "3.3" # copy url to clipboard
|
|
@ -0,0 +1 @@
|
||||||
|
../config.toml
|
|
@ -1,34 +1,37 @@
|
||||||
use serde::Serialize;
|
use serde::{Deserialize, Serialize};
|
||||||
use serde_derive::Deserialize;
|
|
||||||
|
|
||||||
pub mod toml;
|
pub mod toml;
|
||||||
|
|
||||||
|
/// Configuration schema
|
||||||
#[derive(Debug, Serialize, Deserialize)]
|
#[derive(Debug, Serialize, Deserialize)]
|
||||||
pub struct Config {
|
pub struct Config {
|
||||||
|
/// Imgur API configuration options
|
||||||
pub imgur: ConfigImgur,
|
pub imgur: ConfigImgur,
|
||||||
|
/// Notification options
|
||||||
pub notification: ConfigNotification,
|
pub notification: ConfigNotification,
|
||||||
|
/// Clipboard options
|
||||||
pub clipboard: ConfigClipboard,
|
pub clipboard: ConfigClipboard,
|
||||||
pub discord_webhook: ConfigDiscordWebhook,
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// Imgur API configuration options
|
||||||
#[derive(Debug, Serialize, Deserialize)]
|
#[derive(Debug, Serialize, Deserialize)]
|
||||||
pub struct ConfigImgur {
|
pub struct ConfigImgur {
|
||||||
|
/// Imgur Client ID
|
||||||
pub id: String,
|
pub id: String,
|
||||||
|
/// Imgur Domain (e.g. if you have a imgur proxy)
|
||||||
pub image_cdn: String,
|
pub image_cdn: String,
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// Notification options
|
||||||
#[derive(Debug, Serialize, Deserialize)]
|
#[derive(Debug, Serialize, Deserialize)]
|
||||||
pub struct ConfigNotification {
|
pub struct ConfigNotification {
|
||||||
|
/// Send notification
|
||||||
pub enabled: bool,
|
pub enabled: bool,
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// Clipboard options
|
||||||
#[derive(Debug, Serialize, Deserialize)]
|
#[derive(Debug, Serialize, Deserialize)]
|
||||||
pub struct ConfigClipboard {
|
pub struct ConfigClipboard {
|
||||||
|
/// Copy image url to clipboard
|
||||||
pub enabled: bool,
|
pub enabled: bool,
|
||||||
}
|
}
|
||||||
|
|
||||||
#[derive(Debug, Serialize, Deserialize)]
|
|
||||||
pub struct ConfigDiscordWebhook {
|
|
||||||
pub enabled: bool,
|
|
||||||
pub uri: String,
|
|
||||||
}
|
|
|
@ -1,18 +1,22 @@
|
||||||
use super::Config;
|
|
||||||
|
|
||||||
use colored::Colorize;
|
|
||||||
use dirs::config_dir;
|
|
||||||
use log::warn;
|
|
||||||
use std::{
|
use std::{
|
||||||
fs::{create_dir_all, read_to_string, File},
|
fs::{create_dir_all, read_to_string, File},
|
||||||
io::{self, Write as _},
|
io::{self, Write as _},
|
||||||
path::Path,
|
path::Path,
|
||||||
};
|
};
|
||||||
|
|
||||||
|
use colored::Colorize;
|
||||||
|
use dirs::config_dir;
|
||||||
|
use log::warn;
|
||||||
use toml::from_str as toml_from_str;
|
use toml::from_str as toml_from_str;
|
||||||
|
|
||||||
|
use super::Config;
|
||||||
|
|
||||||
|
/// Configuration file path (in system config directory).
|
||||||
const CONFIG_DIR: &str = "/imgurs/config.toml";
|
const CONFIG_DIR: &str = "/imgurs/config.toml";
|
||||||
|
|
||||||
|
/// Parse configuration file
|
||||||
pub fn parse() -> Config {
|
pub fn parse() -> Config {
|
||||||
|
// parse config or use default
|
||||||
toml().unwrap_or_else(|err| {
|
toml().unwrap_or_else(|err| {
|
||||||
let mut stdout = std::io::stdout();
|
let mut stdout = std::io::stdout();
|
||||||
|
|
||||||
|
@ -25,7 +29,7 @@ pub fn parse() -> Config {
|
||||||
.expect("failed to read line");
|
.expect("failed to read line");
|
||||||
|
|
||||||
if value.to_lowercase() != "n\n" {
|
if value.to_lowercase() != "n\n" {
|
||||||
warn!("Parse toml config: {err}! Creating config file...");
|
warn!("Parse toml config error: {err}! Creating config file...");
|
||||||
|
|
||||||
let default_config = include_str!(concat!("../../config.toml"));
|
let default_config = include_str!(concat!("../../config.toml"));
|
||||||
|
|
||||||
|
@ -44,7 +48,7 @@ pub fn parse() -> Config {
|
||||||
|
|
||||||
toml().expect("parse toml config")
|
toml().expect("parse toml config")
|
||||||
} else {
|
} else {
|
||||||
panic!("New config creation cancelled!")
|
panic!("Configuration file creation cancelled!")
|
||||||
}
|
}
|
||||||
})
|
})
|
||||||
}
|
}
|
|
@ -1,18 +1,16 @@
|
||||||
mod parse;
|
mod clipboard;
|
||||||
|
mod credits;
|
||||||
|
mod delete_image;
|
||||||
|
mod info_image;
|
||||||
|
mod upload_image;
|
||||||
|
|
||||||
pub mod clipboard;
|
use std::time::{Duration, UNIX_EPOCH};
|
||||||
pub mod credits;
|
|
||||||
pub mod delete_image;
|
|
||||||
pub mod info_image;
|
|
||||||
pub mod upload_image;
|
|
||||||
pub mod webhook;
|
|
||||||
|
|
||||||
pub use parse::*;
|
|
||||||
|
|
||||||
use chrono::{prelude::DateTime, Utc};
|
use chrono::{prelude::DateTime, Utc};
|
||||||
use colored::Colorize;
|
use colored::Colorize;
|
||||||
use imgurs::ImageInfo;
|
use imgurs::ImageInfo;
|
||||||
use std::time::{Duration, UNIX_EPOCH};
|
|
||||||
|
pub use self::{clipboard::*, credits::*, delete_image::*, info_image::*, upload_image::*};
|
||||||
|
|
||||||
// print image information from imgur
|
// print image information from imgur
|
||||||
pub fn print_image_info(i: &ImageInfo) {
|
pub fn print_image_info(i: &ImageInfo) {
|
|
@ -2,8 +2,8 @@ use imgurs::ImgurClient;
|
||||||
use notify_rust::Notification;
|
use notify_rust::Notification;
|
||||||
|
|
||||||
use crate::{
|
use crate::{
|
||||||
cli::{clipboard::set_clipboard, print_image_info, webhook::send_discord_webhook},
|
|
||||||
config::toml,
|
config::toml,
|
||||||
|
imgur::{clipboard::set_clipboard, print_image_info},
|
||||||
};
|
};
|
||||||
|
|
||||||
// show notification
|
// show notification
|
||||||
|
@ -26,7 +26,7 @@ pub async fn upload_image(client: ImgurClient, path: String) {
|
||||||
.body(&format!("Error: {}", err))
|
.body(&format!("Error: {}", err))
|
||||||
.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!("send request to imagur api: {}", err)
|
panic!("send request to imgur api: {}", err)
|
||||||
});
|
});
|
||||||
|
|
||||||
// change domain to proxy (to be set in config)
|
// change domain to proxy (to be set in config)
|
||||||
|
@ -46,11 +46,4 @@ pub async fn upload_image(client: ImgurClient, path: String) {
|
||||||
if config.clipboard.enabled {
|
if config.clipboard.enabled {
|
||||||
set_clipboard(&i.data.link)
|
set_clipboard(&i.data.link)
|
||||||
}
|
}
|
||||||
|
|
||||||
// if enabled send embed with link and deletehash to discord (something like logger)
|
|
||||||
if config.discord_webhook.enabled {
|
|
||||||
send_discord_webhook(&i.data.link, &i.data.deletehash.unwrap())
|
|
||||||
.await
|
|
||||||
.expect("send discord webhook");
|
|
||||||
}
|
|
||||||
}
|
}
|
|
@ -0,0 +1,82 @@
|
||||||
|
use std::io::stdout;
|
||||||
|
|
||||||
|
use clap::{Command, CommandFactory, Parser};
|
||||||
|
use clap_complete::{generate, Generator, Shell};
|
||||||
|
use imgurs::ImgurClient;
|
||||||
|
use simple_logger::SimpleLogger;
|
||||||
|
|
||||||
|
use crate::imgur::*;
|
||||||
|
|
||||||
|
mod config;
|
||||||
|
mod imgur;
|
||||||
|
|
||||||
|
#[derive(Parser, Debug)]
|
||||||
|
#[clap(
|
||||||
|
name = "imgurs",
|
||||||
|
about = "Imgur API CLI",
|
||||||
|
long_about = env!("CARGO_PKG_DESCRIPTION"),
|
||||||
|
version = env!("CARGO_PKG_VERSION"),
|
||||||
|
)]
|
||||||
|
enum Cli {
|
||||||
|
#[clap(about = "Print Client Rate Limit", display_order = 1)]
|
||||||
|
Credits,
|
||||||
|
|
||||||
|
#[clap(about = "Upload image to Imgur", display_order = 2)]
|
||||||
|
Upload { path: String },
|
||||||
|
|
||||||
|
#[clap(about = "Delete image from Imgur", display_order = 3)]
|
||||||
|
Delete { delete_hash: String },
|
||||||
|
|
||||||
|
#[clap(about = "Print image info", display_order = 4)]
|
||||||
|
Info { id: String },
|
||||||
|
|
||||||
|
#[clap(
|
||||||
|
about = "Generate completion file for a shell [bash, elvish, fish, powershell, zsh]",
|
||||||
|
display_order = 5
|
||||||
|
)]
|
||||||
|
Completions { shell: Shell },
|
||||||
|
|
||||||
|
#[clap(about = "Generate man page", display_order = 6)]
|
||||||
|
Manpage,
|
||||||
|
}
|
||||||
|
|
||||||
|
#[tokio::main]
|
||||||
|
async fn main() {
|
||||||
|
SimpleLogger::new().init().unwrap();
|
||||||
|
|
||||||
|
// parse config file
|
||||||
|
let config = config::toml::parse();
|
||||||
|
|
||||||
|
// create imgur client
|
||||||
|
let client = ImgurClient::new(&config.imgur.id);
|
||||||
|
|
||||||
|
let args = Cli::parse();
|
||||||
|
|
||||||
|
match args {
|
||||||
|
Cli::Credits => credits(client).await,
|
||||||
|
|
||||||
|
Cli::Upload { path } => upload_image(client, path).await,
|
||||||
|
|
||||||
|
Cli::Delete { delete_hash } => delete_image(client, delete_hash.to_string()).await,
|
||||||
|
|
||||||
|
Cli::Info { id } => image_info(client, id.to_string()).await,
|
||||||
|
|
||||||
|
Cli::Completions { shell } => {
|
||||||
|
let mut app = Cli::command();
|
||||||
|
|
||||||
|
fn print_completions<G: Generator>(gen: G, app: &mut Command) {
|
||||||
|
generate(gen, app, app.get_name().to_string(), &mut stdout())
|
||||||
|
}
|
||||||
|
|
||||||
|
print_completions(shell, &mut app)
|
||||||
|
},
|
||||||
|
|
||||||
|
Cli::Manpage => {
|
||||||
|
let clap_app = Cli::command();
|
||||||
|
let man = clap_mangen::Man::new(clap_app);
|
||||||
|
|
||||||
|
man.render(&mut stdout())
|
||||||
|
.expect("Failed to generate man page");
|
||||||
|
},
|
||||||
|
}
|
||||||
|
}
|
|
@ -1,8 +1,14 @@
|
||||||
{
|
{
|
||||||
|
"$schema": "https://docs.renovatebot.com/renovate-schema.json",
|
||||||
"extends": [
|
"extends": [
|
||||||
"config:base"
|
"config:base",
|
||||||
|
"schedule:weekly",
|
||||||
|
"group:allNonMajor",
|
||||||
|
":semanticCommits"
|
||||||
|
],
|
||||||
|
"labels": [
|
||||||
|
"dependencies"
|
||||||
],
|
],
|
||||||
"prHourlyLimit": 0,
|
|
||||||
"automergeType": "pr",
|
"automergeType": "pr",
|
||||||
"prCreation": "immediate",
|
"prCreation": "immediate",
|
||||||
"packageRules": [
|
"packageRules": [
|
||||||
|
|
|
@ -0,0 +1,11 @@
|
||||||
|
# https://rust-lang.github.io/rustfmt
|
||||||
|
|
||||||
|
# stable
|
||||||
|
edition = "2021"
|
||||||
|
newline_style = "Unix"
|
||||||
|
match_block_trailing_comma = true
|
||||||
|
|
||||||
|
# nightly
|
||||||
|
group_imports = "StdExternalCrate"
|
||||||
|
imports_granularity = "Crate"
|
||||||
|
format_code_in_doc_comments = true
|
|
@ -1,118 +0,0 @@
|
||||||
macro_rules! api_url (
|
|
||||||
($path: expr) => (
|
|
||||||
format!("{}{}", "https://api.imgur.com/3/", $path)
|
|
||||||
);
|
|
||||||
);
|
|
||||||
|
|
||||||
use std::{fmt, fs, io, path::Path};
|
|
||||||
|
|
||||||
use anyhow::Result;
|
|
||||||
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 {
|
|
||||||
/// Create new Imgur Client
|
|
||||||
/// ```
|
|
||||||
/// use imgurs::ImgurClient;
|
|
||||||
///
|
|
||||||
/// let client = ImgurClient::new("3e3ce0d7ac14d56");
|
|
||||||
/// ```
|
|
||||||
pub fn new(client_id: &str) -> Self {
|
|
||||||
let client_id = client_id.to_string();
|
|
||||||
let client = Client::new();
|
|
||||||
ImgurClient { client_id, client }
|
|
||||||
}
|
|
||||||
|
|
||||||
/// Upload image to Imgur
|
|
||||||
/// ```
|
|
||||||
/// use imgurs::ImgurClient;
|
|
||||||
///
|
|
||||||
/// #[tokio::main]
|
|
||||||
/// async fn main() {
|
|
||||||
/// let client = ImgurClient::new("3e3ce0d7ac14d56");
|
|
||||||
///
|
|
||||||
/// client.upload_image("https://i.imgur.com/lFaGr1x.png").await.expect("upload image");
|
|
||||||
/// }
|
|
||||||
/// ```
|
|
||||||
pub async fn upload_image(&self, path: &str) -> Result<ImageInfo> {
|
|
||||||
let mut image = path.to_string();
|
|
||||||
|
|
||||||
// check if the specified file exists if not then check if it is a url
|
|
||||||
if Path::new(&path).exists() {
|
|
||||||
let bytes = fs::read(&path)?;
|
|
||||||
image = base64::encode(bytes)
|
|
||||||
}
|
|
||||||
// validate adress url
|
|
||||||
else if !validator::validate_url(&*path) {
|
|
||||||
let err = io::Error::new(
|
|
||||||
io::ErrorKind::Other,
|
|
||||||
format!("{path} is not url or file path"),
|
|
||||||
);
|
|
||||||
|
|
||||||
return Err(err.into());
|
|
||||||
}
|
|
||||||
|
|
||||||
upload_image(self, image).await
|
|
||||||
}
|
|
||||||
|
|
||||||
/// Delete image from Imgur
|
|
||||||
/// ```
|
|
||||||
/// use imgurs::ImgurClient;
|
|
||||||
///
|
|
||||||
/// #[tokio::main]
|
|
||||||
/// async fn main() {
|
|
||||||
/// let client = ImgurClient::new("3e3ce0d7ac14d56");
|
|
||||||
///
|
|
||||||
/// let image = client.upload_image("https://i.imgur.com/lFaGr1x.png").await.expect("upload image");
|
|
||||||
/// let deletehash = image.data.deletehash.unwrap();
|
|
||||||
///
|
|
||||||
/// client.delete_image(&deletehash).await.expect("delete image");
|
|
||||||
/// }
|
|
||||||
/// ```
|
|
||||||
pub async fn delete_image(&self, delete_hash: &str) -> Result<()> {
|
|
||||||
delete_image(self, delete_hash).await
|
|
||||||
}
|
|
||||||
|
|
||||||
/// Client Rate Limit
|
|
||||||
/// ```
|
|
||||||
/// use imgurs::ImgurClient;
|
|
||||||
///
|
|
||||||
/// #[tokio::main]
|
|
||||||
/// async fn main() {
|
|
||||||
/// let client = ImgurClient::new("3e3ce0d7ac14d56");
|
|
||||||
///
|
|
||||||
/// client.rate_limit().await.expect("get rate limit");
|
|
||||||
/// }
|
|
||||||
/// ```
|
|
||||||
pub async fn rate_limit(&self) -> Result<RateLimitInfo> {
|
|
||||||
rate_limit(self).await
|
|
||||||
}
|
|
||||||
|
|
||||||
/// Get Imgur image info
|
|
||||||
/// ```
|
|
||||||
/// use imgurs::ImgurClient;
|
|
||||||
///
|
|
||||||
/// #[tokio::main]
|
|
||||||
/// async fn main() {
|
|
||||||
/// let client = ImgurClient::new("3e3ce0d7ac14d56");
|
|
||||||
///
|
|
||||||
/// client.image_info("lFaGr1x").await.expect("delete image");
|
|
||||||
/// }
|
|
||||||
/// ```
|
|
||||||
pub async fn image_info(&self, id: &str) -> Result<ImageInfo> {
|
|
||||||
get_image(self, id).await
|
|
||||||
}
|
|
||||||
}
|
|
|
@ -1,29 +0,0 @@
|
||||||
use std::io;
|
|
||||||
|
|
||||||
use reqwest::Method;
|
|
||||||
|
|
||||||
use super::{client::api_url, send_api_request, ImageInfo, ImgurClient};
|
|
||||||
|
|
||||||
pub async fn get_image(client: &ImgurClient, image: &str) -> anyhow::Result<ImageInfo> {
|
|
||||||
// get imgur api url
|
|
||||||
let uri = api_url!(format!("image/{image}"));
|
|
||||||
|
|
||||||
// send request to imgur api
|
|
||||||
let res = send_api_request(client, Method::GET, uri, None).await?;
|
|
||||||
|
|
||||||
// get response http code
|
|
||||||
let status = res.status();
|
|
||||||
|
|
||||||
// check if an error has occurred
|
|
||||||
if status.is_client_error() || status.is_server_error() {
|
|
||||||
let err = io::Error::new(
|
|
||||||
io::ErrorKind::Other,
|
|
||||||
format!("server returned non-successful status code = {status}"),
|
|
||||||
);
|
|
||||||
|
|
||||||
Err(err.into())
|
|
||||||
} else {
|
|
||||||
let content: ImageInfo = res.json().await?;
|
|
||||||
Ok(content)
|
|
||||||
}
|
|
||||||
}
|
|
|
@ -1,27 +0,0 @@
|
||||||
use serde_derive::{Deserialize, Serialize};
|
|
||||||
|
|
||||||
#[derive(Debug, Serialize, Deserialize, Clone)]
|
|
||||||
pub struct ImageInfo {
|
|
||||||
pub data: ImageInfoData,
|
|
||||||
pub success: bool,
|
|
||||||
pub status: i32,
|
|
||||||
}
|
|
||||||
|
|
||||||
#[derive(Debug, Serialize, Deserialize, Clone)]
|
|
||||||
pub struct ImageInfoData {
|
|
||||||
pub id: String,
|
|
||||||
pub title: Option<String>,
|
|
||||||
pub description: Option<String>,
|
|
||||||
pub datetime: i32,
|
|
||||||
#[serde(rename = "type")]
|
|
||||||
pub img_type: String,
|
|
||||||
pub animated: bool,
|
|
||||||
pub width: i32,
|
|
||||||
pub height: i32,
|
|
||||||
pub size: i32,
|
|
||||||
pub views: i32,
|
|
||||||
pub bandwidth: i64,
|
|
||||||
pub favorite: bool,
|
|
||||||
pub deletehash: Option<String>,
|
|
||||||
pub link: String,
|
|
||||||
}
|
|
|
@ -1,52 +0,0 @@
|
||||||
mod delete_image;
|
|
||||||
mod get_image;
|
|
||||||
mod image_type;
|
|
||||||
mod rate_limit;
|
|
||||||
mod upload_image;
|
|
||||||
|
|
||||||
pub mod client;
|
|
||||||
|
|
||||||
pub use client::ImgurClient;
|
|
||||||
pub use delete_image::*;
|
|
||||||
pub use get_image::*;
|
|
||||||
pub use image_type::*;
|
|
||||||
pub use rate_limit::*;
|
|
||||||
pub use upload_image::*;
|
|
||||||
|
|
||||||
use std::collections::HashMap;
|
|
||||||
|
|
||||||
use reqwest::{Method, Response};
|
|
||||||
|
|
||||||
// send request to imgur api
|
|
||||||
pub async fn send_api_request(
|
|
||||||
config: &ImgurClient,
|
|
||||||
method: Method,
|
|
||||||
uri: String,
|
|
||||||
form: Option<HashMap<&str, String>>,
|
|
||||||
) -> anyhow::Result<Response> {
|
|
||||||
// get request client
|
|
||||||
let client = &config.client;
|
|
||||||
|
|
||||||
// create request buidler
|
|
||||||
let mut req = client.request(method, uri.as_str());
|
|
||||||
|
|
||||||
// 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
|
|
||||||
.header("Authorization", format!("Client-ID {}", config.client_id))
|
|
||||||
.header("User-Agent", format!("Imgur/{:?}", version));
|
|
||||||
|
|
||||||
// if exists add hashmap to request
|
|
||||||
if form != None {
|
|
||||||
req = req.form(&form.unwrap())
|
|
||||||
}
|
|
||||||
|
|
||||||
// build request
|
|
||||||
let req = req.build()?;
|
|
||||||
|
|
||||||
// send request
|
|
||||||
Ok(client.execute(req).await?)
|
|
||||||
}
|
|
|
@ -1,76 +0,0 @@
|
||||||
use clap::{Command, IntoApp, Parser, Subcommand};
|
|
||||||
use clap_complete::{generate, Generator, Shell};
|
|
||||||
use imgurs::ImgurClient;
|
|
||||||
use std::io::{self, stdout};
|
|
||||||
|
|
||||||
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 NAME: Option<&str> = option_env!("CARGO_PKG_NAME");
|
|
||||||
|
|
||||||
#[derive(Parser, Debug)]
|
|
||||||
#[clap(
|
|
||||||
name = NAME.unwrap_or("unknown"),
|
|
||||||
about = "Imgur API CLI", long_about = None,
|
|
||||||
version = VERSION.unwrap_or("unknown")
|
|
||||||
)]
|
|
||||||
struct Cli {
|
|
||||||
#[clap(subcommand)]
|
|
||||||
command: Commands,
|
|
||||||
}
|
|
||||||
|
|
||||||
#[derive(Subcommand, Debug)]
|
|
||||||
enum Commands {
|
|
||||||
#[clap(about = "Print Client Rate Limit", display_order = 1)]
|
|
||||||
Credits,
|
|
||||||
|
|
||||||
#[clap(about = "Upload image to Imgur", display_order = 2)]
|
|
||||||
Upload { path: String },
|
|
||||||
|
|
||||||
#[clap(about = "Delete image from Imgur", display_order = 3)]
|
|
||||||
Delete { delete_hash: String },
|
|
||||||
|
|
||||||
#[clap(about = "Print image info", display_order = 4)]
|
|
||||||
Info { id: String },
|
|
||||||
|
|
||||||
#[clap(
|
|
||||||
about = "Generate completion file for a shell [bash, elvish, fish, powershell, zsh]",
|
|
||||||
display_order = 5
|
|
||||||
)]
|
|
||||||
Completions { shell: Shell },
|
|
||||||
|
|
||||||
#[clap(about = "Generate man page", display_order = 6)]
|
|
||||||
Manpage,
|
|
||||||
}
|
|
||||||
|
|
||||||
fn print_completions<G: Generator>(gen: G, app: &mut Command) {
|
|
||||||
generate(gen, app, app.get_name().to_string(), &mut stdout())
|
|
||||||
}
|
|
||||||
|
|
||||||
pub async fn parse(client: ImgurClient) {
|
|
||||||
let args = Cli::parse();
|
|
||||||
|
|
||||||
match args.command {
|
|
||||||
Commands::Credits => credits(client).await,
|
|
||||||
|
|
||||||
Commands::Upload { path } => upload_image(client, path.to_string()).await,
|
|
||||||
|
|
||||||
Commands::Delete { delete_hash } => delete_image(client, delete_hash.to_string()).await,
|
|
||||||
|
|
||||||
Commands::Info { id } => image_info(client, id.to_string()).await,
|
|
||||||
|
|
||||||
Commands::Completions { shell } => {
|
|
||||||
let mut app = Cli::command();
|
|
||||||
|
|
||||||
print_completions(shell, &mut app)
|
|
||||||
}
|
|
||||||
|
|
||||||
Commands::Manpage => {
|
|
||||||
let clap_app = Cli::command();
|
|
||||||
let man = clap_mangen::Man::new(clap_app);
|
|
||||||
|
|
||||||
man.render(&mut io::stdout()).expect("generate manpage")
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
|
@ -1,34 +0,0 @@
|
||||||
use discord_webhook::client::WebhookClient;
|
|
||||||
use std::error::Error;
|
|
||||||
|
|
||||||
use crate::config::toml;
|
|
||||||
|
|
||||||
// send embed with link and deletehash to discord (something like logger)
|
|
||||||
pub async fn send_discord_webhook(
|
|
||||||
link: &str,
|
|
||||||
deletehash: &str,
|
|
||||||
) -> Result<(), Box<dyn Error + Send + Sync>> {
|
|
||||||
// get discord webhook uri from config
|
|
||||||
let url = toml::parse().discord_webhook.uri;
|
|
||||||
|
|
||||||
// create WebhookClient
|
|
||||||
let client: WebhookClient = WebhookClient::new(&url);
|
|
||||||
|
|
||||||
// get program version
|
|
||||||
let version = option_env!("CARGO_PKG_VERSION").unwrap_or("unknown");
|
|
||||||
|
|
||||||
// send discord webhook
|
|
||||||
client
|
|
||||||
.send(|message| {
|
|
||||||
message.username("Imgurs").embed(|embed| {
|
|
||||||
embed
|
|
||||||
.title(link)
|
|
||||||
.description(&format!("Delete Hash ||{deletehash}||"))
|
|
||||||
.image(link)
|
|
||||||
.footer(&format!("Imgurs v{version}"), None)
|
|
||||||
})
|
|
||||||
})
|
|
||||||
.await?;
|
|
||||||
|
|
||||||
Ok(())
|
|
||||||
}
|
|
|
@ -0,0 +1,36 @@
|
||||||
|
use thiserror::Error;
|
||||||
|
|
||||||
|
/// Client Errors
|
||||||
|
#[derive(Debug, Error)]
|
||||||
|
pub enum Error {
|
||||||
|
/// Imgur API returned non-successful status code
|
||||||
|
#[error("server reponse non-successful status code - {0}, body = `{1}`")]
|
||||||
|
ApiError(u16, String),
|
||||||
|
/// Imgur API returned non-successful status code (body is too long)
|
||||||
|
#[error("server reponse non-successful status code - {0}, (response body is too long)")]
|
||||||
|
ApiErrorBodyTooLong(u16),
|
||||||
|
/// Invalid file path or URL adress
|
||||||
|
#[error("{0} is not url or file path")]
|
||||||
|
InvalidUrlOrFile(String),
|
||||||
|
/// Imgur API error or reqwest::Error
|
||||||
|
#[error("send request to imgur api: {0}")]
|
||||||
|
SendApiRequest(reqwest::Error),
|
||||||
|
/// std::io::Error
|
||||||
|
#[error("io error - {0}")]
|
||||||
|
IoError(std::io::Error),
|
||||||
|
}
|
||||||
|
|
||||||
|
impl From<reqwest::Error> for Error {
|
||||||
|
fn from(err: reqwest::Error) -> Self {
|
||||||
|
Error::SendApiRequest(err)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl From<std::io::Error> for Error {
|
||||||
|
fn from(err: std::io::Error) -> Self {
|
||||||
|
Error::IoError(err)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/// A `Result` alias where the `Err` case is `imgurs::Error`
|
||||||
|
pub type Result<T> = std::result::Result<T, Error>;
|
|
@ -0,0 +1,69 @@
|
||||||
|
use serde::{Deserialize, Serialize};
|
||||||
|
|
||||||
|
use crate::ImageInfoData;
|
||||||
|
|
||||||
|
/// Album Info Response
|
||||||
|
#[derive(Debug, Serialize, Deserialize, PartialEq, Eq, Clone)]
|
||||||
|
pub struct AlbumInfo {
|
||||||
|
/// Image Data
|
||||||
|
pub data: AlbumInfoData,
|
||||||
|
/// Request processed success or not.
|
||||||
|
pub success: bool,
|
||||||
|
/// HTTP status code from API request.
|
||||||
|
pub status: i32,
|
||||||
|
}
|
||||||
|
|
||||||
|
#[derive(Debug, Serialize, Deserialize, PartialEq, Eq, Clone)]
|
||||||
|
pub struct AlbumInfoData {
|
||||||
|
/// Album ID
|
||||||
|
pub id: String,
|
||||||
|
/// Title of the album
|
||||||
|
pub title: Option<String>,
|
||||||
|
/// Description of the album
|
||||||
|
pub description: Option<String>,
|
||||||
|
pub datetime: i64,
|
||||||
|
pub cover: String,
|
||||||
|
pub cover_edited: Option<String>,
|
||||||
|
pub cover_width: i64,
|
||||||
|
pub cover_height: i64,
|
||||||
|
pub account_url: Option<String>,
|
||||||
|
pub account_id: Option<AccountId>,
|
||||||
|
pub privacy: String,
|
||||||
|
pub layout: String,
|
||||||
|
pub views: i64,
|
||||||
|
/// Album link
|
||||||
|
pub link: String,
|
||||||
|
pub favorite: bool,
|
||||||
|
pub nsfw: bool,
|
||||||
|
pub section: Option<String>,
|
||||||
|
pub images_count: i64,
|
||||||
|
pub in_gallery: bool,
|
||||||
|
pub is_ad: bool,
|
||||||
|
pub include_album_ads: bool,
|
||||||
|
pub is_album: bool,
|
||||||
|
pub images: Vec<ImageInfoData>,
|
||||||
|
pub ad_config: AdConfig,
|
||||||
|
}
|
||||||
|
|
||||||
|
#[derive(Debug, Serialize, Deserialize, PartialEq, Eq, Clone)]
|
||||||
|
#[serde(untagged)]
|
||||||
|
pub enum AccountId {
|
||||||
|
String(String),
|
||||||
|
Int(i64),
|
||||||
|
}
|
||||||
|
|
||||||
|
#[derive(Debug, Serialize, Deserialize, PartialEq, Eq, Clone)]
|
||||||
|
pub struct AdConfig {
|
||||||
|
#[serde(rename = "safeFlags")]
|
||||||
|
pub safe_flags: Vec<String>,
|
||||||
|
#[serde(rename = "highRiskFlags")]
|
||||||
|
pub high_risk_flags: Vec<String>,
|
||||||
|
#[serde(rename = "unsafeFlags")]
|
||||||
|
pub unsafe_flags: Vec<String>,
|
||||||
|
#[serde(rename = "wallUnsafeFlags")]
|
||||||
|
pub wall_unsafe_flags: Vec<String>,
|
||||||
|
#[serde(rename = "showsAds")]
|
||||||
|
pub shows_ads: bool,
|
||||||
|
#[serde(rename = "showAdLevel")]
|
||||||
|
pub show_ad_level: i64,
|
||||||
|
}
|
|
@ -0,0 +1,25 @@
|
||||||
|
macro_rules! api_url (
|
||||||
|
($path: expr) => (
|
||||||
|
format!("{}{}", "https://api.imgur.com/3/", $path)
|
||||||
|
);
|
||||||
|
);
|
||||||
|
|
||||||
|
use std::fmt;
|
||||||
|
|
||||||
|
pub(crate) use api_url;
|
||||||
|
use reqwest::Client;
|
||||||
|
|
||||||
|
/// Imgur Client
|
||||||
|
#[derive(Clone)]
|
||||||
|
pub struct ImgurClient {
|
||||||
|
/// Imgur API Client ID
|
||||||
|
pub client_id: String,
|
||||||
|
/// HTTP Client
|
||||||
|
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)
|
||||||
|
}
|
||||||
|
}
|
|
@ -0,0 +1,48 @@
|
||||||
|
use serde::{Deserialize, Serialize};
|
||||||
|
|
||||||
|
/// Image Info Response
|
||||||
|
#[derive(Debug, Serialize, Deserialize, PartialEq, Eq, Clone)]
|
||||||
|
pub struct ImageInfo {
|
||||||
|
/// Image Data
|
||||||
|
pub data: ImageInfoData,
|
||||||
|
/// Request processed success or not.
|
||||||
|
pub success: bool,
|
||||||
|
/// HTTP status code from API request.
|
||||||
|
pub status: i32,
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Image Info Reponse (`data` json)
|
||||||
|
#[derive(Debug, Serialize, Deserialize, PartialEq, Eq, Clone)]
|
||||||
|
pub struct ImageInfoData {
|
||||||
|
/// Image ID
|
||||||
|
/// e.g. `iDYNKJq`
|
||||||
|
pub id: String,
|
||||||
|
/// Image title
|
||||||
|
pub title: Option<String>,
|
||||||
|
/// Description of this image
|
||||||
|
pub description: Option<String>,
|
||||||
|
/// Image uploaded time
|
||||||
|
pub datetime: i32,
|
||||||
|
/// Image type
|
||||||
|
/// e.g. `image/png`
|
||||||
|
#[serde(rename = "type")]
|
||||||
|
pub img_type: String,
|
||||||
|
/// If image if animated (gif, etc)
|
||||||
|
pub animated: bool,
|
||||||
|
/// Width of this image
|
||||||
|
pub width: i32,
|
||||||
|
/// Height of this image
|
||||||
|
pub height: i32,
|
||||||
|
/// Image size in bytes
|
||||||
|
pub size: i32,
|
||||||
|
/// Unique image views
|
||||||
|
pub views: i32,
|
||||||
|
/// Bandwidth used by this image
|
||||||
|
pub bandwidth: i64,
|
||||||
|
/// If image is added to favorite
|
||||||
|
pub favorite: bool,
|
||||||
|
/// Delete hash (only show after image upload)
|
||||||
|
pub deletehash: Option<String>,
|
||||||
|
/// Link of this image
|
||||||
|
pub link: String,
|
||||||
|
}
|
|
@ -0,0 +1,148 @@
|
||||||
|
mod album_type;
|
||||||
|
mod client;
|
||||||
|
mod image_type;
|
||||||
|
mod requests;
|
||||||
|
mod send_api_request;
|
||||||
|
|
||||||
|
pub use album_type::*;
|
||||||
|
pub(crate) use client::api_url;
|
||||||
|
pub use client::ImgurClient;
|
||||||
|
pub use image_type::*;
|
||||||
|
pub use send_api_request::*;
|
||||||
|
use url::Url;
|
||||||
|
|
||||||
|
use crate::{Error, Result};
|
||||||
|
|
||||||
|
impl ImgurClient {
|
||||||
|
/// Create a new Imgur Client
|
||||||
|
/// ```
|
||||||
|
/// use imgurs::ImgurClient;
|
||||||
|
///
|
||||||
|
/// let client = ImgurClient::new("3e3ce0d7ac14d56");
|
||||||
|
/// ```
|
||||||
|
pub fn new(client_id: &str) -> Self {
|
||||||
|
let client_id = client_id.to_string();
|
||||||
|
let client = reqwest::Client::new();
|
||||||
|
ImgurClient { client_id, client }
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Create a new Imgur Client with the provided `reqwest::Client`
|
||||||
|
///
|
||||||
|
/// This allows for customization of the http client settings like timeout or the user agent.
|
||||||
|
/// ```
|
||||||
|
/// use imgurs::ImgurClient;
|
||||||
|
/// use reqwest::Client;
|
||||||
|
///
|
||||||
|
/// let http_client = Client::builder().build().unwrap();
|
||||||
|
///
|
||||||
|
/// let client = ImgurClient::with_http_client("3e3ce0d7ac14d56", http_client);
|
||||||
|
/// ```
|
||||||
|
pub fn with_http_client(client_id: &str, http_client: reqwest::Client) -> Self {
|
||||||
|
let client_id = client_id.to_string();
|
||||||
|
ImgurClient {
|
||||||
|
client_id,
|
||||||
|
client: http_client,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Upload image to Imgur
|
||||||
|
/// ```
|
||||||
|
/// use imgurs::ImgurClient;
|
||||||
|
///
|
||||||
|
/// #[tokio::main]
|
||||||
|
/// async fn main() {
|
||||||
|
/// let client = ImgurClient::new("3e3ce0d7ac14d56");
|
||||||
|
///
|
||||||
|
/// client
|
||||||
|
/// .upload_image("https://i.imgur.com/lFaGr1x.png")
|
||||||
|
/// .await
|
||||||
|
/// .expect("upload image");
|
||||||
|
/// }
|
||||||
|
/// ```
|
||||||
|
pub async fn upload_image(&self, path: &str) -> Result<ImageInfo> {
|
||||||
|
use base64::prelude::{Engine, BASE64_STANDARD};
|
||||||
|
|
||||||
|
let mut image = path.to_string();
|
||||||
|
|
||||||
|
// check if the specified file exists if not then check if it is a url
|
||||||
|
if std::path::Path::new(path).exists() {
|
||||||
|
let bytes = std::fs::read(path)?;
|
||||||
|
image = BASE64_STANDARD.encode(bytes)
|
||||||
|
}
|
||||||
|
// validate url adress
|
||||||
|
else if Url::parse(path).is_err() {
|
||||||
|
Err(Error::InvalidUrlOrFile(path.to_string()))?;
|
||||||
|
}
|
||||||
|
|
||||||
|
requests::upload_image(self, image).await
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Delete image from Imgur
|
||||||
|
/// ```
|
||||||
|
/// use imgurs::ImgurClient;
|
||||||
|
///
|
||||||
|
/// #[tokio::main]
|
||||||
|
/// async fn main() {
|
||||||
|
/// let client = ImgurClient::new("3e3ce0d7ac14d56");
|
||||||
|
///
|
||||||
|
/// let image = client
|
||||||
|
/// .upload_image("https://i.imgur.com/lFaGr1x.png")
|
||||||
|
/// .await
|
||||||
|
/// .expect("upload image");
|
||||||
|
/// let deletehash = image.data.deletehash.unwrap();
|
||||||
|
///
|
||||||
|
/// client
|
||||||
|
/// .delete_image(&deletehash)
|
||||||
|
/// .await
|
||||||
|
/// .expect("delete image");
|
||||||
|
/// }
|
||||||
|
/// ```
|
||||||
|
pub async fn delete_image(&self, delete_hash: &str) -> Result<()> {
|
||||||
|
requests::delete_image(self, delete_hash).await
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Get Rame Limit of this Imgur Client
|
||||||
|
/// ```
|
||||||
|
/// use imgurs::ImgurClient;
|
||||||
|
///
|
||||||
|
/// #[tokio::main]
|
||||||
|
/// async fn main() {
|
||||||
|
/// let client = ImgurClient::new("3e3ce0d7ac14d56");
|
||||||
|
///
|
||||||
|
/// client.rate_limit().await.expect("get rate limit");
|
||||||
|
/// }
|
||||||
|
/// ```
|
||||||
|
pub async fn rate_limit(&self) -> Result<requests::RateLimitInfo> {
|
||||||
|
requests::rate_limit(self).await
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Get image info from a Imgur
|
||||||
|
/// ```
|
||||||
|
/// use imgurs::ImgurClient;
|
||||||
|
///
|
||||||
|
/// #[tokio::main]
|
||||||
|
/// async fn main() {
|
||||||
|
/// let client = ImgurClient::new("3e3ce0d7ac14d56");
|
||||||
|
///
|
||||||
|
/// client.image_info("lFaGr1x").await.expect("delete image");
|
||||||
|
/// }
|
||||||
|
/// ```
|
||||||
|
pub async fn image_info(&self, id: &str) -> Result<ImageInfo> {
|
||||||
|
requests::get_image(self, id).await
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Get album info from a Imgur
|
||||||
|
/// ```no_run
|
||||||
|
/// use imgurs::ImgurClient;
|
||||||
|
///
|
||||||
|
/// #[tokio::main]
|
||||||
|
/// async fn main() {
|
||||||
|
/// let client = ImgurClient::new("3e3ce0d7ac14d56");
|
||||||
|
///
|
||||||
|
/// client.album_info("id").await.expect("get album info");
|
||||||
|
/// }
|
||||||
|
/// ```
|
||||||
|
pub async fn album_info(&self, id: &str) -> Result<AlbumInfo> {
|
||||||
|
requests::get_album(self, id).await
|
||||||
|
}
|
||||||
|
}
|
|
@ -1,10 +1,8 @@
|
||||||
use std::io;
|
|
||||||
|
|
||||||
use reqwest::Method;
|
use reqwest::Method;
|
||||||
|
|
||||||
use super::{client::api_url, send_api_request, ImgurClient};
|
use crate::{api_url, send_api_request, Error, ImgurClient, Result};
|
||||||
|
|
||||||
pub async fn delete_image(client: &ImgurClient, delete_hash: &str) -> anyhow::Result<()> {
|
pub async fn delete_image(client: &ImgurClient, delete_hash: &str) -> Result<()> {
|
||||||
// get imgur api url
|
// get imgur api url
|
||||||
let uri = api_url!(format!("image/{delete_hash}"));
|
let uri = api_url!(format!("image/{delete_hash}"));
|
||||||
|
|
||||||
|
@ -16,18 +14,9 @@ pub async fn delete_image(client: &ImgurClient, delete_hash: &str) -> anyhow::Re
|
||||||
|
|
||||||
// check if an error has occurred
|
// 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?;
|
let body = res.text().await?;
|
||||||
|
|
||||||
if body.chars().count() > 30 {
|
Err(Error::ApiError(status.as_u16(), body))?;
|
||||||
body = "body is too length".to_string()
|
|
||||||
}
|
|
||||||
|
|
||||||
let err = io::Error::new(
|
|
||||||
io::ErrorKind::Other,
|
|
||||||
format!("server returned non-successful status code = {status}, body = {body}"),
|
|
||||||
);
|
|
||||||
|
|
||||||
return Err(err.into());
|
|
||||||
}
|
}
|
||||||
|
|
||||||
Ok(())
|
Ok(())
|
|
@ -0,0 +1,24 @@
|
||||||
|
use reqwest::Method;
|
||||||
|
|
||||||
|
use crate::{api_url, send_api_request, AlbumInfo, Error, ImgurClient, Result};
|
||||||
|
|
||||||
|
pub async fn get_album(client: &ImgurClient, album: &str) -> Result<AlbumInfo> {
|
||||||
|
// get imgur api url
|
||||||
|
let uri = api_url!(format!("album/{album}"));
|
||||||
|
|
||||||
|
// send request to imgur api
|
||||||
|
let res = send_api_request(client, Method::GET, uri, None).await?;
|
||||||
|
|
||||||
|
// get response http code
|
||||||
|
let status = res.status();
|
||||||
|
|
||||||
|
// check if an error has occurred
|
||||||
|
if status.is_client_error() || status.is_server_error() {
|
||||||
|
let body = res.text().await?;
|
||||||
|
|
||||||
|
return Err(Error::ApiError(status.as_u16(), body));
|
||||||
|
}
|
||||||
|
|
||||||
|
// return `ImageInfo`
|
||||||
|
Ok(res.json().await?)
|
||||||
|
}
|
|
@ -0,0 +1,24 @@
|
||||||
|
use reqwest::Method;
|
||||||
|
|
||||||
|
use crate::{api_url, send_api_request, Error, ImageInfo, ImgurClient, Result};
|
||||||
|
|
||||||
|
pub async fn get_image(client: &ImgurClient, image: &str) -> Result<ImageInfo> {
|
||||||
|
// get imgur api url
|
||||||
|
let uri = api_url!(format!("image/{image}"));
|
||||||
|
|
||||||
|
// send request to imgur api
|
||||||
|
let res = send_api_request(client, Method::GET, uri, None).await?;
|
||||||
|
|
||||||
|
// get response http code
|
||||||
|
let status = res.status();
|
||||||
|
|
||||||
|
// check if an error has occurred
|
||||||
|
if status.is_client_error() || status.is_server_error() {
|
||||||
|
let body = res.text().await?;
|
||||||
|
|
||||||
|
return Err(Error::ApiError(status.as_u16(), body));
|
||||||
|
}
|
||||||
|
|
||||||
|
// return `ImageInfo`
|
||||||
|
Ok(res.json().await?)
|
||||||
|
}
|
|
@ -0,0 +1,11 @@
|
||||||
|
mod delete_image;
|
||||||
|
mod get_album;
|
||||||
|
mod get_image;
|
||||||
|
mod rate_limit;
|
||||||
|
mod upload_image;
|
||||||
|
|
||||||
|
pub use delete_image::*;
|
||||||
|
pub use get_album::*;
|
||||||
|
pub use get_image::*;
|
||||||
|
pub use rate_limit::*;
|
||||||
|
pub use upload_image::*;
|
|
@ -1,9 +1,7 @@
|
||||||
use std::io;
|
|
||||||
|
|
||||||
use reqwest::Method;
|
use reqwest::Method;
|
||||||
use serde::{Deserialize, Serialize};
|
use serde::{Deserialize, Serialize};
|
||||||
|
|
||||||
use super::{client::api_url, send_api_request, ImgurClient};
|
use crate::{api_url, send_api_request, Error, ImgurClient, Result};
|
||||||
|
|
||||||
#[derive(Debug, Serialize, Deserialize)]
|
#[derive(Debug, Serialize, Deserialize)]
|
||||||
pub struct RateLimitInfo {
|
pub struct RateLimitInfo {
|
||||||
|
@ -26,7 +24,7 @@ pub struct RateLimitData {
|
||||||
pub client_remaining: i32,
|
pub client_remaining: i32,
|
||||||
}
|
}
|
||||||
|
|
||||||
pub async fn rate_limit(client: &ImgurClient) -> anyhow::Result<RateLimitInfo> {
|
pub async fn rate_limit(client: &ImgurClient) -> Result<RateLimitInfo> {
|
||||||
// get imgur api url
|
// get imgur api url
|
||||||
let uri = api_url!("credits");
|
let uri = api_url!("credits");
|
||||||
|
|
||||||
|
@ -40,14 +38,9 @@ pub async fn rate_limit(client: &ImgurClient) -> anyhow::Result<RateLimitInfo> {
|
||||||
if status.is_client_error() || status.is_server_error() {
|
if status.is_client_error() || status.is_server_error() {
|
||||||
let body = res.text().await?;
|
let body = res.text().await?;
|
||||||
|
|
||||||
let err = io::Error::new(
|
return Err(Error::ApiError(status.as_u16(), body));
|
||||||
io::ErrorKind::Other,
|
|
||||||
format!("server returned non-successful status code = {status}, body = {body}"),
|
|
||||||
);
|
|
||||||
|
|
||||||
Err(err.into())
|
|
||||||
} else {
|
|
||||||
let content = res.json::<RateLimitInfo>().await?;
|
|
||||||
Ok(content)
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// return `RateLimitInfo`
|
||||||
|
Ok(res.json().await?)
|
||||||
}
|
}
|
|
@ -1,10 +1,10 @@
|
||||||
use std::{collections::HashMap, io};
|
use std::collections::HashMap;
|
||||||
|
|
||||||
use reqwest::Method;
|
use reqwest::Method;
|
||||||
|
|
||||||
use super::{client::api_url, send_api_request, ImageInfo, ImgurClient};
|
use crate::{api_url, send_api_request, Error, ImageInfo, ImgurClient, Result};
|
||||||
|
|
||||||
pub async fn upload_image(client: &ImgurClient, image: String) -> anyhow::Result<ImageInfo> {
|
pub async fn upload_image(client: &ImgurClient, image: String) -> Result<ImageInfo> {
|
||||||
// create http form (hashmap)
|
// create http form (hashmap)
|
||||||
let mut form = HashMap::new();
|
let mut form = HashMap::new();
|
||||||
// insert image to form
|
// insert image to form
|
||||||
|
@ -21,20 +21,16 @@ pub async fn upload_image(client: &ImgurClient, image: String) -> anyhow::Result
|
||||||
|
|
||||||
// check if an error has occurred
|
// 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?;
|
let body = res.text().await?;
|
||||||
|
|
||||||
if body.chars().count() > 200 {
|
// if body is too long do not return it (imgur sometimes returns whole Request)
|
||||||
body = "server returned too long".to_string()
|
if body.chars().count() > 50 {
|
||||||
|
Err(Error::ApiErrorBodyTooLong(status.as_u16()))?;
|
||||||
}
|
}
|
||||||
|
|
||||||
let err = io::Error::new(
|
return Err(Error::ApiError(status.as_u16(), body));
|
||||||
io::ErrorKind::Other,
|
|
||||||
format!("server returned non-successful status code = {status}, body = {body}"),
|
|
||||||
);
|
|
||||||
|
|
||||||
Err(err.into())
|
|
||||||
} else {
|
|
||||||
let content: ImageInfo = res.json().await?;
|
|
||||||
Ok(content)
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// return `ImageInfo`
|
||||||
|
Ok(res.json().await?)
|
||||||
}
|
}
|
|
@ -0,0 +1,38 @@
|
||||||
|
use std::collections::HashMap;
|
||||||
|
|
||||||
|
use reqwest::{Method, Response};
|
||||||
|
|
||||||
|
use crate::{ImgurClient, Result};
|
||||||
|
|
||||||
|
/// Send request to a Imgur API
|
||||||
|
pub async fn send_api_request(
|
||||||
|
config: &ImgurClient,
|
||||||
|
method: Method,
|
||||||
|
uri: String,
|
||||||
|
form: Option<HashMap<&str, String>>,
|
||||||
|
) -> Result<Response> {
|
||||||
|
// get http client
|
||||||
|
let client = &config.client;
|
||||||
|
|
||||||
|
// create Request buidler
|
||||||
|
let mut req = client.request(method, uri.as_str());
|
||||||
|
|
||||||
|
// add `Authorization` and `User-Agent` to Request
|
||||||
|
req = req
|
||||||
|
.header("Authorization", format!("Client-ID {}", config.client_id))
|
||||||
|
.header(
|
||||||
|
"User-Agent",
|
||||||
|
format!("Imgur/{:?}", env!("CARGO_PKG_VERSION")),
|
||||||
|
);
|
||||||
|
|
||||||
|
// if exists add HashMap to Request
|
||||||
|
if form.is_some() {
|
||||||
|
req = req.form(&form.unwrap())
|
||||||
|
}
|
||||||
|
|
||||||
|
// build Request
|
||||||
|
let req = req.build()?;
|
||||||
|
|
||||||
|
// send Request
|
||||||
|
Ok(client.execute(req).await?)
|
||||||
|
}
|
82
src/lib.rs
82
src/lib.rs
|
@ -1,3 +1,11 @@
|
||||||
|
//! [![github]](https://github.com/M3DZIK/imgurs)
|
||||||
|
//! [![crates-io]](https://crates.io/crates/imgurs)
|
||||||
|
//! [![docs-rs]](https://docs.rs/imgurs)
|
||||||
|
//!
|
||||||
|
//! [github]: https://img.shields.io/badge/github-8da0cb?style=for-the-badge&labelColor=555555&logo=github
|
||||||
|
//! [crates-io]: https://img.shields.io/badge/crates.io-fc8d62?style=for-the-badge&labelColor=555555&logo=rust
|
||||||
|
//! [docs-rs]: https://img.shields.io/badge/docs.rs-66c2a5?style=for-the-badge&labelColor=555555&logo=docs.rs
|
||||||
|
//!
|
||||||
//! This crate is an unofficial implementation of the [Imgur API](https://imgur.com) in Rust.
|
//! This crate is an unofficial implementation of the [Imgur API](https://imgur.com) in Rust.
|
||||||
//!
|
//!
|
||||||
//! # Installation
|
//! # Installation
|
||||||
|
@ -11,46 +19,84 @@
|
||||||
//! your application, simply add it to your project's `Cargo.toml`.
|
//! your application, simply add it to your project's `Cargo.toml`.
|
||||||
//! ```toml
|
//! ```toml
|
||||||
//! [dependencies]
|
//! [dependencies]
|
||||||
//! imgurs = "0.7.3"
|
//! imgurs = "0.11.3"
|
||||||
//! ```
|
//! ```
|
||||||
//!
|
//!
|
||||||
//! # Example Usage
|
//! # Example Usage
|
||||||
//!
|
//!
|
||||||
//! ## Create new ImgurClient
|
//! ## Create new ImgurClient
|
||||||
//! ```ignore
|
//! ```
|
||||||
//! use imgurs::ImgurClient;
|
//! use imgurs::ImgurClient;
|
||||||
//!
|
//!
|
||||||
//! let client = ImgurClient::new("client id");
|
//! let client = ImgurClient::new("client_id");
|
||||||
//! ```
|
//! ```
|
||||||
//!
|
//!
|
||||||
//! ## Image Upload
|
//! ## Image Upload
|
||||||
//! ```ignore
|
//! ```no_run
|
||||||
//! // From URL
|
//! use imgurs::ImgurClient;
|
||||||
//! let info = client.upload_image("https://i.imgur.com/lFaGr1x.png").await?;
|
|
||||||
//!
|
//!
|
||||||
//! // From File
|
//! #[tokio::main]
|
||||||
//! let info = client.upload_image("path/to/image.png").await?;
|
//! async fn main() {
|
||||||
|
//! let client = ImgurClient::new("client_id");
|
||||||
|
//!
|
||||||
|
//! // From URL
|
||||||
|
//! let info = client
|
||||||
|
//! .upload_image("https://i.imgur.com/lFaGr1x.png")
|
||||||
|
//! .await
|
||||||
|
//! .unwrap();
|
||||||
|
//! println!("{:?}", info);
|
||||||
|
//!
|
||||||
|
//! // From File
|
||||||
|
//! let info = client.upload_image("path/to/file.png").await.unwrap();
|
||||||
|
//! println!("{:?}", info);
|
||||||
|
//! }
|
||||||
//! ```
|
//! ```
|
||||||
//!
|
//!
|
||||||
//! ## Delete Image
|
//! ## Delete Image
|
||||||
//! ```ignore
|
//! ```no_run
|
||||||
//! client.delete_image("SuPeRsEcReTDeLeTeHaSh").await?; // delete hash
|
//! use imgurs::ImgurClient;
|
||||||
|
//!
|
||||||
|
//! #[tokio::main]
|
||||||
|
//! async fn main() {
|
||||||
|
//! let client = ImgurClient::new("client_id");
|
||||||
|
//!
|
||||||
|
//! client.delete_image("delete_hash").await.unwrap(); // delete hash
|
||||||
|
//! }
|
||||||
//! ```
|
//! ```
|
||||||
//!
|
//!
|
||||||
//! ## Get Image Info
|
//! ## Get Image Info
|
||||||
//! ```ignore
|
//! ```no_run
|
||||||
//! let info = client.image_info("lFaGr1x").await?; // image id
|
//! use imgurs::ImgurClient;
|
||||||
//!
|
//!
|
||||||
//! println!("{:?}", info);
|
//! #[tokio::main]
|
||||||
|
//! async fn main() {
|
||||||
|
//! let client = ImgurClient::new("client_id");
|
||||||
|
//!
|
||||||
|
//! let info = client.image_info("lFaGr1x").await.unwrap(); // image id
|
||||||
|
//!
|
||||||
|
//! println!("{:?}", info);
|
||||||
|
//! }
|
||||||
//! ```
|
//! ```
|
||||||
//!
|
//!
|
||||||
//! ## Get Client RateLimit
|
//! ## Get Client RateLimit
|
||||||
//! ```ignore
|
//! ```no_run
|
||||||
//! let info = client.rate_limit.await?;
|
//! use imgurs::ImgurClient;
|
||||||
//!
|
//!
|
||||||
//! println!("{:?}", info);
|
//! #[tokio::main]
|
||||||
|
//! async fn main() {
|
||||||
|
//! let client = ImgurClient::new("client_id");
|
||||||
|
//!
|
||||||
|
//! let info = client.rate_limit().await.unwrap();
|
||||||
|
//!
|
||||||
|
//! println!("{:?}", info);
|
||||||
|
//! }
|
||||||
//! ```
|
//! ```
|
||||||
|
|
||||||
mod api;
|
mod error;
|
||||||
|
pub use error::*;
|
||||||
|
|
||||||
pub use api::*;
|
#[cfg(feature = "imgur")]
|
||||||
|
mod imgur;
|
||||||
|
|
||||||
|
#[cfg(feature = "imgur")]
|
||||||
|
pub use imgur::*;
|
||||||
|
|
19
src/main.rs
19
src/main.rs
|
@ -1,19 +0,0 @@
|
||||||
use imgurs::ImgurClient;
|
|
||||||
use simple_logger::SimpleLogger;
|
|
||||||
|
|
||||||
mod cli;
|
|
||||||
mod config;
|
|
||||||
|
|
||||||
#[tokio::main]
|
|
||||||
async fn main() {
|
|
||||||
SimpleLogger::new().init().expect("init SimpleLogger");
|
|
||||||
better_panic::install();
|
|
||||||
|
|
||||||
// parse config file
|
|
||||||
let config = config::toml::parse();
|
|
||||||
|
|
||||||
// create imgur client
|
|
||||||
let client = ImgurClient::new(&config.imgur.id);
|
|
||||||
|
|
||||||
cli::parse(client).await
|
|
||||||
}
|
|
Loading…
Reference in New Issue