youtube-search 4.6 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165
  1. #!/bin/bash
  2. usage() {
  3. echo "
  4. Search Youtube.
  5. Usage: youtube-search [OPTIONS] [\"SEARCH STRING\"]
  6. Requires jshon and youtube-dl to be in PATH (or a youtube-dl compatible
  7. executable, see -e option). Requires perl and HTML::Entities.
  8. You can provide a search string in double quotes on the command line,
  9. or enter it interactively.
  10. It helps if xclip and/or tput are available, but the script works without those.
  11. OPTIONS
  12. -l List more detail for each result (slower, larger download).
  13. -f Full width - don't cut long strings to terminal width.
  14. -m int Maximum number of results shown Default: $max_results.
  15. We suspect that only the values 3 or 10 should be used.
  16. -t int Timeout for URL retrieval. Default: $timeout.
  17. -e str Use this executable instead of youtbe-dl.
  18. -M str Use this application to open the selected Youtube URL.
  19. Tested with youtube-dl and also mpv.
  20. -D Debug: dump complete json result and more.
  21. -h This help.
  22. "
  23. exit 1
  24. }
  25. base_url='https://m.youtube.com'
  26. minlen=3 # minimum length for search term
  27. # character for separator line
  28. sepchar="-"
  29. # Colors
  30. RED='\033[31m'
  31. BLUE='\033[34m'
  32. CYAN='\033[36m'
  33. GREEN='\033[32m'
  34. YELLOW='\033[33m'
  35. END='\033[0;0m'
  36. BOLD='\033[1m'
  37. #Set number of video results here.
  38. max_results=3
  39. timeout=10
  40. fullwidth=False
  41. debug=0
  42. uts=''
  43. mpv=()
  44. YTDL="${YTDL:-youtube-dl}"
  45. ytdlopts=( --flat-playlist --sub-lang en )
  46. options=( title description duration view_count id )
  47. # Parsing the command line
  48. while getopts "lfm:t:e:M:Dh" opt; do
  49. case $opt in
  50. l)
  51. options=( "${options[@]}" uploader_id like_count dislike_count thumbnail )
  52. ytdlopts=( --sub-lang en )
  53. ;;
  54. f)
  55. fullwidth=True
  56. ;;
  57. m)
  58. max_results="$OPTARG"
  59. ;;
  60. t)
  61. timeout="$OPTARG"
  62. ;;
  63. e)
  64. which "$OPTARG" >/dev/null && YTDL="$OPTARG" || exit 1
  65. ;;
  66. M)
  67. mpv=( $OPTARG )
  68. which "${mpv[0]}" >/dev/null || exit 1
  69. ;;
  70. D)
  71. debug=1
  72. ;;
  73. h|*)
  74. usage
  75. ;;
  76. esac
  77. done
  78. shift $((OPTIND-1))
  79. # quick dependency check
  80. for dep in "$YTDL" jshon; do
  81. type "$dep" >/dev/null || exit 1
  82. done
  83. perl -MHTML::Entities -e 1 || exit 1
  84. sep=''
  85. columns="$(tput cols)"
  86. [ -z "$columns" ] && columns=80
  87. # adjust separator width to terminal width
  88. for ((i=0;i<columns;i++)); do sep="$sep$sepchar"; done
  89. unset sepchar
  90. # Interactively obtain search term
  91. uts="${1%%$'\n'*}" # cut before first newline
  92. read -r -e -i "$uts" -p "Enter search term: " uts
  93. xclip -selection clipboard <<<"$uts";xclip -selection primary <<<"$uts"
  94. uts="$(perl -CS -MHTML::Entities -pe 'encode_entities($_);' <<<"$uts")"
  95. [ -z "$uts" ] && exit 1
  96. [[ "$debug" == 1 ]] && { echo "$sep"; echo "Encoded search term: $uts"; echo "Manual search: https://www.youtube.com/results?search_query=$uts"; echo "$sep"; }
  97. # adjust tabstops to longest key, cut strings to terminal width - tabstop
  98. longest=0
  99. for i in "${options[@]}"; do ((${#i} > longest)) && longest=${#i}; done
  100. longest=$((longest+3)); tabs $longest
  101. #### AND ACTION! ####
  102. mapfile -n "$max_results" -t results <<<"$("$YTDL" "${ytdlopts[@]}" --socket-timeout "$timeout" --dump-json "ytsearch$max_results:$uts")"
  103. #### AND ACTION! ####
  104. i=0
  105. url=()
  106. for line in "${results[@]}"; do
  107. echo -e "$YELLOW$i ${sep::-$(( ${#i} + 1 ))}$END"
  108. [ -z "$line" ] && echo "Empty line" && continue
  109. [[ "$debug" == 1 ]] && jshon <<<"$line" && echo -e "$YELLOW$sep$END"
  110. for o in "${options[@]}"; do
  111. res="$(jshon -e $o -u <<<"$line")"
  112. reswidth="$((columns-longest))"
  113. [[ "$fullwidth" == False ]] && (( reswidth > 15 )) && res="${res:0:$reswidth}"
  114. case "$o" in
  115. id) res="$base_url/watch?v=$res"
  116. url[$i]="$res"
  117. o="URL"
  118. ;;
  119. duration)
  120. res="${res%%.*}"
  121. ((h=${res}/3600))
  122. ((m=(${res}%3600)/60))
  123. ((s=${res}%60))
  124. res="$(printf "%02d:%02d:%02d\n" $h $m $s)"
  125. ;;
  126. esac
  127. echo -e "$GREEN$o:$END\t$res"
  128. done
  129. ((i++))
  130. done
  131. echo
  132. while :; do
  133. answer="-1"
  134. until [[ "$answer" =~ ^[0-9]+$ ]] && (( answer >= 0 )) && (( answer < i )); do
  135. read -p "Select URL no. (q to quit): " answer
  136. [[ "$answer" == q ]] && exit
  137. done
  138. url="${url[answer]}"
  139. if which xclip >/dev/null 2>&1; then
  140. xclip -selection clipboard <<<"$url"
  141. xclip -selection primary <<<"$url"
  142. echo "Copied $url to clipboard and primary."
  143. else
  144. echo "$url"
  145. fi
  146. [[ "${mpv[0]}" != '' ]] && echo "Launching ${mpv[@]} $url" && "${mpv[@]}" "$url"
  147. done