#!/usr/bin/env bash loc_storage="${HOME}/.config/url-diff"; if [[ ! -z "${URLDIFF_STORAGE_DIR}" ]]; then loc_storage="${URLDIFF_STORAGE_DIR}"; fi loc_firefox_profile="${loc_storage}/firefox-profile"; loc_prev_images="${loc_storage}/previous-images"; highlight_colour="${URLDIFF_HIGHLIGHT_COLOUR:-#ff000044}"; quiet="${URLDIFF_QUIET:-false}"; window_width="${URLDIFF_WINDOW_WIDTH}"; change_threshold="${URLDIFF_CHANGE_THRESHOLD:-2}"; ############################################################################### if [[ -z "$(type -p calc)" ]]; then echo "calc command not detected - it would appear it is not installed" >&2; echo "Install it like this on debian systems:" >&2; echo " sudo apt install apcalc" >&2; fi ############################################################################### log_msg() { if [[ "${quiet}" == "true" ]]; then return 0; fi echo "[${SECONDS}] $*"; } # $1 Image to process # $2 Colour to find calculate_percentage_colour() { loc_image="${1}"; colour="${2}"; if [[ -z "${colour}" ]]; then log_msg "calculate_percentage_colour/Error: No colour specified." >&2; return 1; fi image_width="$(identify -format "%[fx:w]" "${loc_image}" )"; image_height="$(identify -format "%[fx:h]" "${loc_image}")"; pixel_count_colour="$(convert "${loc_image}" -fill black +opaque "${colour}" -fill white -opaque "${colour}" -format "%[fx:w*h*mean]" info:)"; # echo "image_width: ${image_width}, image_height: ${image_height}, pixel_count_colour: ${pixel_count_colour}" >&2; calc -p "(${pixel_count_colour} / (${image_width}*${image_height})) * 100" | tr -d '~'; } ############################################################################### mode="${1}"; shift; if [[ -z "${mode}" ]]; then echo -e "Webpage visual diff checker By Starbeamrainbowlabs Usage: webpage-diff {subcommand} [{arguments}] Subcommands: check {url} {output_diff_image} [{output_apng}] Checks the given URL for differences, and saves a diff image to a specified location. Exits with code 0 if differences are found, or code 1 if no differences are found. Optionally generates an animated PNG that alternates between the 2 screenshots. Environment Variables: Variable Default variable ---------------------------------------------------------------------- URLDIFF_STORAGE_DIR ~/.config/url-diff The directory in which previous images are stored to diff against. The firefox profile is also stored in here. URLDIFF_HIGHLIGHT_COLOUR #ffffffcc The colour to highlight any changes in. URLDIFF_WINDOW_WIDTH The window width to tell firefox to screenshot with. URLDIFF_CHANGE_THRESHOLD 2 The percentage of the screenshot that should have changed for it to count. Allows for ignoring random minor rendering artifacts. " >&2; fi # Create the config directories mkdir -p "${loc_firefox_profile}"; mkdir -p "${loc_prev_images}"; case "${mode}" in check ) url="${1}"; url_hash="$(echo "${url}" | sha256sum | cut -d ' ' -f 1)"; loc_output_diffimage="${2}"; loc_output_apng="${3}"; tmpdir="$(mktemp -d)"; on_exit() { rm -rf "${tmpdir}"; } trap on_exit EXIT; loc_img_old="${loc_prev_images}/${url_hash}.png"; loc_img_new="${tmpdir}/new.png"; if [[ ! -d "$(dirname "${loc_output_diffimage}")" ]]; then echo "Error: Output directory for diff image does not exist"; exit 2; fi log_msg "Taking screenshot"; log_msg "$(firefox --window-size "${window_width}" --profile "${loc_firefox_profile}" --headless --screenshot "${loc_img_new}" "${url}" 2>&1)"; if [[ ! -f "${loc_img_old}" ]]; then log_msg "No image exists yet, storing initial snapshot"; mv "${loc_img_new}" "${loc_img_old}"; exit 1; fi # eog "${loc_img_old}"; # eog "${loc_img_new}"; # img_hash_old="$(identify -quiet -format "%#" "${loc_img_old}")"; # img_hash_new="$(identify -quiet -format "%#" "${loc_img_new}")"; # Generate the diff image compare "${loc_img_old}" "${loc_img_new}" -compose src -highlight-color "${highlight_colour}" "${tmpdir}/diff.png"; convert "${tmpdir}/diff.png" -transparent "#ffffffcc" "${tmpdir}/transp.png"; # Work out how much of the image has changed percentage_changed="$(calculate_percentage_colour "${tmpdir}/transp.png" "${highlight_colour}")"; if [[ -z "${percentage_changed}" ]]; then echo "Something went wrong when calculating the percentage changed - no value was returned"; exit 1; fi log_msg "Changed: ${percentage_changed}%"; # if [[ "${img_hash_new}" == "${img_hash_old}" ]]; then if [[ "$(calc -p "${percentage_changed} > ${change_threshold}")" -eq 0 ]]; then log_msg "No changes detected."; exit 1; fi log_msg "Changes detected, outputting diff image."; convert "${loc_img_new}" "${tmpdir}/transp.png" -compose over -composite "${loc_output_diffimage}"; if which optipng >/dev/null 2>&1; then log_msg "Optimising new image"; optipng "${loc_img_new}"; fi if [[ ! -z "${loc_output_apng}" ]]; then log_msg "Making animated PNG"; cp "${loc_img_old}" "${tmpdir}/0.png"; cp "${loc_img_new}" "${tmpdir}/1.png"; ffmpeg -hide_banner -r 1 -i "${tmpdir}/%d.png" -plays 0 "${loc_output_apng}"; fi mv "${loc_img_new}" "${loc_img_old}"; exit 0; ;; esac