Skip to content

Commit

Permalink
Add CLI help
Browse files Browse the repository at this point in the history
  • Loading branch information
moriar1 committed Dec 29, 2024
1 parent 91283a4 commit a07bc38
Show file tree
Hide file tree
Showing 2 changed files with 65 additions and 28 deletions.
26 changes: 15 additions & 11 deletions README.md
Original file line number Diff line number Diff line change
@@ -1,30 +1,34 @@
# UpSauce

UpSauce uploads your image on [linx-server](https://github.com/ZizzyDizzyMC/linx-server/) instance and
outputs links to it found on [SauceNAO](https://saucenao.com) as Markdown string, like this: [Pixiv](https://www.pixiv.net/member_illust.php?mode=medium&illust_id=61477678) | [Twitter](https://twitter.com/i/web/status/837653407900934145) | ... | [Image](https://put.icu/x2zj493c.jpeg)
UpSauce uploads your images on [linx-server](https://github.com/ZizzyDizzyMC/linx-server/) instance and
outputs links found on [SauceNAO](https://saucenao.com) as a Markdown string, formatted like this: [Pixiv](https://www.pixiv.net/member_illust.php?mode=medium&illust_id=61477678) | [Twitter](https://twitter.com/i/web/status/837653407900934145) | ... | [Image](https://put.icu/x2zj493c.jpeg)

# Usage
Sing up on [SauceNAO](https://saucenao.com) and put your API key in `config.json`:
Sign up on [SauceNAO](https://saucenao.com) to obtain your API key. Enter the linx-server instance URL, your SauceNAO API key, and optionally the source delimiter (which defaults to ` | `) in `config.json`:

```json
{
"api_key": "r4epRxaMzDdmDX"
"api_key": "r4epRxaMzDdmDX",
"linx_url": "https://put.icu",
"delim": " | "
}
```

Copy your image to upload to the git project directory
(for instance, [this](https://i.imgur.com/W42kkKS.jpg) I got from [RustNao](https://github.com/ClementTsang/RustNAO) example):
Run `upsauce` with the path to your image as a single command line argument:

```bash
cp path/to/your/image.jpg .
upsauce path/to/image.jpg
```

Then run:
Alternatively, you can use a direct link to an image (it should end with .jpg, .png, etc.). The image will be downloaded in your current working directory
(for example, [this](https://i.imgur.com/W42kkKS.jpg) I got from [RustNAO](https://github.com/ClementTsang/RustNAO) example):

```bash
cargo run -- image.jpg
upsauce https://i.imgur.com/W42kkKS.jpg
```

You will get output like this:
You will receive output like this:

```bash
Skipped ext_url: "https://chan.sankakucomplex.com/post/show/5874087" # This source is not included in the next Markdown string

Expand All @@ -36,4 +40,4 @@ To delete your file on `https://put.icu` use: `curl -H "Linx-Delete-Key: Ypzwq5t
```

> [!NOTE]
> If SauceNAO finds several links to the same site, then only the first link found is prints in Markdown string, the rest are marked as skipped.
> If SauceNAO finds several links to the same site, only the first link found will be printed in the Markdown string, the rest are marked as skipped.
67 changes: 50 additions & 17 deletions src/main.rs
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@ use core::panic;
use rustnao::HandlerBuilder;
use std::{
env::args,
path::PathBuf,
process::{Command, Stdio},
};
use url::Url;
Expand Down Expand Up @@ -46,22 +47,20 @@ fn upload(path: &str, linx_url: &str) -> Result<(String, String, String), String
Ok((direct_url.to_owned(), url.to_owned(), delete_key.to_owned()))
}

fn get_pretty_sauce(direct_url: &str, linx_file_url: &str, delim: &str) -> Result<String, String> {
// Get SauceNAO API key
let data = std::fs::read_to_string("config.json")
.map_err(|e| format!("Failed reading `config.json`: {e}"))?;
let json: serde_json::Value = serde_json::from_str(data.as_str())
.map_err(|e| format!("JSON not well formatted: {e}."))?;
let key = json["api_key"].as_str().ok_or("No api key".to_string())?;

fn get_pretty_sauce(
linx_direct_url: &str,
linx_file_url: &str,
delim: &str,
api_key: &str,
) -> Result<String, String> {
// SauceNAO request
let handle = HandlerBuilder::default()
.api_key(key)
.api_key(api_key)
.num_results(999)
.build();
handle.set_min_similarity(61.0);
let result = handle
.get_sauce_as_pretty_json(direct_url, None, None)
.get_sauce_as_pretty_json(linx_direct_url, None, None)
.map_err(|e| format!("Cannot get sauce: {e}"))?;
let json_result: serde_json::Value =
serde_json::from_str(&result).map_err(|e| format!("Failed parse SNAO JSON: {e}"))?;
Expand Down Expand Up @@ -133,7 +132,7 @@ fn check_yes_input() -> bool {

fn delete_image_request(url: &str, key: &str) -> Result<(), String> {
let del_key_str = format!("Linx-Delete-Key: {key}");
let a = ["curl", "-H", del_key_str.as_str(), "-X", "DELETE", url];
let a = ["-H", del_key_str.as_str(), "-X", "DELETE", url];

let output = Command::new("curl")
.args(a)
Expand All @@ -151,26 +150,60 @@ fn delete_image_request(url: &str, key: &str) -> Result<(), String> {
}

fn main() {
const USAGE_STR: &str = "Usage: upsauce <PATH/URL>
Options:
-h, --help Print help
-V, --version Print version
";

let arg = args().nth(1).unwrap_or_else(|| {
println!("{USAGE_STR}");
String::new()
});
let path = match arg.as_str() {
"" => return,
"--version" | "-V" => {
println!("{}", env!("CARGO_PKG_VERSION"));
return;
}
"--help" | "-h" => {
println!("{USAGE_STR}");
return;
}
_ => arg,
};

// Get SauceNAO API key, linx_url, delimiter between sources from `config.json`
let data = std::fs::read_to_string("config.json")
.unwrap_or_else(|e| panic!("Failed reading `config.json`: {e}"));
let json: serde_json::Value = serde_json::from_str(data.as_str())
.unwrap_or_else(|e| panic!("JSON not well formatted: {e}."));
let api_key = json["api_key"]
.as_str()
.unwrap_or_else(|| panic!("No SaunceNAO API key in `config.json`"));
let linx_url = json["linx_url"]
.as_str()
.unwrap_or_else(|| panic!("No linx_url in `config.json`"));
let delim = json["delim"].as_str().unwrap_or(" | "); // Delimiter between sources in Markdown string

// Get path to image from command line argument or download it if url is provided
let path = args().nth(1).expect("error: provide path/to/image"); // Local path or url to image
let path = if path.starts_with("https://") {
println!("Dowloading image from {path}");
download_image(&path).unwrap_or_else(|e| panic!("Failed downloading provided image: {e}"))
} else if !PathBuf::from(&path).exists() {
panic!("Path to file do not exists")
} else {
path
};

let delim = " | "; // Delimiter between sources in Markdown string
let linx_url = "https://put.icu"; // linx-server instance url

println!("Uploading image to {linx_url}");
let (direct_url, url, delete_key) = upload(&path, linx_url)
.unwrap_or_else(|e| panic!("Failed uploading your image on linx-server: {e}"));
// TODO: add visual feedback

println!("Searching for sauce");
// Get sauce from SauceNAO
match get_pretty_sauce(&direct_url, &url, delim) {
match get_pretty_sauce(&direct_url, &url, delim, api_key) {
Ok(pretty_sauce) => println!("\n{pretty_sauce}\n{direct_url}\n"),
Err(e) => {
println!("Failed sauce fetching. {e}\nDelete image uploaded on `{linx_url}`? [y/n]");
Expand Down

0 comments on commit a07bc38

Please sign in to comment.