#!/usr/bin/env bash
#
# Behavior:
#   Userscript for qutebrowser which views the current web page in mpv using
#   sensible mpv-flags. While viewing the page in MPV, all <video>, <embed>,
#   and <object> tags in the original page are temporarily removed. Clicking on
#   such a removed video restores the respective video.
#
#   In order to use this script, just start it using `spawn --userscript` from
#   qutebrowser. I recommend using an alias, e.g. put this in the
#   [alias]-section of qutebrowser.conf:
#
#     mpv = spawn --userscript /path/to/view_in_mpv
#
# Background:
#   Most of my machines are too slow to play youtube videos using html5, but
#   they work fine in mpv (and mpv has further advantages like video scaling,
#   etc). Of course, I don't want the video to be played (or even to be
#   downloaded) twice — in MPV and in qwebkit. So I often close the tab after
#   opening it in mpv. However, I actually want to keep the rest of the page
#   (comments and video suggestions), i.e. only the videos should disappear
#   when mpv is started. And that's precisely what the present script does.
#
# Thorsten Wißmann, 2015 (thorsten` on Libera Chat)
# Any feedback is welcome!

set -e

if [ -z "$QUTE_FIFO" ] ; then
    cat 1>&2 <<EOF
Error: $0 can not be run as a standalone script.

It is a qutebrowser userscript. In order to use it, call it using
'spawn --userscript' as described in qute://help/userscripts.html
EOF
    exit 1
fi

msg() {
    local cmd="$1"
    shift
    local msg="$*"
    if [ -z "$QUTE_FIFO" ] ; then
        echo "$cmd: $msg" >&2
    else
        echo "message-$cmd '${msg//\'/\\\'}'" >> "$QUTE_FIFO"
    fi
}

MPV_COMMAND=${MPV_COMMAND:-mpv}
# Warning: spaces in single flags are not supported
MPV_FLAGS=${MPV_FLAGS:- --force-window --no-terminal --keep-open=yes --ytdl}
IFS=" " read -r -a video_command <<< "$MPV_COMMAND $MPV_FLAGS"

js() {
cat <<EOF

    function descendantOfTagName(child, ancestorTagName) {
        // tells whether child has some (proper) ancestor
        // with the tag name ancestorTagName
        while (child.parentNode != null) {
            child = child.parentNode;
            if (typeof child.tagName === 'undefined') break;
            if (child.tagName.toUpperCase() == ancestorTagName.toUpperCase()) {
                return true;
            }
        }
        return false;
    }

    var App = {};

    var all_videos = [];
    all_videos.push.apply(all_videos, document.getElementsByTagName("video"));
    all_videos.push.apply(all_videos, document.getElementsByTagName("object"));
    all_videos.push.apply(all_videos, document.getElementsByTagName("embed"));
    App.backup_videos = Array();
    App.all_replacements = Array();
    for (i = 0; i < all_videos.length; i++) {
        var video = all_videos[i];
        if (descendantOfTagName(video, "object")) {
            // skip tags that are contained in an object, because we hide
            // the object anyway.
            continue;
        }
        var replacement = document.createElement("div");
        replacement.innerHTML = "
            <p style=\\"margin-bottom: 0.5em\\">
            Opening page with:
            <span style=\\"font-family: monospace;\\">${video_command[*]}</span>
            </p>
            <p>
            In order to restore this particular video
            <a style=\\"font-weight: bold;
                        color: white;
                        background: transparent;
                     \\"
               onClick=\\"restore_video(this, " + i + ");\\"
               href=\\"javascript: restore_video(this, " + i + ")\\"
              >click here</a>.
            </p>
        ";
        replacement.style.position = "relative";
        replacement.style.zIndex = "100003000000";
        replacement.style.fontSize = "1rem";
        replacement.style.textAlign = "center";
        replacement.style.verticalAlign = "middle";
        replacement.style.height = "100%";
        replacement.style.background = "#101010";
        replacement.style.color = "white";
        replacement.style.border = "4px dashed #545454";
        replacement.style.padding = "2em";
        replacement.style.margin = "auto";
        App.all_replacements[i] = replacement;
        App.backup_videos[i] = video;
        video.parentNode.replaceChild(replacement, video);
    }

    function restore_video(obj, index) {
        obj = App.all_replacements[index];
        video = App.backup_videos[index];
        console.log(video);
        obj.parentNode.replaceChild(video, obj);
    }

    /** force repainting the video, thanks to:
     * http://web.archive.org/web/20151029064649/https://martinwolf.org/2014/06/10/force-repaint-of-an-element-with-javascript/
     */
    var siteHeader = document.getElementById('header');
    siteHeader.style.display='none';
    siteHeader.offsetHeight; // no need to store this anywhere, the reference is enough
    siteHeader.style.display='block';

EOF
}

printjs() {
    js | sed 's,//.*$,,' | tr '\n' ' '
}
echo "jseval -q $(printjs)" >> "$QUTE_FIFO"

msg info "Opening $QUTE_URL with mpv"
"${video_command[@]}" "$@" "$QUTE_URL"
