#!/bin/sh # Depends: GNU getopt, mpv, socat, streamlink, xclip SOCK="/tmp/umpv-fifo" help() { B=$(tput bold) U=$(tput smul) N=$(tput sgr0) cat << EOF ${B}NAME${N} play - mpv playback functions ${B}SYNOPSIS${N} ${B}play${N} [${U}OPTION${N}] [${U}ARGS${N}...] ${B}DESCRIPTION${N} play is a script to manage different mpv viewing bahavior. If no ${U}URLS${N} argument is provided, it is read from the clipboard instead. The queue option starts a mpv window with a playlist, which all videos of subsequent queue calls get added to. ${B}OPTIONS${N} ${B}-h${N}, ${B}--help${N} Display usage message and exit. ${B}-q${N}, ${B}--quality${N} ${U}QUALITY${N} Set the video quality, example: ${U}720p60${N}. ${B}-f${N}, ${B}--shuffle${N} [${U}URLS${N}...] Shuffle audio playlist (disables video playback). ${B}-u${N}, ${B}--queue${N} [${U}URLS${N}...] Add multiple videos to the unique mpv's queue. ${B}-s${N}, ${B}--stream${N} [${U}URLS${N}...] Play video(s) using streamlink. ${B}-l${N}, ${B}--low-latency${N} Enable twitch low-latency mode in streamlink. EOF } # -------------------------------------- qualityFormat() { url="$1" # Twitch urls dont support fancy matching if echo "$url" | grep -q "twitch\.tv"; then if [ -z "$quality" ]; then echo "Source" else echo "$quality" fi return fi # , separator = download several formats # + separator = merge several formats into a single file # / separator = or if [ -z "$quality" ]; then echo "bestvideo[height<=?1080]+bestaudio/best" else height="$(echo "$quality" | awk -F 'p' '{ print $1 }')" fps="$(echo "$quality" | awk -F 'p' '{ print $2 }')" format="bestvideo[height<=?$height]" if [ -n "$fps" ]; then format="${format}[fps<=?$fps]" fi format="$format+bestaudio/best" echo "$format" fi } play() { url="$1" notify-send -t 2500 "Loading video: $url" setsid -f mpv --no-terminal \ --ytdl-format="$(qualityFormat "$url")" \ --ytdl-raw-options=add-metadata=,external-downloader=aria2c \ "$url" } shuffle() { urls="$*" mpv --no-video --shuffle \ --ytdl-format='bestaudio[ext=m4a]' \ --ytdl-raw-options=add-metadata=,external-downloader=aria2c \ "$urls" } queue() { urls="$*" options="--no-terminal --force-window --input-ipc-server=$SOCK" # Create mpv cache directory dir="$(dirname "$SOCK")" [ ! -d "$dir" ] && mkdir -p "$dir" # Delete socket if no umpv is running if ! pgrep -f "mpv $options" > /dev/null; then rm -f "$SOCK" fi if [ -S "$SOCK" ]; then notify-send -t 2500 "Added video to queue.." # Add video to named pipe echo "$urls" | awk -v RS=' ' '{ print "raw loadfile "$1" append" }' \ | socat UNIX-CONNECT:"$SOCK" - else # Play video notify-send -t 2500 "Loading video: $urls" # shellcheck disable=2086 setsid -f mpv $options \ --ytdl-format="$(qualityFormat $urls)" \ --ytdl-raw-options=add-metadata=,external-downloader=aria2c \ $urls fi } stream() { channel="$1" quality="$2" lowLatency="$3" if [ -z "$quality" ]; then if ! streamlink --quiet --config /dev/null "$channel"; then return 1 fi printf "Select stream quality: " read -r quality fi if [ -z "$lowLatency" ]; then arguments="\ --player-args '--force-window'" else arguments="\ --twitch-low-latency \ --player-args '--force-window --cache=yes --demuxer-max-bytes=750k'" fi echo "Starting stream $channel @ $quality" command="setsid -f streamlink \ --twitch-disable-hosting \ --twitch-disable-reruns \ --player mpv \ --stream-sorting-excludes '<480p,>=1080p' \ $arguments \ $channel $quality > /dev/null 2>&1" eval "$command" } # Option parsing # -------------------------------------- script="$(basename "$0")" parsed="$(getopt --options "hslquf" \ --longoptions "help,stream,quality,queue,shuffle" \ -n "$script" -- "$@" 2>&1)" result="$?" # Exit if invalid option is provided if [ "$result" -ne 0 ]; then echo "$parsed" | head -n 1 >&2 echo "Try './$script --help' for more information." >&2 exit 1 fi eval set -- "$parsed" streamOption=0 qualityOption=0 lowLatencyOption=0 queueOption=0 shuffleOption=0 while true; do case "$1" in -h | --help) help exit ;; -s | --stream) streamOption=1 shift ;; -l | --low-latency) lowLatencyOption=1 shift ;; -q | --quality) qualityOption=1 shift ;; -u | --queue) queueOption=1 shift ;; -f | --shuffle) shuffleOption=1 shift ;; --) shift break ;; *) break ;; esac done # Target parsing # -------------------------------------- # Incompatible flags result=$((streamOption + queueOption + shuffleOption)) if [ $result -gt 1 ]; then echo "Incompatible flags." >&2 echo "Try './$script --help' for more information." >&2 exit 1; fi # Get quality if [ $qualityOption -eq 1 ]; then quality="$1" shift fi # Set url to clipboard if none provided clip="$(xclip -selection clipboard -out)" if [ "$#" -eq 0 ]; then eval set -- "$clip" fi [ $lowLatencyOption -eq 1 ] && lowLatency="1" # Execute # -------------------------------------- if [ $streamOption -eq 1 ]; then for url in "$@"; do stream "$url" "$quality" "$lowLatency" done elif [ $shuffleOption -eq 1 ]; then shuffle "$*" elif [ $queueOption -eq 1 ]; then queue "$*" else if [ "$*" = "" ]; then play "$(xclip -o)" else for url in "$@"; do play "$url" done fi fi