Skip to content

Instantly share code, notes, and snippets.

@catvec
Last active June 6, 2018 15:22
Show Gist options
  • Select an option

  • Save catvec/199680f33b32ed087ac667bf86fbf0d3 to your computer and use it in GitHub Desktop.

Select an option

Save catvec/199680f33b32ed087ac667bf86fbf0d3 to your computer and use it in GitHub Desktop.
OSX Alarm Script
#!/bin/bash
#
# Usage: alarm COMMAND [command positional arguments]
#
# Args:
# - COMMAND: Action to run
# - set: Set an alarm, positional arguments:
# - MINUTES: Number of minutes until alarm should go off
# - [SAY]: Text to print and speak when alarm is done, defaults to
# "Alarm done"
# - time: Set an alarm for a specific time
# - ls: List set alarms
# - rm: Remove set alarm, positional arguments:
# - ALARM_NUM: Identifying alarm number
# - wait: Wait for alarms to complete, automatically run after set is
# called
# Check GNU Date installed
if ! which gdate > /dev/null; then
echo "Error GNU date must be installed under the name \"gdate\"" >&2
exit 1
fi
# Initialize alarm dir
alarms_dir="$HOME/.alarms"
alarm_time_file="time"
alarm_say_file="say"
mkdir -p "$alarms_dir"
# Command constants
wait_poll_time=10
wait_lock_file="$alarms_dir/WAIT.lock"
# Helpers
function exec_ls_alarms_dir() { # ()
out=$(ls -1 -a -d $alarms_dir/*/ 2> /dev/null | sort -n)
}
function get_alarms_dirs() { # ()
if ! exec_ls_alarms_dir; then
return
fi
while read "d"; do
basename "$d"
done <<< "$out"
}
function get_last_alarm() { # ()
echo $(get_alarms_dirs | tail -n 1)
}
function get_next_alarm_num() { # ()
last_alarm="$(get_last_alarm)"
if [ -z "$last_alarm" ]; then
echo "1"
else
echo "$last_alarm + 1" | bc
fi
}
function get_current_time() { # ()
echo $(date +%s)
}
function get_alarm_time() { # ( alarm_num )
# Arguments
alarm_num="$1"
if [ -z "$alarm_num" ]; then
echo "Error - get_alarm_time: alarm_num argument must be provided" >&2
exit 1
fi
# Get
cat "$alarms_dir/$alarm_num/$alarm_time_file"
}
function get_alarm_say() { # ( alarm_num )
# Arguments
alarm_num="$1"
if [ -z "$alarm_num" ]; then
echo "Error - get_alarm_say: alarm_num argument must be provided" >&2
exit 1
fi
# Get
cat "$alarms_dir/$alarm_num/$alarm_say_file"
}
function clean_wait_lock() { # ()
rm "$wait_lock_file"
}
function trigger_alarm() { # ( alarm_num )
# Arguments
alarm_num="$1"
if [ -z "$alarm_num" ]; then
echo "Error - trigger_alarm: alarm_num argument must be provided" >&2
exit 1
fi
# Trigger
say="$(get_alarm_say $alarm_num)"
echo " !Alarm #$alarm_num done: $say"
say "$say"
notify "$say"
bloop
}
function unix_to_timestamp() { # (unix_time)
# Arguments
unix_time="$1"
if [ -z "$unix_time" ]; then
echo "Error - unix_to_timestamp: unix_time argument must be provided" >&2
exit 1
fi
# Convert
date -r "$unix_time"
}
# Commands
function cmd_time() { # (timestamp, say)
# Arguments
timestamp="$1"
shift
if [ "$1" == "am" ] || [ "$1" == "AM" ] || [ "$1" == "pm" ] || [ "$1" == "PM" ]; then
timestamp="$timestamp $1"
shift
fi
if [ -z "$timestamp" ]; then
echo "Timestamp argument must be provided" >&2
exit 1
fi
say="$1"
# Parse provided time
timestamp_unix=$(gdate -d "$timestamp" "+%s")
if [ "$?" != "0" ]; then
echo "Error parsing timestamp into unix time" >&2
exit 1
fi
# Get difference
current_unix=$(get_current_time)
if [ "$?" != "0" ]; then
echo "Failed to get current unix time" >&2
exit 1
fi
minutes=$(echo "scale=2; ($timestamp_unix - $current_unix) / 60" | bc)
if [ "$?" != "0" ]; then
echo "Error calculating difference between current time and provided time" >&2
exit 1
fi
# Set
echo "Setting alarm for $timestamp (In $minutes minutes)"
cmd_set "$minutes" "$say"
}
function cmd_set() { # (time, say)
# Arguments
minutes="$1"
if [ -z "$minutes" ]; then
echo "Minutes argument must be provided" >&2
exit 1
fi
say="$2"
if [ -z "$say" ]; then
say="Alarm done"
fi
# Calculate alarm params
seconds=$(echo "$minutes * 60" | bc)
alarm_time=$(echo "$(get_current_time) + $seconds" | bc)
alarm_time=${alarm_time%.*}
alarm_num=$(get_next_alarm_num)
alarm_dir="$alarms_dir/$alarm_num"
# Set alarm
echo "Alarm #$alarm_num will go off in $minutes minutes at $(unix_to_timestamp $alarm_time) ($seconds seconds)"
mkdir -p "$alarm_dir"
echo "$alarm_time" > "$alarm_dir/$alarm_time_file"
echo "$say" > "$alarm_dir/$alarm_say_file"
echo ""
cmd_wait
}
function cmd_ls() { # ()
ds=$(get_alarms_dirs)
if [ -z "$ds" ]; then
echo "No alarms"
else
echo "Alarms:"
while read "alarm_num"; do
alarm_time="$(get_alarm_time $alarm_num)"
alarm_time="$(unix_to_timestamp $alarm_time)"
alarm_say="$(get_alarm_say $alarm_num)"
echo " - $alarm_num: $alarm_time, \"$alarm_say\""
done <<< "$ds"
fi
}
function cmd_rm() { # ( alarm_num )
# Arguments
alarm_num="$1"
if [ -z "$alarm_num" ]; then
echo "Error - rm: alarm_num argument must be provided" >&2
exit 1
fi
# Remove
rm -rf "$alarms_dir/$alarm_num"
}
function cmd_wait() { # ()
# Wait lock
if [ -f "$wait_lock_file" ]; then
echo "Error: wait is already running, stop or delete $wait_lock_file" >&2
exit 1
fi
trap clean_wait_lock EXIT
touch "$wait_lock_file"
# Wait
temp_poll_time=""
while true; do
echo "Checking alarms"
current_time="$(get_current_time)"
# Loop through alarms and check
ds=$(get_alarms_dirs)
if [ -z "$ds" ]; then
echo " No alarms"
sleep "$wait_poll_time"
else
while read "alarm_num"; do
alarm_time="$(get_alarm_time $alarm_num)"
# If alarm done
if (( "$current_time" > "$alarm_time" )); then
trigger_alarm "$alarm_num"
echo " Press any key to acknowledge alarm #$alarm_num"
read -t 3 -n 1 "in" </dev/tty
if [ ! -z "$in" ]; then
in=""
cmd_rm "$alarm_num"
echo " Alarm #$alarm_num removed"
else
echo "$in"
temp_poll_time="1"
fi
if [ -z "$(get_alarms_dirs)" ]; then
echo "No more alarms"
exit 1
fi
else
# If alarm waiting
delta=$(echo "$alarm_time - $current_time" | bc)
echo " Alarm #$alarm_num has $delta seconds left"
# If delta to alarm being done is less than poll interval
if (( "$delta" < "$wait_poll_time" )); then
# If delta is smaller than any temp poll time we have
if [ -z "$temp_poll_time" ] || (( "$delta" < "$temp_poll_time" )); then
temp_poll_time=$(echo "$delta + 1" | bc)
fi
fi
fi
done <<< "$ds"
fi
# Wait till next check
sleep_time="$wait_poll_time"
if [ ! -z "$temp_poll_time" ]; then
sleep_time="$temp_poll_time"
temp_poll_time=""
fi
sleep "$sleep_time"
echo ""
done
}
# Parse command
cmd="$1"
shift
case "$cmd" in
time)
cmd_time "$@"
;;
set)
cmd_set "$@"
;;
ls)
cmd_ls
;;
rm)
cmd_rm "$@"
;;
wait)
cmd_wait
;;
*)
echo "Error: unknown command $cmd" >&2
exit 1
;;
esac
#!/usr/bin/env bash
afplay /System/Library/Sounds/Funk.aiff
#!/usr/bin/env bash
terminal-notifier -message "$1" -title "Terminal Notification"
bloop
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment