215 lines
7.2 KiB
Bash
Executable File
215 lines
7.2 KiB
Bash
Executable File
#!/bin/bash
|
|
|
|
# DISCLAIMER: this script has been started solely by me (sayan01)
|
|
# and has had contributions from others like Nicholas-Baron and
|
|
# juanCortelezzi (refer to contributors on github for details)
|
|
# this script is not based off of any other work by anyone else,
|
|
# nor is it made in association with anyone else, regardless of
|
|
# their claims.
|
|
|
|
# Dependencies: mpv youtube-dl fzf rofi/dmenu gnu-grep
|
|
|
|
# NOTE: if you don't have gnu grep, you can replace grep with rg
|
|
|
|
# Explain usage
|
|
function usage () {
|
|
printf "usage: yt\n"
|
|
printf " -h help\n"
|
|
printf " -c channels/subscriptions\n"
|
|
printf " -s query search\n"
|
|
printf " -g / -r gui mode (rofi/dmenu)\n"
|
|
printf " -m music mode (audio only) [dont use with -r]\n"
|
|
printf " nothing use defaults (search from prompt)\n"
|
|
printf "\n"
|
|
printf "add channel names to the file %s to show them\n" "$sublistpath"
|
|
printf "in yt -c option. First word should be channel url, optionally\n"
|
|
printf "followed by tab and then anything else (channel name/description)\n"
|
|
printf "channels not in sublist can be viewed by typing their url in the prompt\n"
|
|
printf "\n"
|
|
printf "example file format:\n"
|
|
printf "markrober Mark Rober\n"
|
|
printf "vsauce1 VSauce Michael Steven's Channel\n"
|
|
printf "BlackGryph0n Black Gryph0n Gabriel Brown signs stuff\n"
|
|
printf "TomScottGo Tom Scott\n"
|
|
printf "danielthrasher Daniel Thrasher\n"
|
|
exit 0
|
|
}
|
|
|
|
# Use defaults if no arguments provided
|
|
useDefaults="f"
|
|
if [[ ${#} -eq 0 ]]; then
|
|
useDefaults="t"
|
|
fi
|
|
|
|
# Available flags
|
|
optstring=":s:cgrhm"
|
|
|
|
defcmd="fzf"
|
|
defaction="s"
|
|
guicmd="rofi -dmenu -i" # uncomment next line for dmenu
|
|
# guicmd="dmenu -i -l 15"
|
|
|
|
# Defaults
|
|
promptcmd="$defcmd"
|
|
action="$defaction"
|
|
isGui="f"
|
|
query=""
|
|
mpv_options=""
|
|
|
|
max_resolution="480"
|
|
max_fps="30"
|
|
ignore_codec=""
|
|
ytdlformats="bestvideo"
|
|
|
|
if [ -n "$max_resolution" ] ; then
|
|
ytdlformats+="[height<=?$max_resolution]"
|
|
fi
|
|
if [ -n "$max_fps" ] ; then
|
|
ytdlformats+="[fps<=?$max_fps]"
|
|
fi
|
|
if [ -n "$ignore_codec" ] ; then
|
|
ytdlformats+="[vcodec!=$ignore_codec]"
|
|
fi
|
|
ytdlformats+="+bestaudio/best"
|
|
|
|
# Subscription list
|
|
mkdir -p "${HOME:-}/.config/yt"
|
|
sublistpath="${HOME:-}/.config/yt/sublist"
|
|
sublist=""
|
|
[ -f "$sublistpath" ] && sublist=$(cat "$sublistpath")
|
|
|
|
# If not using defaults, search for flags
|
|
if [[ $useDefaults = "f" ]]; then
|
|
while getopts ${optstring} arg; do
|
|
case "${arg}" in
|
|
s)
|
|
# Search in YouTube for a query
|
|
action="s"
|
|
query="${OPTARG}" ;;
|
|
c)
|
|
# Search in subscriptions for a specific channel
|
|
action="c"
|
|
query="${OPTARG}" ;;
|
|
g|r)
|
|
# Set gui mode to true and change the prompt to gui prompt
|
|
isGui="t"
|
|
promptcmd="$guicmd" ;;
|
|
m)
|
|
# Make the mpv headless
|
|
mpv_options+="--no-video" ;;
|
|
h)
|
|
# Display help / usage
|
|
usage ;;
|
|
\?|:)
|
|
# Wrong args -> exit with explanation of usage
|
|
echo "invalid option: -${OPTARG}"
|
|
echo
|
|
usage
|
|
exit 1 ;;
|
|
esac
|
|
done
|
|
fi
|
|
|
|
# If no query is set with flags, then ask for one
|
|
if [ -z "$query" ]; then
|
|
# Ask for a channel
|
|
if [[ $action = "c" ]]; then
|
|
# If in gui mode, use gui prompt
|
|
if [[ $isGui = "t" ]]; then
|
|
query=$($promptcmd -p "Channel: " <<< "$sublist")
|
|
promptcmd="$promptcmd -p Video:"
|
|
else
|
|
query=$($promptcmd --print-query <<< "$sublist" | tail -n1)
|
|
fi
|
|
query=$(echo "$query" | awk '{print $1}')
|
|
else
|
|
# Ask for a query
|
|
# If in gui mode, use gui prompt
|
|
if [[ $isGui = "t" ]]; then
|
|
query=$(echo | $promptcmd -p "Search: ")
|
|
promptcmd="$promptcmd -p Video:"
|
|
else
|
|
echo -n "Search: "
|
|
read -r query
|
|
fi
|
|
fi
|
|
fi
|
|
|
|
# Program cancelled -> exit
|
|
if [ -z "$query" ]; then exit; fi
|
|
|
|
# Clean query / channel
|
|
query=$(sed \
|
|
-e 's|+|%2B|g'\
|
|
-e 's|#|%23|g'\
|
|
-e 's|&|%26|g'\
|
|
-e 's| |+|g' <<< "$query")
|
|
|
|
# If channel, look for channel vids
|
|
if [[ $action = "c" ]]; then
|
|
response=$(curl -s "https://www.youtube.com/c/$query/videos" |\
|
|
sed "s/{\"gridVideoRenderer/\n\n&/g" |\
|
|
sed "s/}]}}}]}}/&\n\n/g" |\
|
|
awk -v ORS="\n\n" '/gridVideoRenderer/')
|
|
|
|
# If unable to fetch the YouTube results page, inform and exit
|
|
if ! grep -q "gridVideoRenderer" <<< "$response"; then echo "unable to fetch yt"; exit 1; fi
|
|
|
|
# Regex expression to match video entries from YouTube channel page
|
|
# Get the list of videos and their ids to ids
|
|
ids=$(awk -F '[""]' '{print $6 "\t" $50;}' <<< "$response" | grep "^\S")
|
|
|
|
# URL prefix for videos
|
|
videolink="https://youtu.be/"
|
|
|
|
# Prompt the results to user infinitely until they exit (escape)
|
|
while true; do
|
|
choice=$(echo -e "$ids" | cut -d' ' -f2 | $promptcmd) # Don't show id
|
|
if [ -z "$choice" ]; then exit; fi # If esc-ed then exit
|
|
id=$(echo -e "$ids" | grep -Fwm1 "$choice" | cut -d' ' -f1) # Get id of choice
|
|
echo -e "$choice\t($id)"
|
|
case $id in
|
|
???????????) mpv "$videolink$id" "$mpv_options" --ytdl-format="$ytdlformats";;
|
|
*) exit ;;
|
|
esac
|
|
done
|
|
else
|
|
# If in search, show query result vids
|
|
response="$(curl -s "https://www.youtube.com/results?search_query=$query" |\
|
|
sed 's|\\.||g')"
|
|
# If unable to fetch the YouTube results page, inform and exit
|
|
if ! grep -q "script" <<< "$response"; then echo "unable to fetch yt"; exit 1; fi
|
|
# Regex expression to match video and playlist entries from YouTube result page
|
|
vgrep='"videoRenderer":{"videoId":"\K.{11}".+?"text":".+?[^\\](?=")'
|
|
pgrep='"playlistRenderer":{"playlistId":"\K.{34}?","title":{"simpleText":".+?[^\"](?=")'
|
|
# Grep the id and title
|
|
# Return them in format id (type) title
|
|
getresults() {
|
|
grep -oP "$1" <<< "$response" |\
|
|
awk -F\" -v p="$2" '{ print $1 "\t" p " " $NF}'
|
|
}
|
|
# Get the list of videos/playlists and their ids in videoids and playlistids
|
|
videoids=$(getresults "$vgrep")
|
|
playlistids=$(getresults "$pgrep" "(playlist)")
|
|
# If there are playlists or videos, append them to list
|
|
[ -n "$playlistids" ] && ids="$playlistids\n"
|
|
[ -n "$videoids" ] && ids="$ids$videoids"
|
|
# URL prefix for videos and playlists
|
|
videolink="https://youtu.be/"
|
|
playlink="https://youtube.com/playlist?list="
|
|
# Prompt the results to user infinitely until they exit (escape)
|
|
while true; do
|
|
choice=$(echo -e "$ids" | cut -d' ' -f2 | $promptcmd) # Don't show id
|
|
if [ -z "$choice" ]; then exit; fi # If esc-ed then exit
|
|
id=$(echo -e "$ids" | grep -Fwm1 "$choice" | cut -d' ' -f1) # Get id of choice
|
|
echo -e "$choice\t($id)"
|
|
case $id in
|
|
# 11 digit id = video
|
|
???????????) mpv "$videolink$id" $mpv_options --ytdl-format="$ytdlformats";;
|
|
# 34 digit id = playlist
|
|
??????????????????????????????????) mpv "$playlink$id" $mpv_options --ytdl-format="$ytdlformats";;
|
|
*) exit ;;
|
|
esac
|
|
done
|
|
fi
|