#!/bin/sh
#
# This script is based on work of mendel from
# http://www.lafferty.ca/software/webshots/webshot
# webshot: hackish thing to take a picture of a whole webpage.
#
# idea from sippey (http://www.sippey.com/2004/blog-snaps/)
# inspiration from bradfitz
#
# usage: webshot url filename
#
# JPEG seems to be the best format.
#
# Modified by Dobrica Pavlinusic 2004-07-25
# - include signal grabbing
# - dynamic vncserver display 
# - correct WindowID parsing
# - wait for browser to load full page (useful on slow links)
#
# It will need follwing external utilities:
# vncserver
# mozilla-firefox
# HEAD (part or LWP perl library, it can be commented out)
# nc (netcat, to simulate web server)
# xwininfo (standard part of X-clients)
# import (part of ImageMagick package)
# xdotool (much more useful than xwit for this purpose)
#
# It will create snapshot of following size
W=1024
H=768
D=24

# and then resize it to (comment out to disable)
#RESIZE=200x

# turn locally visible server to watch progress
DEBUG=0
if [ ! -z "$3" ] ; then
	echo "DEBUG turned on"
	DEBUG=1
	D=8
fi

# wait for $WAIT seconds for page to load
WAIT=30

# some configurable paths
BROWSER=mozilla-firefox
XSERVER=Xvfb
URL=$1
FILE=${2:-screenshot.jpg}

FRAMESET="`mktemp`.html"
PROFILE_DIR=`mktemp -d`
PORT=8888

LOCAL_DISPLAY=$DISPLAY

if [ -z "$URL" ] ; then
	echo "usage: $0 http://url.to.capture [screenshot.jpg]"
	exit 1
fi

if [ -z "`which xdotool`" ] ; then
	echo "$0 need xdotool from http://www.semicomplete.com/blog/projects/xdotool/"
	exit 1
fi

if [ -z "`which $XSERVER`" ] ; then
	echo "$0 really need $XSERVER to operate. please install it."
	exit 1
fi

while netstat -ln | grep ":$PORT " >/dev/null ; do
	PORT=`expr $PORT + 1`
done

echo "### using port $PORT"

echo -n "testing URL $URL "
if HEAD $URL >/dev/null ; then
	echo "ok"
else
	echo "FAILED"
	exit 1
fi

DISPLAY_PORT=6042

while netstat -ln | grep ":$DISPLAY_PORT " >/dev/null ; do
	DISPLAY_PORT=`expr $DISPLAY_PORT + 1`
done

DISPLAY=:`expr $DISPLAY_PORT - 6000`

echo "using DISPLAY=$DISPLAY"

if [ "$DEBUG" == 1 ] ; then
	echo "using locally visible debug server on $LOCAL_DISPLAY"
	DISPLAY=$LOCAL_DISPLAY Xephyr -ac -screen ${W}x${H}x${D} $DISPLAY 2>/dev/null &
else
	echo "starting $XSERVER"
	$XSERVER -ac -screen 0 ${W}x${H}x${D} $DISPLAY 2>/dev/null &
fi

if [ -z "$!" ] ; then
	echo "ABORT: can't start X server!"
	exit
fi
XSERVER_PID=$!

echo "X server pid $XSERVER_PID"

function kill_x_server() {
	echo "Killing server $XSERVER_PID"
	kill $XSERVER_PID
	rm -f $FRAMESET
	rm -fr $PROFILE_DIR
	trap '' EXIT
	exit 1
}
trap 'kill_x_server' INT QUIT TERM SEGV EXIT

# create frameset to load site and after site is loaded trigger this script
cat > $FRAMESET <<END_OF_FRAMESET
<html>
<head>
<frameset rows="0,*" border=0 frameborder=no framespacing=0 onload="window.frames['trigger_frame'].window.location.replace('http://localhost:$PORT');">
  <frame src="about:blank" name="trigger_frame" scrolling=no marginwidth=0 marginheight=0>
  <frame src="$URL" name="page_frame" scrolling=no>
</frameset>
</head>
</html>
END_OF_FRAMESET

echo "Using frameset html $FRAMESET"

echo "preview available with: xwd -display $DISPLAY -root | xwud"

echo "making 'Screenshot' profile in $PROFILE_DIR"
$BROWSER -CreateProfile "Screenshot $PROFILE_DIR" 2>/dev/null | grep Success

echo "launching browser $BROWSER with $URL"
$BROWSER -P Screenshot -width $W -height $H -safemode $FRAMESET 2>/dev/null &
BROWSER_PID=$!

function kill_browser() {
	echo "Killing browser $BROWSER_PID"
	kill $BROWSER_PID
	echo "Killing server $XSERVER_PID"
	kill $XSERVER_PID
	rm -f $FRAMESET
	rm -fr $PROFILE_DIR
	trap '' EXIT
	exit 1
}
trap 'kill_browser' INT QUIT TERM SEGV EXIT

function ping_browser() {
	echo -n "ping browser"
	while ! ( $BROWSER -remote "ping();" 2>&1 ) >/dev/null ; do
		RID=`xdotool search Restore 2>/dev/null`
		if [ ! -z "$RID" ] ; then
			echo -n "Esc"
			xdotool focus $RID
			xdotool key Escape
			sleep 1
		fi
		echo -n "."
		sleep 1
	done
	echo " OK"
}

ping_browser

# get Mozilla Firefox window id (for resize)
WINDOW_ID=`xwininfo -display $DISPLAY -root -tree | grep gecko | cut -d\" -f1 | sort -n | head -1`

if [ -z "$WINDOW_ID" ] ; then
	echo "can't find window with name 'Mozilla Firefox'"
	exit 1
else
	echo "working on firefox window $WINDOW_ID"
fi

xdotool search firefox

xdotool focus $WINDOW_ID
xdotool key F11

ping_browser

$BROWSER -remote "openURL($FRAMESET)" 2>/dev/null

echo "waiting for on_load event from browser $BROWSER_PID for ${WAIT}s"

# there is hard-coded limit here:
# we will wait $WAIT sec for page to load and render

echo -e "HTTP/1.0 304 Not modified\r\n\r\n" | nc -l -w $WAIT -p $PORT >/dev/null || echo "Timeout after $WAIT sec!"

# try to deduce inside area of window

DUMP_ID=`xwininfo -display $DISPLAY -id $WINDOW_ID -tree | grep 0x | grep -v ${W}x${H} | grep ${W}x | head -1 | sed 's/^ *//' | cut -d' ' -f1`

if [ -z "$DUMP_ID" ] ; then
	echo "can't find inside area of window. Using whole browser!"
	DUMP_ID=$WINDOW_ID
fi

echo "saving window $DUMP_ID to $FILE"
if [ ! -z "$RESIZE" ] ; then
	RESIZE="-geometry $RESIZE"
fi

import -window $DUMP_ID $RESIZE $FILE

if [ "$DEBUG" == 1 ] ; then
	echo -n "press enter to exit! "
	read
fi
