Files
hyprland/misc/bin/yt
T
sankalp 887d33ff0d feat(misc/bin): add autoplay mode and refactor GUI handling
- New Features
  - Introduce `-a` flag for autoplay mode that automatically plays the next video.
  - Remove unused GUI handling (`-g`/`-r`) and update dependency comment.
- Enhancements
  - Simplify flag parsing by adding `a` to `optstring` and consolidating logic.
  - Replace `isGui` toggle with `autoplay` state management.
- Bug Fixes
  - Fix index tracking in autoplay to correctly continue after manual selection.
  - Ensure proper termination of playlists when reaching the end.
2026-03-06 21:58:12 +05:45

271 lines
8.8 KiB
Plaintext
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 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 " -m music mode (audio only) [dont use with -r]\n"
printf " -a autoplay mode (play next video automatically)\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:cgrhma"
defcmd="fzf"
defaction="s"
# Defaults
promptcmd="$defcmd"
action="$defaction"
autoplay="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}" ;;
m)
# Make the mpv headless
mpv_options+="--no-video" ;;
a)
# Enable autoplay mode
autoplay="t" ;;
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
query=$($promptcmd --print-query <<< "$sublist" | tail -n1)
query=$(echo "$query" | awk '{print $1}')
else
# Ask for a query
echo -n "Search: "
read -r query
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/"
# Convert ids to array for autoplay
readarray -t id_array <<< "$ids"
current_index=0
# Prompt the results to user infinitely until they exit (escape)
while true; do
if [[ $autoplay = "t" ]] && [[ $current_index -gt 0 ]]; then
# In autoplay mode, automatically play the next video
if [[ $current_index -lt ${#id_array[@]} ]]; then
choice=$(echo "${id_array[$current_index]}" | cut -d' ' -f2)
id=$(echo "${id_array[$current_index]}" | cut -d' ' -f1)
echo -e "Autoplaying: $choice\t($id)"
else
echo "End of playlist reached"
exit
fi
else
# Manual selection mode
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)"
# Find the index of selected video for autoplay continuation
for i in "${!id_array[@]}"; do
if [[ "${id_array[$i]}" == "$id"* ]]; then
current_index=$i
break
fi
done
fi
case $id in
???????????)
mpv "$videolink$id" $mpv_options --ytdl-format="$ytdlformats"
current_index=$((current_index + 1))
;;
*) exit ;;
esac
# If not in autoplay mode, continue prompting
if [[ $autoplay = "f" ]]; then
continue
fi
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="
# Convert ids to array for autoplay
readarray -t id_array <<< "$(echo -e "$ids")"
current_index=0
# Prompt the results to user infinitely until they exit (escape)
while true; do
if [[ $autoplay = "t" ]] && [[ $current_index -gt 0 ]]; then
# In autoplay mode, automatically play the next video
if [[ $current_index -lt ${#id_array[@]} ]]; then
choice=$(echo "${id_array[$current_index]}" | cut -d' ' -f2)
id=$(echo "${id_array[$current_index]}" | cut -d' ' -f1)
echo -e "Autoplaying: $choice\t($id)"
else
echo "End of playlist reached"
exit
fi
else
# Manual selection mode
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)"
# Find the index of selected video for autoplay continuation
for i in "${!id_array[@]}"; do
if [[ "${id_array[$i]}" == "$id"* ]]; then
current_index=$i
break
fi
done
fi
case $id in
# 11 digit id = video
???????????)
mpv "$videolink$id" $mpv_options --ytdl-format="$ytdlformats"
current_index=$((current_index + 1))
;;
# 34 digit id = playlist
??????????????????????????????????)
mpv "$playlink$id" $mpv_options --ytdl-format="$ytdlformats"
current_index=$((current_index + 1))
;;
*) exit ;;
esac
# If not in autoplay mode, continue prompting
if [[ $autoplay = "f" ]]; then
continue
fi
done
fi