dotfiles
Inspired by this post and the long weekend, I dove into learning bash and writing some dotfiles to make my life a little easier (sometimes).
Some of these were lifted straight from Evan Hahn at the beginning, some were modified, some were just inspired and I tried writing them. Most importantly, all work and I learned some basic bash scripting!
bb
runs the process in the background like bb timer 10m
#!/usr/bin/env bash
set -e
set -u
if test -t 1; then
exec 1>/dev/null
fi
if test -t 2; then
exec 2>/dev/null
fi
setsid -f "$@"
getsong
gets a song and the best guess at the metadata as an mp3. reception is not great (read: god awful) when going around NZ, so you gotta have offline backups.
always check because sometimes spotdl gives you a random song.
#!/usr/bin/env bash
set -e
set -u
set -o pipefail
url="$1"
if [[ "$url" == *"spotify.com"* ]]; then
exec spotdl "$url" --output "$HOME/Music"
else
exec yt-dlp -f bestaudio -x --audio-format mp3 --embed-metadata --embed-thumbnail --parse-metadata "%(title)s:%(artist)s - %(track)s" -o "$HOME/Music/%(title)s.%(ext)s" "$@"
fi
hoy
prints today's date and puts it in my clipboard
#!/usr/bin/env bash
set -e
set -u
set -o pipefail
date '+%Y-%m-%d' | tee >(wl-copy)
imgup
uploads a compressed version of an image from my pictures directory to imgbb, then puts the link in my clipboard so I can put it in my site. I could probably use it for sending images to people with temp links, but I'm not sure I want that in this dotfile or not.
#!/bin/bash
# Your ImgBB API key
IMGBB_API_KEY="your_api_key_here"
PICTURES_DIR="$HOME/Pictures"
UPLOAD_DIR="$PICTURES_DIR/uped2imgbb"
# Create upload directory if it doesn't exist
mkdir -p "$UPLOAD_DIR"
# If no argument provided, show numbered list
if [ -z "$1" ]; then
echo "Files in Pictures:"
mapfile -t files < <(find "$PICTURES_DIR" -maxdepth 1 -type f \( -iname "*.jpg" -o -iname "*.jpeg" -o -iname "*.png" -o -iname "*.gif" -o -iname "*.webp" \) | sort)
if [ ${#files[@]} -eq 0 ]; then
echo "No image files found in $PICTURES_DIR"
exit 1
fi
for i in "${!files[@]}"; do
echo "$((i+1)). $(basename "${files[$i]}")"
done
echo ""
echo -n "Enter number (or 'q' to quit): "
read -r selection
if "$selection" == "q" ]] ; then
echo "Cancelled."
exit 0
fi
if ! [[ "$selection" =~ ^[0-9]+$ ]] || [ "$selection" -lt 1 ] || [ "$selection" -gt ${#files[@]} ]; then
echo "Invalid selection."
exit 1
fi
INPUT_FILE="${files[$((selection-1))]}"
echo ""
echo "Convert $(basename "$INPUT_FILE")? [y/n]"
read -r response
if [[ ! "$response" =~ ^[Yy]$ ]]; then
echo "Cancelled."
exit 0
fi
else
# Search for file (case-insensitive)
INPUT_FILE=$(find "$PICTURES_DIR" -maxdepth 1 -iname "$1" -type f | head -1)
if [ -z "$INPUT_FILE" ]; then
echo "Image does not exist in $PICTURES_DIR"
exit 1
fi
fi
# Get original file size
ORIGINAL_SIZE=$(stat -c%s "$INPUT_FILE")
TEMP_DIR="/tmp/squoosh-$"
mkdir -p "$TEMP_DIR"
# Compress to WebP with quality 30
echo "Compressing image..."
squoosh-cli --webp '{"quality":30}' "$INPUT_FILE" -d "$TEMP_DIR"
# Get the output filename (squoosh changes extension to .webp)
COMPRESSED_FILE="$TEMP_DIR/$(basename "${INPUT_FILE%.*}").webp"
# Get compressed file size
COMPRESSED_SIZE=$(stat -c%s "$COMPRESSED_FILE")
# Calculate savings
DIFF=$((ORIGINAL_SIZE - COMPRESSED_SIZE))
PERCENT=$(awk "BEGIN {printf \"%.1f\", ($DIFF / $ORIGINAL_SIZE) * 100}")
# Display size comparison
if [ $DIFF -gt 0 ]; then
echo "Space saved: $(numfmt --to=iec-i --suffix=B $DIFF) (${PERCENT}% reduction)"
else
DIFF_ABS=${DIFF#-}
echo "Warning: File is larger by $(numfmt --to=iec-i --suffix=B $DIFF_ABS)"
fi
# Upload to ImgBB
echo "Uploading to ImgBB..."
RESPONSE=$(curl -s --location --request POST "https://api.imgbb.com/1/upload?key=$IMGBB_API_KEY" \
--form "image=@$COMPRESSED_FILE")
# Extract the URL
URL=$(echo "$RESPONSE" | grep -o '"url":"[^"]*"' | head -1 | sed 's/"url":"//;s/"//;s/\\//g')
# Copy to clipboard
echo "$URL" | wl-copy
# Move original file to uploaded folder
mv "$INPUT_FILE" "$UPLOAD_DIR/"
echo "Original moved to: $UPLOAD_DIR/$(basename "$INPUT_FILE")"
# Clean up
rm -rf "$TEMP_DIR"
echo "Done! URL copied to clipboard:"
echo "$URL"
mkdot
makes it easier for me to make new dotfiles, especially while I was playing around
#!/usr/bin/env bash
set -e
set -u
set -o pipefail
filename="$HOME/.dotfiles/$1"
touch "$filename"
chmod +x "$filename"
kate "$filename"
notify
used inside timer and weather to send a notification. might use in other stuff later?
#!/usr/bin/env bash
set -e
set -u
set -o pipefail
title="${1:-Notification}"
description="${2:-$(date --iso-8601=seconds)}"
notify-send --expire-time=5000 "$title" "$description"
now
shows me a calendar of this month with today highlighted. been using it for when I'm making lesson plans.
#!/usr/bin/env bash
set -e
set -u
date "+%l:%M%p on %A, %B %e, %Y"
echo
cal | grep -E --color=always "^|$(date '+%e')"
radio
sometimes (usually?), you just need someone else to make choices for you
#!/usr/bin/env bash
set -e
set -u
set -o pipefail
# Define stations in an associative array
declare -A stations=(
[00s]='https://stream.revma.ihrhls.com/zc6850'
[80hh]='https://regiocast.streamabc.net/regc-80s80shiphop3449572-mp3-192-3635250'
[80s]='https://live.hunter.fm/80s_stream?ag=mp3'
[90hh]='https://streams.90s90s.de/hiphop/mp3-192'
[90s]='https://streams.90s90s.de/main/aac-64'
[classical]='https://cms.stream.publicradio.org/cms.aac'
[kfai]='https://kfai.broadcasttool.stream/kfai-1'
[kpop]='https://live.hunter.fm/kpop_stream?ag=mp3'
[lofi]='https://live.hunter.fm/lofi_high'
[master]='https://live.hunter.fm/master_stream?ag=mp3'
[pop]='https://live.hunter.fm/pop_stream?ag=mp3'
[pop2k]='https://live.hunter.fm/pop2k_stream?ag=mp3'
[trance]='https://fr3.1mix.co.uk:8000/stream13'
[wnyc]='https://opera-stream.wqxr.org/wnycfm-tunein.aac'
[xmas]='https://christmasfm.cdnstream1.com/2547_64.aac'
)
# If no argument provided, list stations
if [ $# -eq 0 ]; then
echo "Available stations:"
printf '%s\n' "${!stations[@]}" | sort
exit 0
fi
# Get the URL for the requested station
url="${stations[$1]:-}"
if [ -z "$url" ]; then
echo "don't know $1" 1>&2
exit 1
fi
exec mpv --msg-level=all=no,statusline=status --term-status-msg='${media-title}' "$url"
timer
just a timer, but pretty handy especially combined with bb
#!/usr/bin/env bash
set -e
set -u
set -o pipefail
sleep "$1"
paplay /usr/share/sounds/freedesktop/stereo/alarm-clock-elapsed.oga &
notify 'timer complete' "$1"
tunes
ipod shuffle on the computer
#!/usr/bin/env bash
set -e
set -u
set -o pipefail
if [ $# -eq 0 ]; then
folder="$HOME/Music"
else
folder="$HOME/Music/${1,,}"
fi
exec mpv --shuffle --loop-playlist --no-video "$folder"/*
vidpod
lessen some stress on my computer when i'm listening to a video podcast without watching the video (always)
#!/usr/bin/env bash
set -e
set -u
set -o pipefail
exec mpv --no-video --ytdl-format=worstaudio "$@"
weather
shows the weather and puts it in my clipboard so I can paste it in my daily notes easier. mostly used to track my mood against the weather here because I was realizing huge shifts in my mood when I moved to New Zealand. it also gives me some notifications about the weather since I usually check before I go to work. still loads slow, so maybe there's some optimization to be had, but I needed to use JSON because the simpler api kept giving me current conditions, not whole day.
#!/usr/bin/env bash
set -e
set -u
set -o pipefail
location="${1:-}"
# Get JSON forecast
forecast=$(curl -s "wttr.in/${location}?format=j1&m")
# Parse daily forecast data
temp=$(echo "$forecast" | jq -r '.weather[0].maxtempC')
condition=$(echo "$forecast" | jq -r '.weather[0].hourly | map(.weatherDesc[0].value) | group_by(.) | max_by(length) | .[0]')
wind=$(echo "$forecast" | jq -r '.weather[0].hourly | map(.windspeedKmph | tonumber) | max')
uv=$(echo "$forecast" | jq -r '.weather[0].hourly | map(.uvIndex | tonumber) | max')
rain=$(echo "$forecast" | jq -r '.weather[0].hourly | map(.precipMM | tonumber) | add')
humidity=$(echo "$forecast" | jq -r '.weather[0].hourly | map(.humidity | tonumber) | max')
# Build display string
weather="+${temp}°C ${condition} Wind: ${wind}km/h UV: ${uv} Rain: ${rain}mm Humidity: ${humidity}%"
echo "$weather"
echo -n "$weather" | wl-copy
# Build alert message
alerts=()
if [ "$uv" -gt 2 ]; then
alerts+=("NEED SUNSCREEN")
fi
if (( $(echo "$rain >= 1" | bc -l) )); then
alerts+=("NEED UMBRELLA")
fi
if [ "$temp" -gt 20 ]; then
alerts+=("NEED WATER")
fi
if [ "$temp" -lt 15 ]; then
alerts+=("NEED JACKET")
fi
if [ "$humidity" -gt 70 ] && [ "$temp" -gt 25 ]; then
alerts+=("NEED FAN")
fi
# Send notification if there are alerts
if [ ${#alerts[@]} -gt 0 ]; then
message=$(IFS=
\n'; echo "${alerts[*]}")
notify "Weather Alert" "$message"
fi