diff --git a/scripts/yt-api-helper.sh b/scripts/yt-api-helper.sh new file mode 100755 index 0000000..38d6157 --- /dev/null +++ b/scripts/yt-api-helper.sh @@ -0,0 +1,337 @@ +#!/bin/zsh + + +print_help() +{ + echo "Usage: yt-api-helper -i [-c ] [-e ]" + echo "Usage: yt-api-helper -e -d " + echo "" + echo "Options:" + echo " -c,--client Client to use. Pass 'help' to this option to get" + echo " the list of supported clients" + echo " -d,--data Raw data to send to the API" + echo " -e,--endpoint Youtube endpoint to request. Pass 'help' to this" + echo " option to get the list of supported endpoints" + echo " -h,--help Show this help" + echo " -i,--interactive Run in interactive mode" + echo " -o,--output Print output to file instead of stdout" + echo "" +} + +print_clients() +{ + echo "Available clients:" + echo "web" +} + +print_endpoints() +{ + echo "Available endpoints:" + echo "browse" + echo "browse-continuation" + echo "next" + echo "next-continuation" + echo "player" + echo "resolve" +} + + +is_arg() +{ + case $1 in + -c|--client) true;; + -d|--data) true;; + -e|--endpoint) true;; + -h|--help) true;; + -i|--interactive) true;; + -o|--output) true;; + *) false;; + esac +} + + +# +# Parameters init +# + +interactive=false + +client_option="" +endpoint_option="" + +data="" + + +# +# Interactive client selection +# + +while :; do + # Exit if no more arguments to parse + if [ $# -eq 0 ]; then break; fi + + case $1 in + -c|--client) + shift + + if [ $# -eq 0 ] || $(is_arg "$1"); then + echo "Error: missing argument after -c/--client" + return 2 + fi + + client_option=$1 + ;; + + -d|--data) + shift + + if [ $# -eq 0 ] || $(is_arg "$1"); then + echo "Error: missing argument after -d/--data" + return 2 + fi + + data=$1 + ;; + + -e|--endpoint) + shift + + if [ $# -eq 0 ] || $(is_arg "$1"); then + echo "Error: missing argument after -e/--endpoint" + return 2 + fi + + endpoint_option=$1 + ;; + + -h|--help) + print_help + return 0 + ;; + + -i|--interactive) + interactive=true + ;; + + -o|--output) + shift + + if [ $# -eq 0 ] || $(is_arg "$1"); then + echo "Error: missing argument after -o/--output" + return 2 + fi + + output="$1" + ;; + + *) + echo "Error: unknown argument '$1'" + return 2 + ;; + esac + + shift +done + + +# +# Input validation +# + +if [ ! -z "$data" ]; then + # Can't pass data in interactive mode + if [ $interactive = true ]; then + echo "Error: -d/--data can't be used with -i/--interactive" + return 2 + fi + + # Can't pass client in non-interactive mode (must be part of data) + if [ ! -z $client_option ]; then + echo "Error: -c/--client can't be used with -d/--data" + return 2 + fi + + # Endpoint must be given if non-interactive mode + if [ -z $endpoint_option ]; then + echo "Error: In non-interactive mode, an endpoint must be passed with -e/--endpoint" + return 2 + fi +fi + +if [ -z "$data" ] && [ $interactive = false ]; then + # Data must be given if non-interactive mode + echo "Error: In non-interactive mode, data must be passed with -d/--data" + return 2 +fi + +if [ -z "$output" ] && [ $interactive = true ]; then + printf "\nIt is recommended to use --output in interactive mode.\nContinue? [y/N]: " + read confirm + + if [ -z $confirm ]; then confirm="n"; fi + + case $confirm in + [Yy]|[Yy][Ee][Ss]) ;; + *) return 0;; + esac +fi + + +# +# Client selection +# + +if [ -z $client_option ]; then + printf "Enter a client to use [web]: " + read client_option + + if [ -z $client_option ]; then client_option="web"; fi +fi + +case $client_option in + help) + print_clients + return 0 + ;; + + web) + apikey="AIzaSyAO_FJ2SlqU8Q4STEHLGCilw_Y9_11qcW8" + client_name="WEB" + client_vers="2.20210330.08.00" + ;; + + *) + echo "Error: Unknown client '$client_option'" + echo "" + print_clients + return 1 + ;; +esac + + +# +# Endpoint selection +# + +if [ -z $endpoint_option ]; then + printf "Enter an endpoint to request []: " + read endpoint_option +fi + +case $endpoint_option in + help) + print_endpoints + return 0 + ;; + + browse) + endpoint="youtubei/v1/browse" + + if [ $interactive = true ]; then + printf "Enter browse ID [UCXuqSBlHAE6Xw-yeJA0Tunw]: " + read browse_id + + if [ -z $browse_id ]; then browse_id="UCXuqSBlHAE6Xw-yeJA0Tunw"; fi + partial_data="\"browseId\":\"${browse_id}\"" + fi + ;; + + browse-cont*|browse-tok*) + endpoint="youtubei/v1/browse" + + if [ $interactive = true ]; then + printf "Enter continuation token []: " + read token + + if [ -z $toekn ]; then echo "Error: token required"; return 1; fi + partial_data="\"continuation\":\"${token}\"" + fi + ;; + + player|next) + endpoint="youtubei/v1/$endpoint_option" + + if [ $interactive = true ]; then + printf "Enter video ID [dQw4w9WgXcQ]: " + read vid + + if [ -z $vid ]; then vid="dQw4w9WgXcQ"; fi + partial_data="\"videoId\":\"${vid}\"" + fi + ;; + + next-cont*|next-tok*) + endpoint="youtubei/v1/next" + + if [ $interactive = true ]; then + printf "Enter continuation token []: " + read token + + if [ -z $toekn ]; then echo "Error: token required"; return 1; fi + partial_data="\"continuation\":\"${token}\"" + fi + ;; + + resolve) + endpoint="navigation/resolve_url" + + if [ $interactive = true ]; then + printf "Enter URL []: " + read url + + if [ -z $url ]; then echo "Error: URL required"; return 1; fi + partial_data="\"url\":\"${url}\"" + fi + ;; + + *) + echo "Error: Unknown endpoint '$endpoint_option'" + echo "" + print_clients + return 1 + ;; +esac + + +# +# Interactive language/region selection +# + +if [ $interactive = true ]; then + printf "Enter content language (hl) [en]: " + read hl + + printf "Enter content region (gl) [US]: " + read gl + + if [ -z $hl ]; then hl="en"; fi + if [ -z $gl ]; then gl="US"; fi + + client="\"clientName\":\"${client_name}\",\"clientVersion\":\"${client_vers}\",\"hl\":\"${hl}\",\"gl\":\"${gl}\"" +fi + + +# +# Final command +# + +if [ $interactive = true ]; then + data="{\"context\":{\"client\":{$client}},$partial_data}" + + # Basic debug + echo "sending:" + echo "$data" | sed 's/{/{\n/g; s/}/\n}/g; s/,/,\n/g' +fi + + +url="https://www.youtube.com/${endpoint}?key=${apikey}" + +# Headers +hdr_ct='Content-Type: application/json; charset=utf-8' +hdr_ua='User-Agent: Mozilla/5.0 (Windows NT 10.0; rv:78.0) Gecko/20100101 Firefox/78.0' + +# Default to STDOUT if no output file was given +if [ -z "output" ]; then output='-'; fi + +# Run! +curl --compressed -o "$output" -H "$hdr_ct" -H "$hdr_ua" --data "$data" "$url"