Codebox Software

Meditation Timer Shell Script

Published:

A meditation timer shell script for macOS. The script should also work on Linux with only minimal changes (just replace afplay with whatever command-line mp3 player you have on your system).

To begin a session simply run the script along with the number of minutes you wish to practice for. For example, to start a 30 minute session:

zen.sh 30

If you don't specify how long the session should be, the default length of 60 minutes will be used.

The script shows a progress bar, and will play a bell every 10 minutes. At the end of the session a different bell will sound. To turn off the interval bell, change the value of PLAY_INTERVAL_BELL to false.

The script records how long you have practiced for, and will display your current total at the end of each session. If you need to finish a session early press Ctrl+C, your time will still be recorded.

Source Code

#!/usr/bin/env bash

INTERVAL_BELL_URL=https://codebox.net/assets/audio/bell1.mp3
ENDING_BELL_URL=https://codebox.net/assets/audio/bell2.mp3
MINUTE_MARKER=.
INTERVAL_MARKER=+
LOG_FILE=~/.zen_log

PLAY_INTERVAL_BELL=true

function play {
    URL_VAR=${1}_URL
    URL=${!URL_VAR}
    LOCAL_FILE=$TMPDIR/${1}.mp3
    if [ ! -f $LOCAL_FILE ]; then
        curl -s -o $LOCAL_FILE $URL
    fi
    afplay $LOCAL_FILE &
}

function print_time {
    PREFIX=$1
    MINUTES=$2
    echo "$PREFIX $(( MINUTES / 60 )) hours $(( MINUTES % 60 )) minutes"
}

function log {
    echo
    print_time "This session:" $MINUTES
    if [[ -f $LOG_FILE ]]; then
        PREV_MINUTES=$(<$LOG_FILE)
        NEW_MINUTES=$(( PREV_MINUTES + MINUTES ))
    else
        NEW_MINUTES=$MINUTES
    fi
    echo $NEW_MINUTES > $LOG_FILE
    print_time "All sessions:" $NEW_MINUTES
}

DEFAULT_SESSION_LENGTH_MINUTES=60
SESSION_LENGTH_MINUTES=${1:-$DEFAULT_SESSION_LENGTH_MINUTES}
INTERVAL_LENGTH_MINUTES=10
MINUTES=0

if [[ ! $SESSION_LENGTH_MINUTES =~ ^[1-9][0-9]*$ ]]; then
    echo "Usage: $0 [minutes]"
    exit 1
fi

clear
play INTERVAL_BELL

trap break SIGINT

while :; do
    sleep 60
    MINUTES=$((MINUTES + 1))
    if [[ $MINUTES -eq $SESSION_LENGTH_MINUTES ]]; then
        echo -n $INTERVAL_MARKER
        break
    fi
    if [[ $(( MINUTES % INTERVAL_LENGTH_MINUTES )) -eq 0 ]]; then
        echo -n $INTERVAL_MARKER
        $PLAY_INTERVAL_BELL && play INTERVAL_BELL
    else
        echo -n $MINUTE_MARKER
    fi
done

log $MINUTES

play ENDING_BELL