From af1f264789b83ba55ba22252cbcce6d0c37736ee Mon Sep 17 00:00:00 2001 From: Ritchie Cunningham Date: Tue, 22 Apr 2025 17:58:11 +0100 Subject: [PATCH] [Add] Initial commit. --- README.md | 111 +++++++++++++++++++- imgbb | 303 ++++++++++++++++++++++++++++++++++++++++++++++++++++++ 2 files changed, 412 insertions(+), 2 deletions(-) create mode 100755 imgbb diff --git a/README.md b/README.md index 11c7571..3a687ed 100644 --- a/README.md +++ b/README.md @@ -1,3 +1,110 @@ -# imgbb-uploader +# ImgBB Upload Script (`imgbb`) -Small script to upload an image from clipboard or file to imgbb.com. URL is then inserted directly into clipboard ready to be pasted to IRC or.. wherever. \ No newline at end of file +[![License: GPL v3](https://img.shields.io/badge/License-GPLv3-blue.svg)](https://www.gnu.org/licenses/gpl-3.0) A simple Bash script to quickly upload images from the system clipboard (X11) or a specified file directly to [ImgBB](https://imgbb.com/) using their v1 API. It retrieves the direct image URL, prints it to STDOUT, and copies it to the X11 clipboard. + +Ideal for quickly sharing screenshots or images in environments like IRC without needing to manually use the website interface. + +**Author:** Ritchie Cunningham +**Version:** 1.0 (as of 22/04/2025) + +## Features + +* Upload images directly from the clipboard (PNG or JPEG). +* Upload images directly from a file path. +* Set an optional auto-deletion expiration time (e.g., `5m`, `2h`, `7d`, `0` for none). +* Specify a custom filename for the uploaded image on ImgBB. +* Optionally output and copy the URL in Markdown format. +* Copies the resulting URL to the X11 clipboard. +* Provides desktop notifications for progress and success/failure (optional). + +## Dependencies + +Make sure you have the following command-line tools installed: + +* **curl:** Used for making the HTTP API request. + ```bash + sudo apt install curl # Debian. + ``` +* **jq:** Used for parsing the JSON API response. + ```bash + sudo apt install jq # Debian. + ``` +* **xclip:** Used for accessing the X11 clipboard. **This script will not work on Wayland sessions.** + ```bash + sudo apt install xclip # Debian. + ``` +* **notify-send (Optional):** Used for desktop notifications. The script works without it but won't show popups. + ```bash + sudo apt install notify-send # Debian (often in libnotify-bin). + ``` + +## Installation + +1. **Clone the repository:** + ```bash + git clone git@git.ritchiecunningham.co.uk:Rtch/imgbb-uploader.git + cd imgbb-uploader + ``` +2. **Make the script executable:** + ```bash + chmod +x imgbb + ``` +3. **Place in your PATH (Recommended):** Create a symbolic link to the script from a directory in your `$PATH` for easy execution (e.g., `~/.local/bin`, ensure this is in your `$PATH`). + ```bash + mkdir -p ~/.local/bin + ln -s "$(pwd)/imgbb" ~/.local/bin/imgbb + ``` + Now you can just run `imgbb` from your terminal. + +## Configuration + +This script requires a **free API key** from ImgBB: + +1. Go to [https://api.imgbb.com/](https://api.imgbb.com/) and register or log in to get your key. +2. Store the key in `.config/imgbb/uploader/api_key`. + * **File** Create the directory and file, then paste *only* your API key inside: + ```bash + mkdir -p ~/.config/imgbb_uploader + nano ~/.config/imgbb_uploader/api_key + # Paste your key, save the file. + # Set permissions so only you can read it: + chmod 600 ~/.config/imgbb_uploader/api_key + ``` + +## Usage +**Options:** + +* `[filepath]` : Optional path to an image file to upload. If omitted, uses the clipboard content. +* `-e, --expire DURATION`: Set auto-deletion timeout. DURATION is a number followed by `s`(econds), `m`(inutes), `h`(ours), or `d`(ays) (e.g., `5m`, `2h`, `7d`, `300s`). Range: 60s-180d. Use `0`, `none`, or `never` for no expiration (overrides the default). Default expiration is 2 hours (7200s) if this option is not used. +* `-n, --name NAME`: Set a custom filename for the uploaded image on ImgBB. +* `--markdown`: Output and copy the URL in Markdown image format: `![](URL)` +* `-h, --help`: Show the help message and exit. + +**Examples:** + +```bash +# Upload image from clipboard, expire in 2 hours (default) +imgbb + +# Upload specific image file, expire in 2 hours +imgbb screenshot.png + +# Upload from clipboard, expire in 10 minutes +imgbb -e 10m + +# Upload from clipboard, never expire +imgbb -e 0 + +# Upload file, give it a name on ImgBB, get Markdown output/copy +imgbb -n "Cool Diagram" --markdown diagram.jpg + +# Show help +imgbb -h + +# Notes + +Currently relies on xclip and therefore only works reliably under X11 sessions. Wayland support would require adding logic to use wl-clipboard. + +# License + +This project is licensed under the GPL License. See the LICENSE file for details. (Action: You need to add a file named LICENSE to your repository containing the text of the GPL, likely GPLv3). diff --git a/imgbb b/imgbb new file mode 100755 index 0000000..7c7dbeb --- /dev/null +++ b/imgbb @@ -0,0 +1,303 @@ +#!/bin/bash +# ----------------------------------------------------------------------------- +# Script Name: imgbb +# Description: Uploads an image from the system clipboard or a specified file +# to ImgBB (imgbb.com) using their V1 API. Retrieves the direct +# image URL, prints it to stdout, and copies it to the X11 clipboard. +# Author: Ritchie Cunningham +# License: GPL License +# Version: 3.0 +# Date: 22/04/2025 +# ----------------------------------------------------------------------------- +# Usage Examples: +# +# Examples: +# imgbb # Upload clipboard, expire 2h. +# imgbb my_image.png # Upload file, expire 2h (or whatever you declare expire_seconds to). +# imgbb -e 10m # Upload clipboard, expire 10m. +# imgbb -e 0 # Upload clipboard, never expire. +# imgbb -n "Diagram" --markdown img.jpg. +# imgbb -h # See help for more information. +# ----------------------------------------------------------------------------- +# Dependencies: +# - bash (v4+ required for =~, (( )), BASH_REMATCH) +# - curl: (e.g., sudo apt install curl) +# - jq: (e.g., sudo apt install jq) +# - xclip: (X11 clipboard access) (e.g., sudo apt install xclip) +# - notify-send: (Optional, for desktop notifications) (e.g., sudo apt install notify-send) +# - Coreutils: (mktemp, basename, rm, cat, echo, etc. - usually standard) +# ----------------------------------------------------------------------------- +# Configuration: +# Requires an ImgBB API key (v1). Get one free: https://api.imgbb.com/ +# Store the key: +# - File: ~/.config/imgbb_uploader/api_key (chmod 600 recommended) +# (Create directory: mkdir -p ~/.config/imgbb_uploader) +# ----------------------------------------------------------------------------- +# Notes: +# - Uses 'xclip', works on X11 sessions only. Wayland requires 'wl-clipboard'. +# ----------------------------------------------------------------------------- + +# === Default Configuration & Argument Parsing. === +API_KEY_FILE="$HOME/.config/imgbb_uploader/api_key" +filepath="" +expire_seconds="7200" # 2h - Set to "" for no expiry. or use flag -e 0, never or none. +custom_name="" +markdown_mode="false" + +print_usage() { + echo "Usage: $(basename "$0") [options] [filepath]" + echo "Uploads image from clipboard (default) or filepath to ImgBB." + echo "" + echo "Options:" + echo " [filepath] Optional path to an image file to upload." + echo " -e, --expire DURATION Set auto-deletion timeout. DURATION is a number" + echo " followed by s(econds), m(inutes), h(ours), or d(ays)." + echo " Default unit is minutes if unspecified." + echo " '0', 'none', 'never' to override default expiry." + echo " -n, --name NAME Set a custom filename for the uploaded image." + echo " --markdown Output/copy the URL in Markdown image format." + echo " -h, --help Show this help message." +} + +# Parse command-line options. +while [[ $# -gt 0 ]]; do + key="$1" + case $key in + -e|--expire) + expire_input="$2" # Usr input. + # Check for 'no expiry value'. + if [[ "$expire_input" == "0" || "$expire_input" == "never" || "$expire_input" == 'none' ]]; then + expire_seconds="" # Unset for no expiration. + echo "Setting NO expiration." + else + # Proceed with parsing regular. + value="" unit="" seconds="" + + # Regex to capture the number part and optional unit part (s,m,h,d) + if [[ "$expire_input" =~ ^([0-9]+)([smhd]?)$ ]]; then + value="${BASH_REMATCH[1]}" # The numeric part. + unit="${BASH_REMATCH[2]}" # The unit part. + + # Default to minutes if no unit was provided. + if [ -z "$unit" ]; then unit="s"; fi + + # Calculate total seconds based on the unit. + case "$unit" in + s) seconds=$((value)) ;; + m) seconds=$((value * 60)) ;; + h) seconds=$((value * 3600)) ;; # 60*60. + d) seconds=$((value * 86400)) ;; # 60*60*24. + *) # Not really requried given the regex, but hey-ho. + echo "Error: Internal error parsing unit '$unit' from '$expire_input'." + exit 1 ;; + esac + + # Validate against ImgBB limits (60 seconds to 15552000 seconds / 180 days). + if (( seconds < 60 )) || (( seconds > 15552000 )); then + echo "Error: Calculated expiration ($seconds seconds) is outside of ImgBB's allowed range (60s - 15552000s)." >&2 + exit 1 + fi + + # Store the final result. + expire_seconds="$seconds" + echo "Expiration set to $expire_seconds seconds ($expire_input)" + else + # Someone did funky input. Tell them to stop that! + echo "Error: Invalid expiration format '$expire_input'." >&2 + echo "Use a number optionally followed by s, m, h or d OR use 0/none/never (e.g., 300, 5m, 2h, 7d)." >&2 + print_usage # Maybe they need help. + exit 1 + fi + fi + shift + shift + ;; + -n|--name) + custom_name="$2" + shift + shift + ;; + --markdown) + markdown_mode="true" + shift + ;; + -h|--help) + print_usage + exit 0 + ;; + -*) + # Unknown option. + echo "Error: Unknown option '$1'" >&2 + print_usage + exit 1 + ;; + *) + # Assume it's the filepath (only one allowed). + if [ -n "$filepath" ]; then + echo "Error: Multiple filepaths provided ($filepath, $1). Only one allowed." >&2 + print_usage + exit 1 + fi + filepath="$1" + shift + ;; + esac +done + +# Check if filepath exists and is readable if provided. +if [ -n "$filepath" ] && [ ! -r "$filepath" ]; then + echo "Error: Cannot read file '$filepath'" >&2 + exit 1 +fi + +# === Read API Key. === +API_KEY="" +if [[ -f "$API_KEY_FILE" ]]; then + API_KEY=$(cat "$API_KEY_FILE") +elif [[ -n "$IMGBB_API_KEY" ]]; then + API_KEY="$IMGBB_API_KEY" +fi + +# Check if API key is actually set. +if [ -z "$API_KEY" ]; then + # Use function defined below if notify-send exists. + notify_cmd -u critical "ImgBB Upload Error" "API Key not found." &>/dev/null + echo "Error: API Key not found." >&2 + echo "Please store your key in '$API_KEY_FILE' or set the IMGBB_API_KEY environment variable." >&2 + exit 1 +fi + +# === Check Dependencies. === +check_command() { + if ! command -v "$1" &> /dev/null; then + notify_cmd -u critical "ImgBB Upload Error" "'$1' command not found. Please install it." &>/dev/null + echo "Error: '$1' command not found. Please install it (e.g., sudo apt install $1)." >&2 + exit 1 + fi +} +# Define notify_cmd first based on whether notify-send exists. +if ! command -v notify-send &> /dev/null; then + notify_cmd() { :; } # No-op if not found. + echo "Warning: notify-send not found. Desktop notifications disabled." >&2 +else + notify_cmd() { notify-send "$@"; } # Actual command if found. +fi +# Now check other dependencies. +check_command curl +check_command jq +# Only check xclip if we plan to use the clipboard. +if [ -z "$filepath" ]; then + check_command xclip +fi + +# === Main Logic. === + +TMP_IMG="" # Path to the image file to upload. +image_source_description="" +# Setup trap *only* if using clipboard mode. +if [ -z "$filepath" ]; then + # === Clipboard Input Mode. === + image_source_description="clipboard" + # Create temporary file(s). + TMP_IMG_PNG=$(mktemp --suffix=.png) + TMP_IMG_JPEG=$(mktemp --suffix=.jpg) + # Ensure temporary files are cleaned up on script exit. + trap 'echo "Cleaning up temp files..."; rm -f "$TMP_IMG_PNG" "$TMP_IMG_JPEG"' EXIT + + # Try extracting PNG image from clipboard. + notify_cmd "ImgBB Uploader" "Getting image from clipboard..." + if xclip -selection clipboard -t image/png -o > "$TMP_IMG_PNG" 2>/dev/null && [ -s "$TMP_IMG_PNG" ]; then + echo "Retrieved PNG image from clipboard." + TMP_IMG="$TMP_IMG_PNG" + rm -f "$TMP_IMG_JPEG" # Remove unused JPEG temp file. + else + # If PNG fails or is empty, try JPEG. + echo "PNG failed or empty, trying JPEG..." + if xclip -selection clipboard -t image/jpeg -o > "$TMP_IMG_JPEG" 2>/dev/null && [ -s "$TMP_IMG_JPEG" ]; then + echo "Retrieved JPEG image from clipboard." + TMP_IMG="$TMP_IMG_JPEG" + rm -f "$TMP_IMG_PNG" # Remove unused PNG temp file. + else + # If both fail or are empty. + notify_cmd -u critical "ImgBB Upload Error" "Could not get PNG or JPEG image data from clipboard." + echo "Error: Could not get PNG or JPEG image data from clipboard." >&2 + exit 1 + fi + fi +else + # === File Input Mode. === + image_source_description="file '$filepath'" + TMP_IMG="$filepath" # Use the provided file path directly. + echo "Using image from file: $filepath" + trap '' EXIT # Clear trap if we are not using temp files. +fi + +# Build curl options. +curl_opts=(-s -L -X POST) +curl_opts+=(--form "key=$API_KEY") +curl_opts+=(--form "image=@$TMP_IMG") + +if [ -n "$expire_seconds" ]; then + curl_opts+=(--form "expiration=$expire_seconds") +fi +if [ -n "$custom_name" ]; then + curl_opts+=(--form "name=$custom_name") + echo "Setting custom name to '$custom_name'." +fi + +# Upload the image using curl. +notify_cmd "ImgBB Uploader" "Uploading image from $image_source_description..." +response=$(curl "${curl_opts[@]}" 'https://api.imgbb.com/1/upload') + +# Check curl exit status. +if [ $? -ne 0 ]; then + notify_cmd -u critical "ImgBB Upload Error" "curl command failed during upload. Check network?" + echo "Error: curl command failed during upload. Check network connection." >&2 + exit 1 +fi + +# Parse the JSON response using jq. +# Check for overall success status from ImgBB API. +success=$(echo "$response" | jq -r '.success') + +if [ "$success" != "true" ]; then + error_msg=$(echo "$response" | jq -r '.error.message // "Unknown API error"') + notify_cmd -u critical "ImgBB Upload Error" "API Error: $error_msg" + echo "Error: ImgBB API returned an error - $error_msg" >&2 + echo "Full response: $response" >&2 + exit 1 +fi + +# Extract the direct image URL. +image_url=$(echo "$response" | jq -r '.data.url') + +# Check if URL was successfully extracted. +if [ -z "$image_url" ] || [ "$image_url" == "null" ]; then + notify_cmd -u critical "ImgBB Upload Error" "Could not parse image URL from API response." + echo "Error: Could not parse image URL from API response." >&2 + echo "Full response: $response" >&2 + exit 1 +fi + +# Format output based on markdown flag. +output_url="$image_url" +if [ "$markdown_mode" = "true" ]; then + # Basic markdown image syntax - assumes filename is not needed for alt text here. + output_url="![](${image_url})" + echo "Formatting as Markdown." +fi + +# Output the URL to terminal and copy to clipboard. +echo "Image URL:" +echo "$output_url" +# Use xclip only if we determined we are not uploading from file (i.e., we used clipboard input) +# Or always copy? Let's always copy for now. +if command -v xclip &> /dev/null; then + echo "$output_url" | xclip -selection clipboard + notify_cmd "ImgBB Uploader" "Success! URL copied: $output_url" +else + notify_cmd "ImgBB Uploader" "Success! URL: $output_url" +fi + +# Temporary files are removed automatically by the 'trap' command on exit if they were created. +exit 0