ytsearch (20135B)
1 #!/bin/bash 2 # A messy bash TUI client for YT/Invidious. 3 # DEPENDS: youtube-dl/yt-dlp, mpv, ffmpeg, xclip, coreutils 4 # 5 # Copyright (C) <2020> <nixx@firemail.cc> 6 # 7 # This program is free software: you can redistribute it and/or modify 8 # it under the terms of the GNU General Public License as published by 9 # the Free Software Foundation, either version 3 of the License, or 10 # (at your option) any later version. 11 # 12 # This program is distributed in the hope that it will be useful, 13 # but WITHOUT ANY WARRANTY; without even the implied warranty of 14 # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 15 # GNU General Public License for more details. 16 # 17 # You should have received a copy of the GNU General Public License 18 # along with this program. If not, see <http://www.gnu.org/licenses/>. 19 20 message () { 21 cat << EOF 22 ytsearch 23 ~~~~~~~~ 24 25 TUI client for querying YouTube content. 26 27 Using Invidious to fetch results is faster, and 'friendlier' about 28 number of server requests. When a result is chosen, it is downloaded/ 29 streamed directly from YouTube. 30 31 Some code pertaining to fetching results directly from YouTube 32 remains, but this is slow, and tends to get you banned - I would not 33 recommend. 34 35 Usage: 36 37 All parameters are optional to start the client. 38 39 search - Initial search term. 40 results - Number of results to return - defaults to 15. 41 invid - Alternate Invidious mirror to use - 42 invidious.snopyta.org works best at time of writing 43 this, it is the default. 44 45 'ytsearch "<search>" <results> <invid> 46 47 An example: 48 'ytsearch "linus torvalds" 5 https://yt.iswleuven.be/' 49 50 51 Config File: 52 53 Located at either \$HOME/.config/ytsearch or at \$HOME/.ytsearch. 54 55 Number of results, alternate mirror, preferred download format 56 (default 'best'), and search timeout (secs per loaded page - 57 default 20) can be set via config file. An example: 58 59 's_results = 5' 60 's_website = https://yt.iswleuven.be/' 61 's_format = 18' 62 's_timeout = 10' 63 64 MORE DETAILS: 65 66 s_results: 67 ---------- 68 This is the number of individual results returned. Equivalent to 69 second parameter the in command line. 70 71 s_website: 72 ---------- 73 This is the alternative Invidious mirror to use. Some will work 74 more reliably than others. Equivalent to the third parameter in 75 the command line. 76 77 s_format: 78 --------- 79 Can only be set in config file. Determines video/audio quality: 80 see 'FORMAT SELECTION' on youtube-dl's/yt-dlp's man page for more 81 information on options. Defaults to 'best' - combination of best 82 audio and video quality, youtube-dl's/yt-dlp's default. 83 Note #1: when you select 'audio' it will download bestaudio and no 84 video, no matter the value of s_format. 85 Note #2: I generally recommend you put a '/best' on the end of the 86 quality option, so that if all else fails, it chooses the best 87 default. 88 89 s_timeout: 90 ---------- 91 Time taken to load a page of results, before giving up. Note that 92 timeout applies per page of results (20 results). 10 pages 93 (200 results) with a timeout of 10 seconds, could take up to 100 94 seconds (assuming they all take the maximum time of 10 seconds). 95 96 Issues: 97 98 Invidious instances can be highly unreliable. That's why 99 switching instance via config file exists, often one mirror will 100 be having issues and another will be fine. Increasing your search 101 timeout beyond the default may also help, if queries tend to 102 timeout. 103 104 Managing YouTube subscriptons: 105 106 See the companion program 'ytchannel'. Most of the requirements of 107 subscriptions are already met by an RSS feed reader, so ytchannel 108 fetches and formats channel IDs for such a purpose. 109 EOF 110 } 111 112 copy () { 113 if xset -q >/dev/null 2>&1; then 114 printf "${1}" | xclip -in -selection clipboard 115 printf "\e[0;94m# Copied URL to clipboard.\e[0m\n" 116 fi 117 echo -e "\e[0;94m# URL: ${1}\e[0m" 118 } 119 120 hexformat () { 121 echo "${1}" | sed -e "s/%/%25/g" -e "s/!/%21/g" -e "s/\"/%22/g" -e "s/#/%23/g" -e 's/\$/%24/g' -e "s/&/%26/g" -e "s/'/%27/g" -e "s/(/%28/g" -e "s/)/%29/g" -e "s/=/%3D/g" -e "s/\^/%5E/g" -e "s/|/%7C/g" -e "s/?/%3F/g" -e "s|/|%2F|g" -e "s/,/%2C/g" -e "s/</%3C/g" -e "s/>/%3E/g" -e "s/+/%2B/g" -e "s/;/%3B/g" -e "s/:/%3A/g" -e "s/]/%5D/g" -e "s/\[/%5B/g" -e "s/}/%7D/g" -e "s/{/%7B/g" -e "s/\`/%60/g" -e "s/\"/%22/g" -e "s/ /+/g" 122 } 123 124 line () { 125 printf "\e[1;34m=============================================================================\e[0m\n" 126 } 127 128 title () { 129 printf "\e[1;97m#\tDURAT\t\tTITLE\e[0m\n" 130 line 131 } 132 133 process () { 134 countto=$3 135 [[ -z $countto ]] && countto=9999 136 links=$(cat "${1}" | grep -n '<a style="width:100%" href="/watch?v=\|<a style="width:100%" href="/playlist?list=') 137 lengths=$(cat "${1}" | grep '<p class="length"') 138 rescount=0 139 reslinkscount=$(echo "${links}" | wc -l) 140 reslenscount=$(echo "${lengths}" | wc -l) 141 pageslen=$(($pagecount*20)) 142 while [[ $rescount -le $(($reslinkscount-1)) && $rescount -lt $countto ]]; do ((rescount++)) 143 time=$(echo "${lengths}" | head -n $rescount | tail -n 1) 144 [[ $time == *"LIVE"* ]] && time="LIVE" || time=$(echo $time | cut -d '>' -f 2 | cut -d '<' -f 1) 145 title=$(echo "${links}" | head -n $rescount | tail -n 1) 146 ln=$(echo $title | cut -d : -f 1) 147 if [[ $title == *"/playlist?list="* ]]; then 148 title=$(sed "$((ln+=7))q;d" "${1}" | cut -d '>' -f 2 | cut -d '<' -f 1) 149 else 150 title=$(sed "$((ln+=11))q;d" "${1}" | cut -d '>' -f 2 | cut -d '<' -f 1) 151 fi 152 link=$(echo "${links}" | head -n $rescount | tail -n 1 | cut -d '/' -f 2 | cut -d \" -f 1) 153 [[ -n $title && -n $link && -n $time ]] && echo "${title}" >> $2 && echo "${link}" >> $2 && echo "${time}" >> $2 154 done 155 } 156 157 playlistpages () { 158 playstop=$(($playcount+75)) 159 while [[ ${playcount} -le ${lenplay} && ${playcount} -lt ${playstop} ]]; do 160 ((halfcount++)) 161 echo -en "\e[0;96m$halfcount\t" 162 timeline=$(sed "$(( $playcount + 2))q;d" $playtmpout) 163 echo -en "\e[0;92m${timeline}" 164 [[ $(echo $timeline | wc -L) -gt 7 ]] && printf '\t' || printf '\t\t' 165 titleline="$(sed "${playcount}q;d" $playtmpout)" 166 printf "\e[0;97m" 167 [[ $(echo ${titleline} | wc -L) -gt 50 ]] && printf "$(echo -n "${titleline}" | cut -c 1-50)" && echo -n ... || echo -n "${titleline}" 168 printf '\n' 169 ((playcount+=3)) 170 done 171 } 172 173 playlist () { 174 read -p "(e)xit | (d)escend into playlist $2, or (u)se whole playlist?: " descend 175 [[ $descend == 'e' || $descend == 'E' || $descend == 'exit' || $descend == 'Exit' || $descend == 'q' || $descend == 'Q' ]] && rm $tmp && exit 0 176 if [[ $descend == 'd' || $descend == 'D' || $descend == 'descend' || $descend == 'Descend' ]]; then 177 playtmp=$(mktemp) 178 playtmpout=$(mktemp) 179 curlpage=1 180 curlcheck=$(curl --http2-prior-knowledge -m ${timeout} -s "${1}") 181 echo "${curlcheck}" >> $playtmp 182 while [[ -n $(echo "${curlcheck}" | grep "playlist?list=.*page=$((curlpage+1))") ]]; do ((curlpage++)) 183 curlcheck=$(curl --http2-prior-knowledge -m ${timeout} -s "${1}&page=${curlpage}") 184 echo "${curlcheck}" >> $playtmp 185 done 186 [[ $? == 92 ]] && printf "\e[1;91m# ERROR: HTTP/2 stream 0 was not closed cleanly. This is a server problem, consider switching instance.\e[0m\n" && rm $tmp $playtmp $playtmpout && exit 1 187 process $playtmp $playtmpout 188 [[ $(wc -l $playtmpout | awk '{print $1}') == 0 && -n $(grep "Could not extract playlist info. Instance is likely blocked." $playtmp) ]] && printf "\e[1;91m# ERROR: Could not extract playlist info. Instance is likely blocked - Consider switching instance.\e[0m\n" rm $playtmp $playtmpout $tmp && exit 1 189 [[ $(wc -l $playtmpout | awk '{print $1}') == 0 && -n $(grep "Read timed out" $playtmp) ]] && printf "\e[1;91m# ERROR: Read timed out - Consider switching instance.\e[0m\n" && rm $playtmp $playtmpout $tmp && exit 1 190 [[ $(wc -l $playtmpout | awk '{print $1}') == 0 ]] && printf "\e[1;91m# ERROR: Could not fetch playlist. Consider increasing timeout in the config file, or switching Invidious instance.\e[0m\n" && rm $playtmp $playtmpout $tmp && exit 1 191 rm $playtmp 192 193 lenplay=$(cat $playtmpout | wc -l) 194 playcount=1 195 halfcount=0 196 playnum='' 197 while [[ -z $playnum || $playnum == *[a-z]* || $playnum == *[A-Z]* ]]; do 198 printf '\n' 199 title 200 playlistpages 201 line 202 printf '\n' 203 204 if [[ $lenplay -gt 76 ]]; then 205 if [[ $halfcount -lt 26 ]]; then 206 echo "(n)ext page." 207 elif [[ $halfcount -ge 26 && $halfcount -lt $(($lenplay/3-25)) ]]; then 208 echo "(n)ext/(p)revious page." 209 else 210 echo "(p)revious page." 211 fi 212 fi 213 read -p '(e)xit | Sel. vid. (format: 1,2,3), or all (.): ' playnum 214 [[ $playnum == '.' || $playnum == 'all' || $playnum == 'All' ]] && return 2 215 if [[ $playnum == 'p' || $playnum == 'P' || $playnum == 'prev'* || $playnum == 'Prev'* ]]; then 216 if [[ $halfcount -gt 49 && $playcount -gt 151 ]]; then 217 halfcount=$(($halfcount-50)) && playcount=$(($playcount-150)) 218 else 219 halfcount=0 && playcount=1 220 fi 221 elif [[ $playnum == 'e' || $playnum == 'E' || $playnum == 'exit' || $playnum == 'Exit' || $playnum == 'q' || $playnum == 'Q' ]]; then 222 rm $tmp $playtmpout && exit 0 223 fi 224 done 225 pn=$(echo -n $playnum | tr -d "[:blank:]") 226 IFS="," read -a playarray <<< $pn 227 for no in "${playarray[@]}"; do 228 [[ $no == *[a-z]* || $no == *[A-Z]* || $no -gt $halfcount || $no -lt 1 ]] && printf "\e[1;91mERROR: Invalid number.\e[0m\n" && rm $tmp && exit 1 229 ((loc=no*3-1)) 230 playnewurl=$(sed "${loc}q;d" $playtmpout) 231 playurl[$playurlcount]=$playnewurl 232 ((playurlcount++)) 233 done 234 rm $playtmpout 235 elif [[ $descend == 'u' || $descend == 'U' || $descend == 'use' || $descend == 'Use' ]]; then 236 printf "\e[0;94m# Using whole playlist as input.\e[0m\n" 237 return 2 238 else 239 printf "\e[1;91mERROR: Invalid option.\n" && exit 0 240 fi 241 } 242 243 main () { 244 tmp=$(mktemp) 245 246 if [[ $website == "https://www.youtube.com/" ]]; then 247 ${downloader} --get-id --get-duration -e ytsearch${num}:"${1}" 1> $tmp 2>/dev/null 248 else 249 searchhex=$(hexformat "${1}") 250 resulttmp=$(mktemp) 251 pagecount=0 252 while [ $pagecount -lt $(($num/20+1)) ]; do ((pagecount++)) 253 curl --http2-prior-knowledge -m ${timeout} -s "${website}search?q=${searchhex}&page=${pagecount}" >> $resulttmp 254 done 255 [[ $? == 92 ]] && printf "\e[1;91m# ERROR: HTTP/2 stream 0 was not closed cleanly. This is a server problem, consider switching instance.\e[0m\n" && rm $tmp $resulttmp && exit 1 256 [[ -n $(grep "<title>502 Bad Gateway</title>" $resulttmp) ]] && printf "\e[1;91m# ERROR: 502 Bad Gateway - Consider switching instance.\e[0m\n" && rm $tmp $resulttmp && exit 1 257 process $resulttmp $tmp $num 258 [[ -n $(grep "Read timed out" $resulttmp) && $(wc -l $tmp | awk '{print $1}') == 0 ]] && printf "\e[1;91m# ERROR: Read timed out - Consider switching instance.\e[0m\n" && rm $tmp $resulttmp && exit 1 259 rm $resulttmp 260 fi 261 262 len=$(wc -l $tmp | awk '{print $1}') 263 [[ $len -eq 0 ]] && echo -e "\e[1;91m# ERROR: Could not fetch videos.\n1. Check the spelling of search instance ${website}.\n2. Increase search timeout - currently ${timeout} secs.\n3. Check: ${website}search?q=${searchhex}&page=${pagecount} - instance may be down.\n4. You may also be HTTP Error 429 blocked - have you been making a lot of requests?.\n5. Your search may just be too obscure.\e[0m" && rm $tmp && exit 1 264 printf "\e[0;94m# Searched for results 1 to ${num}.\n\n" 265 title 266 267 count=1 268 halfcount=0 269 while [ ${count} -le ${len} ]; do 270 ((halfcount++)) 271 echo -en "\e[0;96m$halfcount\t" 272 timeline=$(sed "$(( $count + 2))q;d" $tmp) 273 echo -en "\e[0;92m${timeline}" 274 [[ $(echo $timeline | wc -L) -gt 7 ]] && printf '\t' || printf '\t\t' 275 titleline="$(sed "${count}q;d" $tmp)" 276 printf "\e[0;97m" 277 [[ $(echo "${titleline}" | wc -L) -gt 50 ]] && echo -n "$(echo -n "${titleline}" | cut -c 1-50)" && echo -n ... || echo -n "${titleline}" 278 printf '\n' 279 ((count+=3)) 280 done 281 line 282 printf '\n' 283 284 read -p 'Sel. vid. (format:1,2,3), (s)earch again, or (e)xit: ' vidnum 285 [[ $vidnum == 'e' || $vidnum == 'E' || $vidnum == 'q' || $vidnum == 'Q' || $vidnum == 'exit' || $vidnum == 'Exit' ]] && rm $tmp && exit 0 286 [[ $vidnum == 's' || $vidnum == 'S' || $vidnum == 'search' || $vidnum == 'Search' ]] && rm $tmp && again=1 && return 0 287 count=0 288 if [[ $vidnum == *","* ]]; then 289 nums=$(echo -n $vidnum | tr -d "[:blank:]") 290 declare -A url 291 IFS="," read -a array <<< $nums 292 for vnum in "${array[@]}"; do 293 [[ $vnum == *[a-z]* || $vnum == *[A-Z]* || $vnum -gt $halfcount || $vnum -lt 1 ]] && printf "\e[1;91mERROR: Invalid number.\e[0m\n" && rm $tmp && exit 1 294 ((loc=vnum*3-1)) 295 newurl=$(sed "${loc}q;d" $tmp) 296 if [[ $newurl == *"playlist?list="* ]]; then 297 playlist "${website}${newurl}" $vnum 298 fi 299 if [[ $? == 2 && $newurl == *"playlist?list="* || $newurl != *"playlist?list="* ]]; then 300 url[$count]=$newurl 301 ((count++)) 302 fi 303 done 304 rm $tmp 305 else 306 [[ $vidnum == *[a-z]* || $vidnum == *[A-Z]* || $vidnum -gt $halfcount || $vidnum -lt 1 ]] && printf "\e[1;91mERROR: Invalid number.\e[0m\n" && rm $tmp && exit 1 307 ((loc=vidnum*3-1)) 308 url=$(sed "${loc}q;d" $tmp) 309 [[ $url == *"playlist?list="* ]] && playlist "${website}${url}" $vidnum 310 [[ $? != 2 && $url == *"playlist?list="* ]] && url="" 311 rm $tmp 312 fi 313 314 matchcount=0 315 playmatchcount=0 316 read -p 'Action? [(d)ownload/(s)tream/get(u)rl/(e)xit]: ' confirm 317 [[ $confirm == 'E' || $confirm == 'e' || $confirm == 'q' || $confirm == 'Q' || $confirm == 'exit' || $confirm == 'Exit' ]] && exit 0 318 if [[ $confirm == 'D' || $confirm == 'd' || $confirm == 'download' || $confirm == 'Download' ]]; then 319 read -p '(e)xit | (v)ideo or (a)udio only?: ' vid 320 [[ $vid == 'e' || $vid == 'E' || $vid == 'exit' || $vid == 'Exit' || $vid == 'q' || $vid == 'Q' ]] && exit 0 321 if [[ $vid == 'v' || $vid == 'V' || $vid == 'video' || $vid == 'Video' ]]; then 322 if [[ $count == 0 && -n $url ]]; then 323 printf '\n' 324 copy "${website}${url}" 325 [ $vformat ] && ${downloader} -i -f "${vformat}" "${streambase}${url}" || ${downloader} -i "${streambase}${url}" 326 else 327 printf '\n' 328 while [ $(( $matchcount + 1 )) -le $count ]; do 329 copy "${website}${url[$matchcount]}" 330 [ $vformat ] && ${downloader} -i -f "${vformat}" "${streambase}${url[$matchcount]}" || ${downloader} -i "${streambase}${url[$matchcount]}" 331 ((matchcount++)) 332 done 333 fi 334 while [[ $playmatchcount -lt ${#playurl[@]} ]]; do 335 fullurl="${playurl[$playmatchcount]}" 336 copy "${website}${fullurl}" 337 [ $vformat ] && ${downloader} -i -f "${vformat}" --no-playlist "${streambase}${fullurl}" || ${downloader} -i --no-playlist "${streambase}${fullurl}" 338 ((playmatchcount++)) 339 done 340 elif [[ $vid == 'a' || $vid == 'A' || $vid == 'audio' || $vid == 'Audio' ]]; then 341 if [[ $count == 0 && -n $url ]]; then 342 printf '\n' 343 copy "${website}${url}" 344 ${downloader} -ix --audio-format "mp3" "${streambase}${url}" 345 else 346 printf '\n' 347 while [ $(( $matchcount + 1 )) -le $count ]; do 348 copy "${website}${url[$matchcount]}" 349 ${downloader} -ix --audio-format "mp3" "${streambase}${url[$matchcount]}" 350 ((matchcount++)) 351 done 352 fi 353 while [[ $playmatchcount -lt ${#playurl[@]} ]]; do 354 fullurl="${playurl[$playmatchcount]}" 355 copy "${website}${fullurl}" 356 ${downloader} -ix --audio-format "mp3" --no-playlist "${streambase}${fullurl}" 357 ((playmatchcount++)) 358 done 359 else 360 printf "\e[1;91mERROR: Invalid action.\e[0m\n" && exit 1 361 fi 362 elif [[ $confirm == 'S' || $confirm == 's' || $confirm == 'stream' || $confirm == 'Stream' ]]; then 363 read -p '(e)xit | (v)ideo or (a)udio only?: ' vid 364 [[ $vid == 'e' || $vid == 'E' || $vid == 'exit' || $vid == 'Exit' || $vid == 'q' || $vid == 'Q' ]] && exit 0 365 if [[ $vid == 'v' || $vid == 'V' || $vid == 'video' || $vid == 'Video' ]]; then 366 if [[ $count == 0 && -n $url ]]; then 367 printf '\n' 368 copy "${website}${url}" 369 [ $vformat ] && ${player} --ytdl-format="${vformat}" --ytdl "${streambase}${url}" || ${player} --ytdl "${streambase}${url}" 370 else 371 printf '\n' 372 while [ $(( $matchcount + 1 )) -le $count ]; do 373 copy "${website}${url[$matchcount]}" 374 [ $vformat ] && ${player} --ytdl-format="${vformat}" --ytdl "${streambase}${url[$matchcount]}" || ${player} --ytdl "${streambase}${url[$matchcount]}" 375 ((matchcount++)) 376 done 377 fi 378 while [[ $playmatchcount -lt ${#playurl[@]} ]]; do 379 fullurl="${playurl[$playmatchcount]}" 380 copy "${website}${fullurl}" 381 [ $vformat ] && ${player} --ytdl-format="${vformat}" --ytdl "${streambase}${fullurl}" || ${player} --ytdl "${streambase}${fullurl}" 382 ((playmatchcount++)) 383 done 384 elif [[ $vid == 'a' || $vid == 'A' || $vid == 'audio' || $vid == 'Audio' ]]; then 385 if [[ $count == 0 && -n $url ]]; then 386 printf '\n' 387 copy "${website}${url}" 388 ${player} --ytdl-format=bestaudio --no-video --ytdl "${streambase}${url}" 389 else 390 printf '\n' 391 while [ $(( $matchcount + 1 )) -le $count ]; do 392 copy "${website}${url[$matchcount]}" 393 ${player} --ytdl-format=bestaudio --no-video --ytdl "${streambase}${url[$matchcount]}" 394 ((matchcount++)) 395 done 396 fi 397 while [[ $playmatchcount -lt ${#playurl[@]} ]]; do 398 fullurl="${playurl[$playmatchcount]}" 399 copy "${website}${fullurl}" 400 ${player} --ytdl-format=bestaudio --no-video --ytdl "${streambase}${fullurl}" 401 ((playmatchcount++)) 402 done 403 else 404 printf "\e[1;91mERROR: Invalid action.\e[0m\n" && exit 1 405 fi 406 elif [[ $confirm == 'u' || $confirm == 'U' ]]; then 407 read -p '(e)xit | Print to std(o)ut, or to (f)ile?: ' stdf 408 [[ $stdf == 'e' || $stdf == 'E' || $stdf == 'exit' || $stdf == 'Exit' || $stdf == 'q' || $stdf == 'Q' ]] && exit 0 409 [[ $stdf == 'f' || $std == 'F' ]] && read -p 'Append to file: ' fileloc 410 411 if [[ $stdf == 'o' || $stdf == 'O' ]]; then 412 if [[ $count == 0 && -n $url ]]; then 413 printf '\n' 414 copy "${website}${url}" 415 echo "${website}${url}" 416 else 417 printf '\n' 418 while [[ $(( $matchcount + 1 )) -le $count ]]; do 419 echo "${website}${url[$matchcount]}" 420 ((matchcount++)) 421 done 422 fi 423 while [[ $playmatchcount -lt ${#playurl[@]} ]]; do 424 fullurl="${playurl[$playmatchcount]}" 425 echo "${website}${fullurl}" 426 ((playmatchcount++)) 427 done 428 elif [[ -n $fileloc ]]; then 429 if [[ $count == 0 && -n $url ]]; then 430 touch "${fileloc}" 431 copy "${website}${url}" 432 echo "${website}${url}" >> "${fileloc}" 433 else 434 while [[ $(( $matchcount + 1 )) -le $count ]]; do 435 touch "${fileloc}" 436 echo "${website}${url[$matchcount]}" >> "${fileloc}" 437 ((matchcount++)) 438 done 439 fi 440 while [[ $playmatchcount -lt ${#playurl[@]} ]]; do 441 fullurl="${playurl[$playmatchcount]}" 442 echo "${website}${fullurl}" >> "${fileloc}" 443 ((playmatchcount++)) 444 done 445 else 446 printf "\e[1;91mERROR: Invalid action.\e[0m\n" && exit 1 447 fi 448 else 449 printf "\e[1;91mERROR: Invalid action.\e[0m\n" && exit 1 450 fi 451 } 452 453 [[ $1 == '-h' || $1 == *'-help'* || $# -gt 3 ]] && message && exit 0 454 website="${3}" 455 streambase="https://www.youtube.com/" 456 if [[ -z $website ]]; then 457 find ~/.config/ytsearch >/dev/null 2>&1 458 [[ $? == 0 ]] && configf=~/.config/ytsearch 459 [[ -z $configf ]] && find ~/.ytsearch >/dev/null 2>&1 460 [[ $? == 0 ]] && configf=~/.ytsearch 461 [[ -n $configf ]] && website=$(grep "s_website" ${configf} | awk '{print $3}') 462 [[ -z $website ]] && website="https://invidious.snopyta.org/" 463 fi 464 [[ $website != "https://"* ]] && website="https://${website}" 465 [[ $(echo $website | tail -c 2 | head -c 1) != '/' ]] && website="${website}/" 466 [[ $2 == *[a-z]* || $2 == *[A-Z]* ]] && printf "\e[1;91mERROR: Invalid search time parameter.\n\e[0m" && exit 1 467 if [[ -z $2 ]]; then 468 [[ -n $configf ]] && num=$(grep "s_results" "${configf}" | awk '{print $3}') 469 [[ -z $num ]] && num=15 470 else 471 num=$2 472 fi 473 [[ -n $configf && -n $(grep "s_timeout" "${configf}") ]] && timeout=$(grep "s_timeout" "${configf}" | awk '{print $3}') || timeout=20 474 [[ -n $configf && -n $(grep "s_format" "${configf}") ]] && vformat=$(grep "s_format" "${configf}" | awk '{print $3}') 475 476 player="mpv" 477 if [[ $(which yt-dlp > /dev/null 2>&1) ]]; then 478 downloader="youtube-dl" 479 else 480 downloader="yt-dlp" 481 fi 482 483 search="${1}" 484 again=0 485 clear 486 [[ -z $search ]] && read -p 'Search: ' search || echo "Search: ${search}" 487 printf '\n' 488 while ( true ); do 489 playurlcount=0 490 declare -A playurl 491 clearcount=0 492 for u in "${url[@]}"; do 493 url[$clearcount]='' 494 ((clearcount++)) 495 done 496 clearcount=0 497 for p in "${playurl[@]}"; do 498 playurl[$clearcount]='' 499 ((clearcount++)) 500 done 501 main "${search}" "${num}" "${website}" 502 quit='n' 503 [[ $again == 0 ]] && read -p 'Quit? [Y/n]: ' quit 504 again=0 505 [[ $quit != 'n' && $quit != 'N' ]] && exit 0 506 clear 507 read -p 'Search: ' search 508 printf '\n' 509 done