mirror of
https://gitea.invidious.io/iv-org/youtube-utils.git
synced 2024-08-15 00:53:16 +00:00
338 lines
6.1 KiB
Bash
338 lines
6.1 KiB
Bash
|
#!/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"
|