#!/bin/bash

# WARNING: This is a terribly dirty and messy shellscript, written over a
# couple of late nights. There was alcohol …
#
# Further tweaks and porting to free codecs done one early Saturday morning
# in May. There was no coffee … and very little experience with vp8
#
# So this script allows you to create screencasts on Linux, with optional
# sound inputs (both Microphone and system sounds). It stores system sounds
# and microphone in separate audio streams.
#
# It dumps the recording in your $HOME directory with a filename like
# screencast-YYYY-MM-DD-HH-MM-SS.mp4
#
# Written by Einar Jørgen Haraldseid (http://einar.slaskete.net)
# License: http://sam.zoy.org/wtfpl/COPYING

# Get device names and pretty names for enumerating playback sinks:
PLAYSINKLIST=$(pacmd list-sinks | \
 grep -e "name: " -e "device.description = " | cut -d " " -f "2-" | \
 sed -e "s/name: \|= //g" -e "s/<\|>\|\x22//g")

# Display playback monitor chooser
PLAYMON=$(echo "${PLAYSINKLIST}
none
Don't capture system sounds" | \
 zenity --list --title "Choose Output Device" \
 --text "Choose a sound device to capture system sound from:" \
 --column "device" --column "Name" --print-column=1 \
 --hide-column=1 2>/dev/null)

# Catch cancel
if [ -z ${PLAYMON} ]; then
  echo "No choice made on output device, assuming cancel."
  exit 1
fi

if [ ${PLAYMON} != "none" ]; then
  # Unmute monitor of the playback sink (if set):
  PLAYMON="${PLAYMON}.monitor"
  pacmd set-source-mute ${PLAYMON} false >/dev/null
  echo "Recording system sounds from ${PLAYMON}"
else
  echo "Not recording system sounds."
fi

# Get device names and pretty names for microphones:
MICLIST=$(pacmd list-sources | \
 grep -e "name: " -e "device.description = " | \
 grep -v -i "monitor" | cut -d " " -f "2-" | \
 sed -e "s/name: \|= //g" -e "s/<\|>\|\x22//g")

# Display device chooser
MIC=$(echo "${MICLIST}
none
Don't use a microphone" | \
 zenity --list --title "Choose Microphone" \
 --text "Choose a microphone to capture voice from:" \
 --column "device" --column "Name" --print-column=1 \
 --hide-column=1 2>/dev/null)

if [ -z ${MIC} ]; then
  echo "No choice made on microphone, assuming cancel."
  exit 1
fi

if [ ${MIC} != "none" ]; then
  echo "Recording voice from ${MIC}"
else
  echo "Not recording voice."
fi

# Get target window for recording:
TARGET=$(echo "root
Whole screen
window
Specific window" | \
 zenity --list --title "Choose recording mode" \
 --text "Do you want to record the whole screen,\
 or record a specific window?" --column "target" \
 --column "Mode" --print-column=1 --hide-column=1 2>/dev/null)

if [ -z ${TARGET} ]; then
  echo "No choice for recording target, assuming cancel."
  exit 1
fi

if [ ${TARGET} = "root" ]; then
  echo "Root window chosen."
  XWININFO=$(xwininfo -root)
else
  echo "Custom window chosen."
  XWININFO=$(xwininfo)
fi

# Get Window ID and dimensions, make sure X and Y dimensions are
# divisible by two, or else the encoder might fail
WID=$(echo "${XWININFO}" | grep "Window id:" | awk '{print $4}')
WIDTH=$(echo "${XWININFO}" | grep "Width: " | \
 cut -d ":" -f 2 | awk '{print $1+$1%2}')
HEIGHT=$(echo "${XWININFO}" | grep "Height: " | \
 cut -d ":" -f 2 | awk '{print $1+$1%2}')

# Calculate a suitable bitrate based on window dimensions
BITRATE=$(echo "${WIDTH} * ${HEIGHT} * 0.85" | bc | cut -d "." -f 1 )

# Set file name.
FILENAME="screencast-$(date +%F-%H-%M-%S).webm"

# Enable inputs as suitable
if [ ${PLAYMON} != "none" ]; then
  MONITORARG="pulsesrc device=${PLAYMON} slave-method=0 provide-clock=false \
   ! audiorate ! audioconvert ! vorbisenc ! queue2 ! mux."
fi
if [ ${MIC} != "none" ]; then
  MICARG="pulsesrc device=${MIC} slave-method=0 provide-clock=false \
   ! audiorate ! audioconvert ! vorbisenc ! queue2 ! mux."
fi

# Launch gstreamer
gst-launch-1.0 -q -e ximagesrc xid="${WID}" do-timestamp=1 use-damage=0 \
 ! video/x-raw,framerate=20/1 ! videoscale method=0 \
 ! video/x-raw,width=${WIDTH},height=${HEIGHT} ! videoconvert \
 ! vp8enc end-usage=vbr cpu-used=16 target-bitrate=${BITRATE} \
    deadline=100 static-threshold=1000 min-quantizer=0 max-quantizer=63 ! queue2 \
 ! webmmux name="mux" \
 ! filesink location="${HOME}/${FILENAME}" ${MONITORARG} ${MICARG}

echo "Recording done, file is ${FILENAME}"
