Skip to content

Instantly share code, notes, and snippets.

@doersino
Last active August 29, 2015 14:11
Show Gist options
  • Save doersino/ade1edd8fe154ea30ba4 to your computer and use it in GitHub Desktop.
Save doersino/ade1edd8fe154ea30ba4 to your computer and use it in GitHub Desktop.
Downloads a webcam image, overlays the date/time, and compress past images into ZIP and MP4 format.
#!/bin/bash
# http://www.reddit.com/r/spacex/comments/2pwjni/live_video_of_asds_in_port/cn19n2i?context=7
# https://gist.github.com/doersino/ade1edd8fe154ea30ba4
#
# This script downloads a webcam image to a date/hour-labeled directory,
# creating intermediate directories as required, making sure that the image is
# not corrupt, and optionally overlaying the current date and time on the image
# and maintaining a mirror of the webcam. Any images from the previous day will
# optionally be ZIP-compressed and compiled into a MP4 video after the first
# download of each day.
#
# The output is quite verbose for debugging purposes, so you may want to discard
# it by appending >/dev/null 2>&1 to the call.
#
# Run this script either
# * manually whenever you want to download the current webcam image,
# * in a bash loop (e.g. while sleep 30; do bash webcam_dl.sh; done),
# * or, especially for long-term monitoring, with cron (keep in mind that cron
# can only run a command once per minute or less frequently) or runwhen.
#
# Tested on Mac OS X and CentOS.
#
# Dependencies:
# * Required: curl, grep, zip
# * Optional: jpeginfo, imagemagick (identify, mogrify), ghostscript, ffmpeg
# * if found, jpeginfo will be used to detect corrupt images if FILE_EXT is
# either "jpg" or "jpeg", otherwise identify will be used
# * if neither jpeginfo nor identify can be found, corrupt images won't be
# detected and removed
# * if mogrify can't be found or isn't configured to work with ghostscript,
# images won't be annotated with the current date and time
# * if ffmpeg can't be found, no video will be created
#
# In case you're considering using this to spy on somebody: please don't.
# BEGIN CONFIG -----------------------------------------------------------------
WEBCAM_URL="http://www.centennialbulb.org/ctbulb.jpg"
APPEND_TIMESTAMP=1 # try to fool potential server-side caching? (1: determine
# whether to use ? or & as delimiter automatically, 0: don't
# append timestamp, string: use the value assigned to this
# variable as delimiter)
CURL_FLAGS="" # useful if the webcam requires a particular --referer
BASE_DIR="$HOME" # no trailing slash!
#FILENAME=$(date +%Y-%m-%dT%H:%M:%SZ) # ISO 8601
FILENAME=$(date +%s) # UNIX timestamp
FILE_EXT="jpg" # whatever image format the webcam outputs
JPEGINFO_PATH=$(which jpeginfo) # path of jpeginfo executable
IDENTIFY_PATH=$(which identify) # path of imagemagick's identify executable
OVERLAY_TIME=1 # overlay the current date and time on each webcam image?
MOGRIFY_PATH=$(which mogrify) # path of imagemagick's mogrify executable
COPY_TO_BASE_DIR=1 # copy the latest webcam image to BASE_DIR/latest.FILE_EXT,
# essentially creating a mirror of the webcam?
COMPRESS=1 # create daily ZIP archive and MP4 video of yesterday's images?
FFMPEG_PATH=$(which ffmpeg) # path of ffmpeg executable
VIDEO_FPS=24 # framerate of the generated video
# END CONFIG -------------------------------------------------------------------
function echo_debug {
echo -e "\033[1;34m$1\033[0m" # bold/blue
}
function download_image {
URL="$WEBCAM_URL"
if [ "$APPEND_TIMESTAMP" = "1" ]; then
if grep -q '?' <<< "$URL"; then # determine if we need to prepend ? or &
URL="$URL"'&'
else
URL="$URL"'?'
fi
URL="$URL$(date +%s)"
elif [ "$APPEND_TIMESTAMP" != "0" ]; then
URL="$URL$APPEND_TIMESTAMP$(date +%s)"
fi
echo_debug "Downloading $URL to $FILE..."
curl $CURL_FLAGS "$URL" > "$FILE"
}
DAY=$(date -u +"%Y-%m-%d")
HOUR=$(date -u +"%H")
# create directory BASE_DIR/YYYY-MM-DD/HH if not exists
if [ ! -d "$BASE_DIR/$DAY/$HOUR" ]; then
echo_debug "Creating directory $BASE_DIR/$DAY/$HOUR..."
mkdir -p "$BASE_DIR/$DAY/$HOUR"
fi
# download image
FILE="$BASE_DIR/$DAY/$HOUR/$FILENAME.$FILE_EXT"
download_image
# check if the downloaded image is corrupt using either jpeginfo or identify and
# retry if neccessary - if the second try isn't successful either, remove the
# image in order to not upset ffmpeg later on
if [ -e "$JPEGINFO_PATH" ] && { [ "$FILE_EXT" = "jpg" ] || [ "$FILE_EXT" = "jpeg" ]; }; then
if ! "$JPEGINFO_PATH" -c "$FILE" >/dev/null 2>&1; then
echo_debug "Downloaded image is likely corrupt (jpeginfo). Sleeping 2s and retrying..."
sleep 2
download_image
fi
if ! "$JPEGINFO_PATH" -c "$FILE" >/dev/null 2>&1; then
echo_debug "Downloaded image is likely corrupt (jpeginfo). Removing corrupt image..."
rm "$FILE"
fi
elif [ -e "$IDENTIFY_PATH" ]; then
if [ $("$IDENTIFY_PATH" -verbose "$FILE" 2>&1 >/dev/null | wc -l) -ge 1 ]; then
echo_debug "Downloaded image is likely corrupt (identify). Sleeping 2s and retrying..."
sleep 2
download_image
fi
if [ $("$IDENTIFY_PATH" -verbose "$FILE" 2>&1 >/dev/null | wc -l) -ge 1 ]; then
echo_debug "Downloaded image is likely corrupt (identify). Removing corrupt image..."
rm "$FILE"
fi
fi
# if the image is empty, remove it in order to not upset ffmpeg later on
if [ -e "$FILE" ] && [ "$(du -k "$FILE" | cut -f1)" -eq 0 ]; then
echo_debug "Downloaded image is empty. Removing empty image..."
rm "$FILE"
fi
# overlay the current date and time on the image
if [ "$OVERLAY_TIME" -eq 1 ] && [ -e "$MOGRIFY_PATH" ] && [ -e "$FILE" ]; then
echo_debug "Overlaying the current date and time on downloaded image..."
"$MOGRIFY_PATH" -fill black -draw "rectangle 0,0 223,15" -fill white -gravity NorthWest -font Courier -pointsize 15 -annotate +8+2 "$(date -u +'%Y-%m-%d %H:%M:%S') UTC" "$FILE"
fi
# create a mirror of the webcam
if [ "$COPY_TO_BASE_DIR" -eq 1 ] && [ -e "$FILE" ]; then
echo_debug "Copying the downloaded image to $BASE_DIR/latest.$FILE_EXT"
\cp "$FILE" "$BASE_DIR/latest.$FILE_EXT"
fi
# create ZIP archive and MP4 video of yesterday's images if there are any (and
# the ZIP archive doesn't already exist)
if [ "$COMPRESS" -eq 1 ]; then
if [ "$(uname)" = "Darwin" ]; then
YESTERDAY=$(date -j -v-1d -f "%Y-%m-%d" $DAY "+%Y-%m-%d") # Mac OS X
else
YESTERDAY=$(date -u +"%Y-%m-%d" -d "yesterday") # most Linux distributions
fi
if [ ! -e "$BASE_DIR/$YESTERDAY.zip" ] && [ -d "$BASE_DIR/$YESTERDAY" ]; then
echo_debug "Creating ZIP archive of yesterday's images: $BASE_DIR/$YESTERDAY.zip..."
cd "$BASE_DIR"
\zip "$YESTERDAY.zip" "$YESTERDAY" # "touch" the ZIP archive
zip -rv "$YESTERDAY.zip" "$YESTERDAY"
# TODO this works, but it could *really* use some refactoring
if [ -e "$FFMPEG_PATH" ]; then
echo_debug "Creating $VIDEO_FPS fps video of yesterday's images: $BASE_DIR/$YESTERDAY.mp4..."
mkdir -p "$BASE_DIR/$YESTERDAY/temp"
find "$BASE_DIR/$YESTERDAY" -name "*.$FILE_EXT" | sort | awk -v q="\"" 'BEGIN{ a=1 }{ printf "cp "q"%s"q" "q"'"$BASE_DIR/$YESTERDAY/temp/"'%05d'".$FILE_EXT"'"q"\n", $0, a++ }' | bash
"$FFMPEG_PATH" -framerate "$VIDEO_FPS" -i "$BASE_DIR/$YESTERDAY/temp/"%05d.jpg -c:v libx264 -r "$VIDEO_FPS" -pix_fmt yuv420p "$BASE_DIR/$YESTERDAY.mp4"
rm -r "$BASE_DIR/$YESTERDAY/temp"
fi
echo_debug "Removing directory with yesterday's images..."
rm -r "$BASE_DIR/$YESTERDAY"
fi
fi
echo_debug "Finished!"
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment