Add a basic YT API utility script

(made in bash)

This utility script is intended for research on the innertube
API so the developper can query the API without having to compile
invidious nor need to copy-paste the same commands over and over.
This commit is contained in:
Samantaz Fox 2021-10-25 20:02:13 +02:00
parent 6931797a9f
commit b51609a2df

337
scripts/yt-api-helper.sh Executable file
View File

@ -0,0 +1,337 @@
#!/bin/zsh
print_help()
{
echo "Usage: yt-api-helper -i [-c <client>] [-e <endpoint>]"
echo "Usage: yt-api-helper -e <endpoint> -d <data>"
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"