From 47ba51381068ffc3930adc6800a48659a2008f19 Mon Sep 17 00:00:00 2001
From: Starbeamrainbowlabs <sbrl@starbeamrainbowlabs.com>
Date: Fri, 29 May 2020 18:11:17 +0100
Subject: [PATCH] Initial commit.

---
 .gitignore  |  85 ++++++++++++++++++++++++++++
 url-diff.sh | 160 ++++++++++++++++++++++++++++++++++++++++++++++++++++
 2 files changed, 245 insertions(+)
 create mode 100644 .gitignore
 create mode 100755 url-diff.sh

diff --git a/.gitignore b/.gitignore
new file mode 100644
index 0000000..3d42c32
--- /dev/null
+++ b/.gitignore
@@ -0,0 +1,85 @@
+
+# Created by https://www.gitignore.io/api/images,git
+# Edit at https://www.gitignore.io/?templates=images,git
+
+### Git ###
+# Created by git for backups. To disable backups in Git:
+# $ git config --global mergetool.keepBackup false
+*.orig
+
+# Created by git when using merge tools for conflicts
+*.BACKUP.*
+*.BASE.*
+*.LOCAL.*
+*.REMOTE.*
+*_BACKUP_*.txt
+*_BASE_*.txt
+*_LOCAL_*.txt
+*_REMOTE_*.txt
+
+### Images ###
+# JPEG
+*.jpg
+*.jpeg
+*.jpe
+*.jif
+*.jfif
+*.jfi
+
+# JPEG 2000
+*.jp2
+*.j2k
+*.jpf
+*.jpx
+*.jpm
+*.mj2
+
+# JPEG XR
+*.jxr
+*.hdp
+*.wdp
+
+# Graphics Interchange Format
+*.gif
+
+# RAW
+*.raw
+
+# Web P
+*.webp
+
+# Portable Network Graphics
+*.png
+
+# Animated Portable Network Graphics
+*.apng
+
+# Multiple-image Network Graphics
+*.mng
+
+# Tagged Image File Format
+*.tiff
+*.tif
+
+# Scalable Vector Graphics
+*.svg
+*.svgz
+
+# Portable Document Format
+*.pdf
+
+# X BitMap
+*.xbm
+
+# BMP
+*.bmp
+*.dib
+
+# ICO
+*.ico
+
+# 3D Images
+*.3dm
+*.max
+
+# End of https://www.gitignore.io/api/images,git
diff --git a/url-diff.sh b/url-diff.sh
new file mode 100755
index 0000000..a36d344
--- /dev/null
+++ b/url-diff.sh
@@ -0,0 +1,160 @@
+#!/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="#ff000044";
+if [[ ! -z "${URLDIFF_HIGHLIGHT_COLOUR}" ]]; then highlight_colour="${URLDIFF_HIGHLIGHT_COLOUR}"; fi
+
+quiet="false";
+if [[ ! -z "${URLDIFF_QUIET}" ]]; then quiet="${URLDIFF_QUIET}"; fi
+
+window_width="${URLDIFF_WINDOW_WIDTH}";
+
+change_threshold="2";
+if [[ ! -z "${URLDIFF_CHANGE_THRESHOLD}" ]]; then change_threshold="${URLDIFF_CHANGE_THRESHOLD}"; 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 "(${pixel_count_colour} / (${image_width}*${image_height})) * 100" | bc -l
+}
+
+###############################################################################
+
+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}")";
+		
+		log_msg "Changed: ${percentage_changed}%";
+		
+		# if [[ "${img_hash_new}" == "${img_hash_old}" ]]; then
+		if [[ "$(echo "${percentage_changed} > ${change_threshold}" | bc -l)" -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
