text Untitled 3 views
#!/usr/bin/env bash

set -o pipefail

# ============================================================
#                         HASTEBIN
# ============================================================

UPLOAD_URL="https://pste.us/documents"
BASE_URL="https://pste.us"

# Catppuccin Mocha palette
BLUE="\033[38;2;137;180;250m"
CYAN="\033[38;2;137;220;235m"
GREEN="\033[38;2;166;227;161m"
MAUVE="\033[38;2;203;166;247m"
PINK="\033[38;2;245;194;231m"
RED="\033[38;2;243;139;168m"
YELLOW="\033[38;2;249;226;175m"
TEXT="\033[38;2;205;214;244m"
SUBTEXT="\033[38;2;166;173;200m"
DIM="\033[38;2;108;112;134m"
RESET="\033[0m"

TMP_RESPONSE=""
TMP_PROGRESS=""

# ------------------------------------------------------------
# Cleanup
# ------------------------------------------------------------

cleanup() {
    [[ -n "$TMP_RESPONSE" && -f "$TMP_RESPONSE" ]] && rm -f "$TMP_RESPONSE"
    [[ -n "$TMP_PROGRESS" && -f "$TMP_PROGRESS" ]] && rm -f "$TMP_PROGRESS"
}

trap cleanup EXIT
trap 'exit 130' INT TERM

# ------------------------------------------------------------
# Error
# ------------------------------------------------------------

die() {
    echo
    printf "  ${RED}✗${RESET} ${TEXT}%s${RESET}\n" "$1"
    echo
    exit 1
}

# ------------------------------------------------------------
# Dependencies
# ------------------------------------------------------------

for cmd in curl jq gum fzf; do
    command -v "$cmd" &>/dev/null ||
        die "Missing dependency: $cmd"
done

# ------------------------------------------------------------
# Arguments
# ------------------------------------------------------------

FILE_PATH="${1:-}"

case "$FILE_PATH" in
    -h|--help)
        cat <<'EOF'
Usage:
  hastebin
  hastebin <file>

Upload a file to pste.us and copy the resulting URL.
EOF
        exit 0
        ;;
esac

# ------------------------------------------------------------
# Select file
# ------------------------------------------------------------

if [[ -z "$FILE_PATH" ]]; then

    FILE_PATH=$(
        find . -maxdepth 1 -type f -printf '%f\n' |
        fzf \
            --prompt="  󰈔  " \
            --border=rounded \
            --border-label=" hastebin " \
            --border-label-pos=2 \
            --reverse \
            --header=" ↑↓ navigate  •  enter select  •  esc cancel " \
            --pointer="▸" \
            --marker="◆" \
            --color="bg+:#313244,bg:#11111b,spinner:#f5c2e7,hl:#f38ba8,fg:#cdd6f4,header:#7f849c,pointer:#a6e3a1,marker:#f5c2e7,fg+:#cdd6f4,prompt:#89b4fa,hl+:#f38a8a,border:#585b70" \
            --preview='bat --style=numbers --color=always --line-range=:80 {}' \
            --preview-window='right:55%:wrap'
    )

    [[ -n "$FILE_PATH" ]] || exit 0
fi

# ------------------------------------------------------------
# Validate
# ------------------------------------------------------------

[[ -f "$FILE_PATH" ]] ||
    die "File does not exist: $FILE_PATH"

[[ -r "$FILE_PATH" ]] ||
    die "File is not readable: $FILE_PATH"

# ------------------------------------------------------------
# File info
# ------------------------------------------------------------

FILE_NAME="$(basename "$FILE_PATH")"

FILE_BYTES=$(stat -c%s "$FILE_PATH" 2>/dev/null ||
             stat -f%z "$FILE_PATH" 2>/dev/null ||
             echo 0)

if command -v numfmt &>/dev/null; then
    FILE_SIZE=$(numfmt --to=iec --suffix=B "$FILE_BYTES")
else
    FILE_SIZE=$(du -h "$FILE_PATH" | cut -f1)
fi

FILE_TYPE=$(file -b "$FILE_PATH" 2>/dev/null || echo "Unknown")
FILE_TYPE="${FILE_TYPE%%,*}"

# Keep the type short
if (( ${#FILE_TYPE} > 35 )); then
    FILE_TYPE="${FILE_TYPE:0:32}..."
fi

# ------------------------------------------------------------
# Temporary files
# ------------------------------------------------------------

TMP_RESPONSE=$(mktemp)
TMP_PROGRESS=$(mktemp)

# ------------------------------------------------------------
# Header
# ------------------------------------------------------------

clear

echo
printf "  ${MAUVE}◆${RESET} ${TEXT}Hastebin${RESET} ${DIM}·${RESET} ${SUBTEXT}secure little file sharing${RESET}\n"
echo

printf "  ${DIM}────────────────────────────────────────────────────────${RESET}\n"
printf "  ${BLUE}󰈔${RESET}  ${TEXT}%s${RESET}\n" "$FILE_NAME"
printf "  ${DIM}size${RESET}  ${SUBTEXT}%s${RESET}    ${DIM}type${RESET}  ${SUBTEXT}%s${RESET}\n" \
    "$FILE_SIZE" \
    "$FILE_TYPE"
printf "  ${DIM}────────────────────────────────────────────────────────${RESET}\n"

echo

# ------------------------------------------------------------
# Upload indicator
# ------------------------------------------------------------

printf "  ${CYAN}󰑓${RESET}  ${TEXT}Uploading${RESET} "

# Small animated dots
(
    while true; do
        printf "${DIM}.${RESET}"
        sleep 0.25
        printf "\b \b"
        printf "${DIM}..${RESET}"
        sleep 0.25
        printf "\b\b  \b\b"
        printf "${DIM}...${RESET}"
        sleep 0.25
        printf "\b\b\b   \b\b\b"
    done
) &

SPINNER_PID=$!

# ------------------------------------------------------------
# Upload
# ------------------------------------------------------------

curl \
    -fS \
    --progress-bar \
    -X POST \
    -H "Content-Type: text/plain" \
    --data-binary @"$FILE_PATH" \
    "$UPLOAD_URL" \
    >"$TMP_RESPONSE" \
    2>"$TMP_PROGRESS" &

CURL_PID=$!

wait "$CURL_PID"
CURL_STATUS=$?

kill "$SPINNER_PID" 2>/dev/null
wait "$SPINNER_PID" 2>/dev/null

printf "\r\033[2K"

# ------------------------------------------------------------
# Upload failed
# ------------------------------------------------------------

if [[ "$CURL_STATUS" -ne 0 ]]; then
    printf "  ${RED}✗${RESET} ${TEXT}Upload failed.${RESET}\n"
    echo
    exit 1
fi

# ------------------------------------------------------------
# Parse response
# ------------------------------------------------------------

HASTE_KEY=$(jq -r '.key // empty' "$TMP_RESPONSE" 2>/dev/null)

[[ -n "$HASTE_KEY" ]] ||
    die "Server returned an invalid response."

URL="$BASE_URL/$HASTE_KEY"

# ------------------------------------------------------------
# Clipboard
# ------------------------------------------------------------

COPIED=false

if command -v wl-copy &>/dev/null; then
    printf '%s' "$URL" | wl-copy
    COPIED=true

elif command -v xclip &>/dev/null; then
    printf '%s' "$URL" | xclip -selection clipboard
    COPIED=true

elif command -v xsel &>/dev/null; then
    printf '%s' "$URL" | xsel --clipboard --input
    COPIED=true

elif command -v pbcopy &>/dev/null; then
    printf '%s' "$URL" | pbcopy
    COPIED=true
fi

# ------------------------------------------------------------
# Generate QR
# ------------------------------------------------------------

QR=""

if command -v qrencode &>/dev/null; then

    QR=$(
        qrencode \
            -t ANSIUTF8 \
            -m 0 \
            -l M \
            "$URL"
    )

fi

# ------------------------------------------------------------
# Result
# ------------------------------------------------------------

echo

printf "  ${GREEN}╭─${RESET} ${GREEN}✓${RESET} ${TEXT}Uploaded${RESET} ${GREEN}──────────────────────────────────────╮${RESET}\n"

printf "  ${GREEN}│${RESET}                                                        ${GREEN}│${RESET}\n"

printf "  ${GREEN}│${RESET}  ${DIM}FILE${RESET}     ${TEXT}%s${RESET}\n" "$FILE_NAME"

printf "  ${GREEN}│${RESET}  ${DIM}SIZE${RESET}     ${TEXT}%s${RESET}\n" "$FILE_SIZE"

printf "  ${GREEN}│${RESET}  ${DIM}TYPE${RESET}     ${TEXT}%s${RESET}\n" "$FILE_TYPE"

printf "  ${GREEN}│${RESET}                                                        ${GREEN}│${RESET}\n"

printf "  ${GREEN}│${RESET}  ${DIM}URL${RESET}                                                        ${GREEN}│${RESET}\n"

printf "  ${GREEN}│${RESET}  ${BLUE}%s${RESET}\n" "$URL"

printf "  ${GREEN}│${RESET}                                                        ${GREEN}│${RESET}\n"

# ------------------------------------------------------------
# QR
# ------------------------------------------------------------

if [[ -n "$QR" ]]; then

    printf "  ${GREEN}│${RESET}  ${DIM}SCAN${RESET}                                                        ${GREEN}│${RESET}\n"

    while IFS= read -r line; do
        printf "  ${GREEN}│${RESET}  %s\n" "$line"
    done <<< "$QR"

    printf "  ${GREEN}│${RESET}                                                        ${GREEN}│${RESET}\n"

fi

# ------------------------------------------------------------
# Clipboard status
# ------------------------------------------------------------

if [[ "$COPIED" == true ]]; then

    printf "  ${GREEN}│${RESET}  ${GREEN}󰆏${RESET}  ${SUBTEXT}Copied to clipboard${RESET}                         ${GREEN}│${RESET}\n"

else

    printf "  ${GREEN}│${RESET}  ${YELLOW}󰆏${RESET}  ${SUBTEXT}Clipboard unavailable${RESET}                         ${GREEN}│${RESET}\n"

fi

printf "  ${GREEN}│${RESET}                                                        ${GREEN}│${RESET}\n"
printf "  ${GREEN}╰────────────────────────────────────────────────────────╯${RESET}\n"

echo

# ------------------------------------------------------------
# Done
# ------------------------------------------------------------

if [[ "$COPIED" == true ]]; then
    printf "  ${GREEN}◆${RESET} ${SUBTEXT}Ready — URL is in your clipboard.${RESET}\n"
else
    printf "  ${YELLOW}◆${RESET} ${SUBTEXT}Ready — copy the URL above.${RESET}\n"
fi

echo