| #!/bin/bash |
| # |
| # Try to download a flash movie from current ff window. |
| # |
| # Downloads are kept in a cache directory of fixed size, oldest |
| # files are removed as required. Last download is kept with a |
| # fixed name such as 'svtplay.flv' or 'youtube.flv'. Older downloads |
| # are stored with names retrieved from source. |
| # |
| # Prerequisites: |
| # - One firefox window with a page containing a flash video on |
| # current DISPLAY. |
| # |
| # - The CACHE_DIR directory should exist or be possible to create. |
| # |
| # Multiple invocations: |
| # - A running instance initially blocks other instances from |
| # running to not mess with the ff state. Invocations during |
| # this time are logged but otherwise silently ignored. |
| # |
| # - Later attempts to start downloading to same location will kill |
| # running process and overwrite dl location. |
| # |
| # - Later attempts to start downloading to other locations runs in |
| # parallel. |
| # |
| # Dependencies: |
| # xdotool, xsel, get_flash_videos, zenity, xorg-x11-utils |
| # |
| # Bugs: |
| # Fragile, does not use stable API:s, just happens to work |
| # occasionally. |
| |
| readonly FF_WINDOW_NAME='Mozilla Firefox' |
| readonly DEFAULTS_FILE='/etc/sysconfig/ff-get-flash-video' |
| readonly DEFAULT_CACHE_SIZE=5 |
| |
| |
| function get_cachedir() |
| { |
| local xdg_setup_dirs="${XDG_CONFIG_HOME:-$HOME/.config}/user-dirs.dirs" |
| test -r "$xdg_setup_dirs" && source "$xdg_setup_dirs" |
| dir=${XDG_DOWNLOAD_DIR:-$HOME}/flash |
| test -d $dir || mkdir $dir || echo "Cannot create $dir" >&2 |
| echo $dir |
| } |
| |
| |
| [ -r $DEFAULTS_FILE ] && source $DEFAULTS_FILE |
| CACHE_DIR=${CACHE_DIR:-$( get_cachedir )} |
| CACHE_SIZE=${CACHE_SIZE:-$DEFAULT_CACHE_SIZE} |
| |
| |
| function usage() |
| { |
| cat <<EOF |
| |
| Find out what flash video Firefox is running and download it. |
| |
| Usage: $(basename $0) [options] |
| |
| Options |
| -d <dir> Download directory, defaults to $CACHE_DIR. |
| -s <size> Cache size i.e., number of downloaded files kept. |
| Defaults to $CACHE_SIZE. |
| |
| Assumes a single firefox window opened with a flash movie running. |
| EOF |
| } |
| |
| |
| function get_options() |
| { |
| while getopts 'd:s:h' opt; do |
| case $opt in |
| s) CACHE_SIZE=$OPTARG;; |
| d) CACHE_DIR=$OPTARG;; |
| h) usage; exit 0;; |
| *) usage; exit 1;; |
| esac |
| done |
| |
| LOGFILE="$CACHE_DIR/flash-download.trace" |
| LOCK_FILE="$CACHE_DIR/.lock" |
| readonly CACHE_SIZE CACHE_DIR LOGFILE LOCK_FILE |
| } |
| |
| |
| function error_msg() { zenity --error --timeout=4 --text="$1"; } |
| |
| function warning_msg() { zenity --warning --timeout=4 --text="$1"; } |
| |
| function info_msg() { zenity --info --timeout=4 --text="$1"; } |
| |
| |
| function get_size() |
| # Return size of single file argument on stdout, no file returns "0". |
| { |
| if [ -f $1 ]; then |
| ls -l $1 | awk '{print $5}' |
| else |
| echo "0" |
| fi |
| } |
| |
| |
| function get_ff_window() |
| # Return current ff window id, bailing out on missing or multiple |
| # ff window(s). |
| { |
| local win |
| |
| win=$( xdotool search --name "$FF_WINDOW_NAME" ) || win="" |
| if [ -z "$win" ]; then |
| error_msg "No Firefox window!" |
| exit 1 |
| fi |
| if [ "$win" != "${win%% *}" ]; then |
| error_msg "Two (or more) Firefox windows" |
| exit 1 |
| fi |
| echo $win |
| } |
| |
| |
| function get_ff_window_width_height() |
| # Echo shell line like 'width=xxx height=yyy' for window argument. |
| { |
| local win=$1 |
| xwininfo -id "$win" | |
| awk '/Width:/ { w = $2 } |
| /Height:/ { h = $2 } |
| END { printf "width=%s height=%s\n", w, h }' |
| } |
| |
| |
| function get_fullscreen() |
| # Echo 'yes' or 'no' reflecting whether ff is running in fullscreen. |
| { |
| local win=$1 |
| local width height |
| eval $( get_ff_window_width_height $win ) |
| local window_dim="${width}x${height}" |
| |
| screen_dim=$( xdpyinfo | awk ' /dimensions:/ { print $2}') |
| |
| if [ "$window_dim" = "$screen_dim" ]; then |
| echo "yes" |
| else |
| echo "no" |
| fi |
| } |
| |
| |
| function get_ff_url() |
| # Select and copy url from ff (current window) to X clipboard. |
| { |
| fullscreen=$1 |
| if [[ $fullscreen == *n* ]]; then |
| xdotool key alt+d ctrl+c |
| else |
| xdotool key F11 alt+d ctrl+c F11 |
| fi |
| } |
| |
| |
| function get_ff_location() |
| # Get location from current ff window |
| # Arg: ff window id. |
| { |
| local win="$1" |
| local fullscreen="$2" |
| |
| local width height |
| eval $( get_ff_window_width_height $win ) |
| |
| local X Y SCREEN WINDOW |
| eval $(xdotool getmouselocation --shell) |
| echo "No-url" | xsel -ib |
| |
| xdotool windowactivate "$win" |
| |
| # Try to click outside video widget, it doesn't pass alt-d,ctrl-c. |
| # alt+d, ctrl+c = "select location bar", "copy" keyboard shortcuts. |
| xdotool mousemove --sync $(( $width/2 )) $(( $height - 1 )) |
| get_ff_url $fullscreen |
| |
| for delay in 0.1 0.2 0.3 0.5 0.8; do |
| sleep $delay |
| url=$( xsel -ob ) |
| [[ "$url" != *No-url* ]] && break |
| get_ff_url $fullscreen |
| done |
| |
| if [[ "$url" == *No-url* ]]; then |
| error_msg "Can\'t copy url from firefox (!)" |
| exit 2 |
| fi |
| |
| xdotool mousemove $X $Y |
| echo $url |
| } |
| |
| |
| function rotate_cache() |
| # Ensure there are at most CACHE_SIZE - 1 downloads in cache, |
| # remove old log files. Rename newest file to it's "native" |
| # name as hinted by flash-download. |
| { |
| ( |
| cd $CACHE_DIR |
| [ -f ".rename-head" ] && \ |
| eval "$( cat .rename-head)" && rm ".rename-head" |
| rm $( ls -t --hide '*.log' | awk "NR > $((CACHE_SIZE - 1))" ) \ |
| &>/dev/null || : |
| rm $( find . -mtime +1 -name '*.log' ) &>/dev/null || : |
| ) |
| } |
| |
| |
| function check_running_process() |
| # Exit if there is a running process messing w ff, else accquire lock. |
| { |
| if [ -f $LOCK_FILE ]; then |
| local pid=$( cat $LOCK_FILE ) |
| if [ "$( ps --pid "$pid" -o uid --no-headers )" = '' ]; then |
| logger "$0: Removing stale lock file, pid: $pid" |
| echo "Removing stale lock file" >&2 |
| rm -f $LOCK_FILE |
| fi |
| fi |
| local tmp_pid=$( mktemp ) |
| echo $$ > $tmp_pid |
| mv --no-clobber $tmp_pid $LOCK_FILE |
| local lock_pid=$(cat $LOCK_FILE) |
| rm -f "$tmp_pid" |
| if [ "$lock_pid" != "$$" ]; then |
| logger "$0: Another instance is messing with FF, exiting" |
| exit 3 |
| fi |
| } |
| |
| |
| function get_dl_path |
| { |
| local location=$1 |
| local key value |
| get_flash_videos --info $location | while read key value; do |
| [ "$key" = 'Filename:' ] && echo "$value" |
| done |
| } |
| |
| |
| function setup_nickname() |
| { |
| local location=$1 |
| |
| local dl_path=$( get_dl_path $location ) |
| if [ "$dl_path" = "" ] ; then |
| error_msg "Can't download from Firefox" |
| exit 1 |
| fi |
| local nickname=${location%.*} |
| nickname=${nickname#*://} |
| nickname=${nickname#www.}.flv |
| echo "mv '$nickname' '$dl_path'" > "$CACHE_DIR/.rename-head" |
| echo $nickname |
| } |
| |
| |
| get_options $@ |
| |
| exec 1>$LOGFILE 2>&1 |
| set -x |
| |
| check_running_process |
| |
| wid=$( get_ff_window ) |
| fullscreen=$( get_fullscreen $wid ) |
| location=$( get_ff_location $wid $fullscreen ) || exit 1 |
| nickname=$( setup_nickname $location ) || exit 2 |
| |
| dl_file="$CACHE_DIR/$nickname" |
| logfile=${dl_file/.flv/.log} |
| rotate_cache |
| |
| pkill -f "get_flash_videos.*$dl_file" && sleep 1 |
| get_flash_videos -q -f $dl_file $location &>$logfile & |
| dl_pid=$! |
| rm -f $LOCK_FILE |
| |
| info_msg "Download started" & |
| |
| sleep 1; size_1=$( get_size $dl_file) |
| sleep 10; size_2=$( get_size $dl_file) |
| |
| if (( "$size_1" == "$size_2" || "$size_2" == '0' )); then |
| msg="Warning: Download seem to have stalled, $size_2 bytes downloaded" |
| warning_msg "$msg" & |
| fi |
| |
| if wait $dl_pid; then |
| info_msg "Download complete" |
| else |
| result=$? |
| test $result -gt 127 && echo "Interrupted!" >> $logfile |
| echo "Result: $result" >> $logfile |
| fi |
| |
| exit 0 |