#!/bin/bash # # notify - Display notifications with icons and sounds # # Usage: # notify "title" "body" [--persist] [--silent] # # Types: # success - Green checkmark, pleasant chime # fail - Red X, warning tone # alert - Yellow exclamation, attention tone # question - Blue question mark, contemplative tone # alarm - Alarm clock icon, alarm sound # info - Blue info icon, confident tone # security - Shield icon, security tone # bug - Bug icon, error tone # # Options: # --persist Don't auto-dismiss (stays until manually closed) # --silent Show the notification but play no sound # # Environment: # NOTIFY_VOLUME Playback volume for the sound (paplay scale: 65536 = 100%). # Lower it to soften every notification without re-encoding # the sound files. Default 65536. # # Examples: # notify success "Job Complete" "Download finished in 12 minutes" # notify fail "Job Failed" "Connection refused" --persist # notify info "Touchpad" "Disabled" --silent set -euo pipefail ICON_DIR="$HOME/.local/share/icons/notify" SOUND_DIR="$HOME/.local/share/sounds/notify" usage() { cat < "title" "body" [--persist] [--silent] Types: success Green checkmark, pleasant chime fail Red X, warning tone alert Yellow exclamation, attention tone question Blue question mark, contemplative tone alarm Alarm clock, alarm sound info Blue info icon, confident tone security Shield icon, security tone bug Bug icon, error tone Options: --persist Don't auto-dismiss notification --silent Show the notification but play no sound Environment: NOTIFY_VOLUME Sound playback volume (paplay scale: 65536 = 100%) Examples: notify success "Job Complete" "Download finished" notify fail "Build Failed" "Test errors" --persist notify info "Touchpad" "Disabled" --silent EOF exit 1 } # Require at least type, title, body if [[ $# -lt 3 ]]; then usage fi TYPE="$1" TITLE="$2" BODY="$3" shift 3 # Optional flags, in any order PERSIST="" SILENT="" for arg in "$@"; do case "$arg" in --persist) PERSIST="--persist" ;; --silent) SILENT=1 ;; *) echo "Error: Unknown option '$arg'" >&2 usage ;; esac done # Master playback volume (paplay scale: 65536 = 100%) NOTIFY_VOLUME="${NOTIFY_VOLUME:-65536}" # Validate type and set icon/sound case "$TYPE" in success) ICON="$ICON_DIR/success.png" SOUND="$SOUND_DIR/success.ogg" ;; fail) ICON="$ICON_DIR/fail.png" SOUND="$SOUND_DIR/fail.ogg" ;; alert) ICON="$ICON_DIR/alert.png" SOUND="$SOUND_DIR/alert.ogg" ;; question) ICON="$ICON_DIR/question.png" SOUND="$SOUND_DIR/question.ogg" ;; alarm) ICON="$ICON_DIR/alarm.png" SOUND="$SOUND_DIR/alarm.ogg" ;; info) ICON="$ICON_DIR/info.png" SOUND="$SOUND_DIR/info.ogg" ;; security) ICON="$ICON_DIR/security.png" SOUND="$SOUND_DIR/security.ogg" ;; bug) ICON="$ICON_DIR/bug.png" SOUND="$SOUND_DIR/bug.ogg" ;; *) echo "Error: Unknown type '$TYPE'" >&2 echo "Valid types: success, fail, alert, question, alarm, info, security, bug" >&2 exit 1 ;; esac # Check assets exist if [[ ! -f "$ICON" ]]; then echo "Warning: Icon not found: $ICON" >&2 fi if [[ ! -f "$SOUND" ]]; then echo "Warning: Sound not found: $SOUND" >&2 fi # Build notify-send arguments NOTIFY_ARGS=( --app-name="" --urgency=normal ) # Add persist flag if requested if [[ "$PERSIST" == "--persist" ]]; then NOTIFY_ARGS+=(--expire-time=0) fi # Add icon if it exists if [[ -f "$ICON" ]]; then NOTIFY_ARGS+=(--icon="$ICON") fi # Play sound in background (unless silenced, and if the file exists) if [[ -z "$SILENT" && -f "$SOUND" ]]; then paplay --volume="$NOTIFY_VOLUME" "$SOUND" & fi # Send notification notify-send "${NOTIFY_ARGS[@]}" "$TITLE" "$BODY"