#!/usr/bin/env bash # LICENSE: CC0 # Dependencies: # fzf, jq, youtube-dl as well as bash, cut and cat :P # Optionally: mpv to play the videos N=50 CONSUMER="mpv" while [[ $# -gt 0 ]] do case "$1" in -h|--help) echo 'USAGE yt [OPTIONS] "SEARCH STRING"' echo '' echo 'Search and play YouTube videos.' echo '' echo ' -h, --help Show this help.' echo ' -n, --num-results Number of search results to fetch, defaults to 50.' echo ' -c, --consumer Command to be called with URLs of selected videos,' echo ' default is mpv.' echo ' -v, --version Print version.' echo ' -- Stops interpreting the following arguments as options.' exit ;; -n|--num-results) N="$2" if ! [[ "$N" =~ ^[0-9]+$ ]] then echo "'$N' is not an integer!" exit 1 fi shift 2 ;; -c|--consumer) CONSUMER="$2" if [ ! "$CONSUMER" ] then echo "Consumer command is missing!" exit 1 fi shift 2 ;; -v|--version) echo "1.0" exit ;; --) shift break ;; *) break ;; esac done if [ ! "$*" ] then echo "No search string given!" exit 1 fi SEARCH_JQ='.title + " | " + .uploader + " | " + (.description | tojson) + "\u0000", ., "\n"' PREVIEW_JQ='"\u001b[0;1m" + .title + "\u001b[0m" + "\n" + if (.duration | isfinite) then (.duration / 60 | round | tostring) else "?" end + " min | views: " + if (.view_count | isfinite) then (.view_count | tostring) else "?" end + " | " + .uploader + "\n\n" + .description + "\n\n\n"' PREVIEW_CMD="cat {f2} | jq -jr $(printf '%q' "$PREVIEW_JQ");[ '{n}' != '{+n}' ] && echo -e '\033[33;1m--- Playlist ---\033[0m' && cat {+f2} | jq -jr $(printf '%q' "$PREVIEW_JQ")" URLS=$(youtube-dl ytsearch$N:"$*" -j --flat-playlist | jq -cj "$SEARCH_JQ" | fzf --preview="$PREVIEW_CMD" --preview-window="wrap" -m -n 1 --with-nth=1 -d '\0' --ansi | cut -d '' -f2 | jq -r '"https://www.youtube.com/watch?v=" + .url') if [ ! "$URLS" ]; then echo "No video(s) selected!" exit 1 fi echo "Selected URLs:" echo "--------------" echo "$URLS" echo "--------------" $CONSUMER $URLS