#!/bin/bash
# ==========================================
# Notification Wrapper
# ==========================================
show_notification() {
local title="$1"
local message="$2"
local icon="${3:-cloud-upload-symbolic}"
if command -v kdialog &>/dev/null; then
kdialog --passivepopup "$message" 5 --title "$title" --icon "$icon"
else
echo "$title: $message"
fi
}
# ==========================================
# Configuration
# ==========================================
API_URL="http://localhost:1337/api/v2/upload"
API_KEY=""
# ==========================================
FILE="$1"
if [ -z "$FILE" ]; then
show_notification "Upload Failed" "No file provided to uploader." "dialog-error"
exit 1
fi
# Determine clipboard command (Wayland or X11)
if command -v wl-copy &>/dev/null; then
COPY_CMD="wl-copy"
elif command -v xclip &>/dev/null; then
COPY_CMD="xclip -selection clipboard"
else
show_notification "Upload Error" "Please install wl-clipboard (Wayland) or xclip (X11)." "dialog-error"
exit 1
fi
# Detect the real MIME type so curl doesn't fall back to application/octet-stream
MIME_TYPE=$(file --mime-type -b "$FILE")
BASENAME=$(basename "$FILE")
# Get file size locally
FILE_SIZE_BYTES=$(stat -c%s "$FILE" 2>/dev/null || echo "0")
human_readable_size() {
local size=$1
local units=('B' 'KB' 'MB' 'GB' 'TB')
local unit=0
while [ $size -ge 1024 ] && [ $unit -lt 4 ]; do
size=$((size / 1024))
unit=$((unit + 1))
done
echo "$size ${units[$unit]}"
}
TOTAL_SIZE=$(human_readable_size "$FILE_SIZE_BYTES")
# Helper to format centered HTML label with a fixed width
format_label() {
local filename="$1"
local detail="$2"
local wrapped_filename
# Wrap the filename to 45 chars max, and join with
wrapped_filename=$(echo "$filename" | fold -w 45 | sed ':a;N;$!ba;s/\n/
/g')
echo "
Uploading $wrapped_filename $detail |
"
}
INIT_LABEL=$(format_label "$BASENAME" "(0 B / $TOTAL_SIZE) @ 0 B/s — --:--:-- remaining")
# ==========================================
# Progress bar setup (kdialog + qdbus)
# ==========================================
# Prefer qdbus6 on KDE6, fall back to qdbus on KDE5
QDBUS_CMD=""
if command -v qdbus6 &>/dev/null; then
QDBUS_CMD="qdbus6"
elif command -v qdbus &>/dev/null; then
QDBUS_CMD="qdbus"
fi
PROGRESS_SERVICE=""
PROGRESS_OBJECT=""
if command -v kdialog &>/dev/null && [ -n "$QDBUS_CMD" ]; then
DBUS_REF=$(kdialog --title "f0ckm Uploader" \
--progressbar "$INIT_LABEL" 100 2>/dev/null)
PROGRESS_SERVICE=$(echo "$DBUS_REF" | awk '{print $1}')
PROGRESS_OBJECT=$(echo "$DBUS_REF" | awk '{print $2}')
fi
# If no progress dialog is available, show a passive "uploading" popup instead
if [ -z "$PROGRESS_SERVICE" ]; then
show_notification "Uploading..." "Uploading $BASENAME" "cloud-upload-symbolic"
fi
# ==========================================
# Upload via curl with live progress
# ==========================================
# FIFO routes curl's stderr (progress bar) to the reader loop
FIFO=$(mktemp -u /tmp/f0ckm_XXXXXX)
mkfifo "$FIFO"
RESPONSE_TMP=$(mktemp)
# --progress-meter forces curl to output progress table even when redirected to a FIFO
curl --progress-meter -w "\n%{http_code}" -X POST "$API_URL" \
-H "X-Api-Key: $API_KEY" \
-F "file=@$FILE;type=$MIME_TYPE" \
-F "rating=" \
-F "tags=" \
-F "is_oc=0" \
>"$RESPONSE_TMP" 2>"$FIFO" &
CURL_PID=$!
# Parse the curl progress meter output in real-time
if [ -n "$PROGRESS_SERVICE" ] && [ -n "$PROGRESS_OBJECT" ]; then
while IFS= read -r -d $'\r' line; do
# Clean line and split into fields
line=$(echo "$line" | tr -d '\n\r')
read -ra fields <<< "$line"
# Check if valid progress line: starts with percentage digit and has >= 11 fields
if [[ ${#fields[@]} -ge 11 ]] && [[ "${fields[0]}" =~ ^[0-9]+$ ]]; then
PCT="${fields[4]}" # % Xferd
if [[ ! "$PCT" =~ ^[0-9]+$ ]]; then
PCT="${fields[0]}"
fi
TOTAL_SIZE_CURL="${fields[1]}"
XFERD="${fields[5]}"
SPEED="${fields[11]}"
TIME_LEFT="${fields[10]}"
# Format speed (append /s if it looks like a size unit)
if [[ "$SPEED" =~ [0-9]+[bBkKmMgGtT]?$ ]]; then
SPEED="${SPEED}/s"
fi
# Prefer the local size calculation if curl total size is 0/empty/not computed yet
if [ -z "$TOTAL_SIZE_CURL" ] || [ "$TOTAL_SIZE_CURL" = "0" ] || [ "$TOTAL_SIZE_CURL" = "0b" ]; then
TOTAL_SIZE_CURL="$TOTAL_SIZE"
fi
DETAIL="($XFERD / $TOTAL_SIZE_CURL) @ $SPEED — $TIME_LEFT remaining"
LABEL=$(format_label "$BASENAME" "$DETAIL")
$QDBUS_CMD "$PROGRESS_SERVICE" "$PROGRESS_OBJECT" Set "" value "$PCT" 2>/dev/null || true
$QDBUS_CMD "$PROGRESS_SERVICE" "$PROGRESS_OBJECT" setLabelText "$LABEL" 2>/dev/null || true
fi
done < "$FIFO"
else
# No progress dialog — drain the FIFO in the background so curl isn't blocked
cat "$FIFO" >/dev/null &
fi
wait "$CURL_PID"
# Close the progress dialog
if [ -n "$PROGRESS_SERVICE" ] && [ -n "$PROGRESS_OBJECT" ]; then
$QDBUS_CMD "$PROGRESS_SERVICE" "$PROGRESS_OBJECT" close 2>/dev/null || true
fi
rm -f "$FIFO"
# ==========================================
# Parse response
# ==========================================
HTTP_CODE=$(tail -n1 "$RESPONSE_TMP")
BODY=$(sed '$d' "$RESPONSE_TMP")
rm -f "$RESPONSE_TMP"
if [ "$HTTP_CODE" -ge 200 ] && [ "$HTTP_CODE" -lt 300 ]; then
# Parse the direct file URL from the JSON response.
# Expects a response containing a "file_url" field.
URL=$(echo "$BODY" | grep -oP '"file_url"\s*:\s*"\K[^"]+')
# Fallback: if no file_url field is found, copy the whole body
if [ -z "$URL" ]; then
URL="$BODY"
fi
echo -n "$URL" | $COPY_CMD
show_notification "Upload Successful" \
"Link copied to clipboard!
$URL" \
"cloud-upload-symbolic"
else
show_notification "Upload Failed" "HTTP Error $HTTP_CODE\n$BODY" "dialog-error"
exit 1
fi