Last active
March 5, 2024 15:43
-
-
Save DimitriGilbert/bf78c35208ae848c757b0e13fd39342c to your computer and use it in GitHub Desktop.
a simple bash program to play content from YT using mpv. It has a playlist like feature using --next "url". I use it on my RPI homelab from SSH.
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| #!/bin/bash# @parseArger-begin | |
| # @parseArger-help "I send an SOS to the world" --option "help" --short-option "h" | |
| # @parseArger-verbose --option "verbose" --level "0" --quiet-option "quiet" | |
| # @parseArger-declarations | |
| # @parseArger pos vid "video id" | |
| # @parseArger opt base-url "service url" --default-value "https://www.youtube.com/watch?v=" | |
| # @parseArger opt next "play next" --short n --repeat --alias playlist | |
| # @parseArger opt player-command "player command" --short p --default-value "mpv" --repeat --alias player | |
| # @parseArger opt set-display "set display id" --default-value "0" | |
| # @parseArger opt pulse-out "pulseaudio output sink id" --default-value "2" | |
| # @parseArger-declarations-end | |
| # @parseArger-utils | |
| _helpHasBeenPrinted=1; | |
| _SCRIPT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd -P)"; | |
| # @parseArger-utils-end | |
| # @parseArger-parsing | |
| __cli_arg_count=$#; | |
| die() | |
| { | |
| local _ret="${2:-1}" | |
| test "${_PRINT_HELP:-no}" = yes && print_help >&2 | |
| log "$1" -3 >&2 | |
| exit "${_ret}" | |
| } | |
| begins_with_short_option() | |
| { | |
| local first_option all_short_options='' | |
| first_option="${1:0:1}" | |
| test "$all_short_options" = "${all_short_options/$first_option/}" && return 1 || return 0 | |
| } | |
| # POSITIONALS ARGUMENTS | |
| _positionals=(); | |
| _optional_positionals=(); | |
| _arg_vid=""; | |
| # OPTIONALS ARGUMENTS | |
| _arg_base_url="https://www.youtube.com/watch?v=" | |
| _arg_next=() | |
| _arg_player_command=("mpv" --vid=no) | |
| _arg_set_display="0" | |
| _arg_pulse_out="2" | |
| # FLAGS | |
| # NESTED | |
| _verbose_level="0"; | |
| print_help() | |
| { | |
| _triggerSCHelp=1; | |
| if [[ "$_helpHasBeenPrinted" == "1" ]]; then | |
| _helpHasBeenPrinted=0; | |
| echo -e "I send an SOS to the world:" | |
| echo -e " vid: video id" | |
| echo -e " --base-url <base-url>: service url [default: ' https://www.youtube.com/watch?v= ']" | |
| echo -e " -n, --next|--playlist <next>: play next, repeatable" | |
| echo -e " -p, --player-command|--player <player-command>: player command, repeatable [default: '( mpv )']" | |
| echo -e " --set-display <set-display>: set display id [default: ' 0 ']" | |
| echo -e " --pulse-out <pulse-out>: pulseaudio output sink id [default: ' 2 ']" | |
| echo -e "Usage : | |
| $0 <vid> [--base-url <value>] [--next <value>] [--player-command <value>] [--set-display <value>] [--pulse-out <value>]"; | |
| fi | |
| } | |
| log() { | |
| local _arg_msg="${1}"; | |
| local _arg_level="${2:-0}"; | |
| if [ "${_arg_level}" -le "${_verbose_level}" ]; then | |
| case "$_arg_level" in | |
| -3) | |
| _arg_COLOR="\033[0;31m"; | |
| ;; | |
| -2) | |
| _arg_COLOR="\033[0;33m"; | |
| ;; | |
| -1) | |
| _arg_COLOR="\033[1;33m"; | |
| ;; | |
| 1) | |
| _arg_COLOR="\033[0;32m"; | |
| ;; | |
| 2) | |
| _arg_COLOR="\033[1;36m"; | |
| ;; | |
| 3) | |
| _arg_COLOR="\033[0;36m"; | |
| ;; | |
| *) | |
| _arg_COLOR="\033[0m"; | |
| ;; | |
| esac | |
| echo -e "${_arg_COLOR}${_arg_msg}\033[0m"; | |
| fi | |
| } | |
| parse_commandline() | |
| { | |
| _positionals_count=0 | |
| while test $# -gt 0 | |
| do | |
| _key="$1" | |
| case "$_key" in | |
| --base-url) | |
| test $# -lt 2 && die "Missing value for the option: '$_key'" 1 | |
| _arg_base_url="$2" | |
| shift | |
| ;; | |
| --base-url=*) | |
| _arg_base_url="${_key##--base-url=}" | |
| ;; | |
| -n|--playlist|--next) | |
| test $# -lt 2 && die "Missing value for the option: '$_key'" 1 | |
| _arg_next+=("$2") | |
| shift | |
| ;; | |
| --next=*) | |
| _arg_next+=("${_key##--next=}") | |
| ;; | |
| --playlist=*) | |
| _arg_next+=("${_key##--playlist=}") | |
| ;; | |
| -n*) | |
| _arg_next+=("${_key##-n}") | |
| ;; | |
| -p|--player|--player-command) | |
| test $# -lt 2 && die "Missing value for the option: '$_key'" 1 | |
| _arg_player_command+=("$2") | |
| shift | |
| ;; | |
| --player-command=*) | |
| _arg_player_command+=("${_key##--player-command=}") | |
| ;; | |
| --player=*) | |
| _arg_player_command+=("${_key##--player=}") | |
| ;; | |
| -p*) | |
| _arg_player_command+=("${_key##-p}") | |
| ;; | |
| --set-display) | |
| test $# -lt 2 && die "Missing value for the option: '$_key'" 1 | |
| _arg_set_display="$2" | |
| shift | |
| ;; | |
| --set-display=*) | |
| _arg_set_display="${_key##--set-display=}" | |
| ;; | |
| --pulse-out) | |
| test $# -lt 2 && die "Missing value for the option: '$_key'" 1 | |
| _arg_pulse_out="$2" | |
| shift | |
| ;; | |
| --pulse-out=*) | |
| _arg_pulse_out="${_key##--pulse-out=}" | |
| ;; | |
| -h|--help) | |
| print_help; | |
| exit 0; | |
| ;; | |
| -h*) | |
| print_help; | |
| exit 0; | |
| ;; | |
| --verbose) | |
| if [ $# -lt 2 ];then | |
| _verbose_level="$((_verbose_level + 1))"; | |
| else | |
| _verbose_level="$2"; | |
| shift; | |
| fi | |
| ;; | |
| --quiet) | |
| if [ $# -lt 2 ];then | |
| _verbose_level="$((_verbose_level - 1))"; | |
| else | |
| _verbose_level="-$2"; | |
| shift; | |
| fi | |
| ;; | |
| *) | |
| _last_positional="$1" | |
| _positionals+=("$_last_positional") | |
| _positionals_count=$((_positionals_count + 1)) | |
| ;; | |
| esac | |
| shift | |
| done | |
| } | |
| handle_passed_args_count() | |
| { | |
| local _required_args_string="vid" | |
| if [ "${_positionals_count}" -gt 1 ] && [ "$_helpHasBeenPrinted" == "1" ];then | |
| _PRINT_HELP=yes die "FATAL ERROR: There were spurious positional arguments --- we expect at most 1 (namely: $_required_args_string), but got ${_positionals_count} (the last one was: '${_last_positional}').\n\t${_positionals[*]}" 1 | |
| fi | |
| if [ "${_positionals_count}" -lt 1 ] && [ "$_helpHasBeenPrinted" == "1" ];then | |
| _PRINT_HELP=yes die "FATAL ERROR: Not enough positional arguments - we require at least 1 (namely: $_required_args_string), but got only ${_positionals_count}. | |
| ${_positionals[*]}" 1; | |
| fi | |
| } | |
| assign_positional_args() | |
| { | |
| local _positional_name _shift_for=$1; | |
| _positional_names="_arg_vid "; | |
| shift "$_shift_for" | |
| for _positional_name in ${_positional_names};do | |
| test $# -gt 0 || break; | |
| eval "if [ \"\$_one_of${_positional_name}\" != \"\" ];then [[ \"\${_one_of${_positional_name}[*]}\" =~ \"\${1}\" ]];fi" || die "${_positional_name} must be one of: $(eval "echo \"\${_one_of${_positional_name}[*]}\"")" 1; | |
| eval "$_positional_name=\${1}" || die "Error during argument parsing, possibly an ParseArger bug." 1; | |
| shift; | |
| done | |
| } | |
| print_debug() | |
| { | |
| print_help | |
| # shellcheck disable=SC2145 | |
| echo "DEBUG: $0 $@"; | |
| echo -e " vid: ${_arg_vid}"; | |
| echo -e " base-url: ${_arg_base_url}"; | |
| echo -e " next: ${_arg_next[*]}"; | |
| echo -e " player-command: ${_arg_player_command[*]}"; | |
| echo -e " set-display: ${_arg_set_display}"; | |
| echo -e " pulse-out: ${_arg_pulse_out}"; | |
| } | |
| on_interrupt() { | |
| die Process aborted! 130; | |
| } | |
| parse_commandline "$@"; | |
| handle_passed_args_count; | |
| assign_positional_args 1 "${_positionals[@]}"; | |
| trap on_interrupt INT; | |
| # @parseArger-parsing-end | |
| # print_debug "$@" | |
| # @parseArger-end | |
| if [[ $_arg_vid =~ ^https?:// ]] || [[ $_arg_vid =~ ^ftp:// ]] || [[ $_arg_vid =~ ^file:// ]]; then | |
| _topl="${_arg_vid}"; | |
| else | |
| _topl="${_arg_base_url}${_arg_vid}"; | |
| fi | |
| # DISPLAY=:${_arg_set_display} PULSE_SINK=${_arg_pulse_out} mpv --vid=no "$_topl"; | |
| export DISPLAY=:${_arg_set_display}; | |
| export PULSE_SINK=${_arg_pulse_out}; | |
| _plCmd=("${_arg_player_command[@]}" "$_topl"); | |
| "${_plCmd[@]}"; | |
| if [ "${#_arg_next[@]}" -ge 0 ]; then | |
| _nx=${_arg_next[0]}; | |
| _nxCmd=("$0" "$_nx" --base-url "${_arg_base_url}"); | |
| _nxArr=("${_arg_next[@]:1}"); | |
| if [ "${#_nxArr[@]}" -gt 0 ]; then | |
| for i in "${_nxArr[@]}"; do | |
| _nxCmd+=("--next" "$i"); | |
| done | |
| fi | |
| "${_nxCmd[@]}"; | |
| fi |
Author
DimitriGilbert
commented
Mar 5, 2024
Author
# set display 1
yt-mpv cVXMmGUBw34 --set-display 1
# set audio interface 0 (headphone jack on the RPI)
yt-mpv cVXMmGUBw34 --pulse-out 0
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment