diff --git a/INSTALL.md b/INSTALL.md new file mode 100644 index 0000000..3df433c --- /dev/null +++ b/INSTALL.md @@ -0,0 +1,4 @@ +Simple. Just move the "shelltube" script along with +the scripts in lib/ into your PATH. +Then-- boom, installed. +Groovy. diff --git a/README.md b/README.md new file mode 100644 index 0000000..6d9c34b --- /dev/null +++ b/README.md @@ -0,0 +1,102 @@ +![Shelltube](https://cloud.githubusercontent.com/assets/7250745/21452795/52fcd6ea-c901-11e6-871b-bd646f2d7c49.png) + +shellTube is a collection of (pretty POSIX) shell scripts to +browse YouTube quickly, efficiently, and without the bloat +most command-line clients require. + +shellTube is written in pure shell; its only dependencies +are any modern shell (pdksh, bash, zsh), curl/wget, and +vlc/mplayer/kaffeine. + +Even these dependencies, though, can easily be changed. If, +for example, you don't have vlc, you can just modify a +single line and be good-to-go using another player. + +Also, shellTube doesn't use the YouTube API at all. This +avoids the annoying red-tapey stuff that goes with it -- IDs, +registration, quotas -- but has some disadvantages. We'll +power through the downsides, though! :) + + +Usage +------- +shellTube is quite simple to use; this tutorial will go over +the usage of the wrapper script, `shelltube`. +When running the script, you'll see a prompt: + +``` + >> +``` + +In this prompt you can type any of the following commands: + +| (short) command syntax | description | +| --- | --- | +| (`!`) `about` | View the about page. | +| (`cls`) `clear` | Clear the screen. | +| (`dl`) `download [URL] ` | Download the selected/specified video. | +| `exit` | Exit Shelltube. | +| (`?`) `help` | Display this message. | +| (`md`) `metadata [URL]` | Display selected/specified video's metadata. | +| (`//`) `playlist URL` `playlist ID` | View playlist based on `URL` or `ID`. | +| (`/`) `search TERM` | Perform a search for `TERM`. | +| (`str`) `stream [URL]` | Stream the selected/specified video. | +| (`sel`) `video URL` `video ID` | Select video based on `URL` or `ID`. | +| (`lq`) `queue` | Lists all videos in the queue. | +| (`sq`) `squeue` | Streams all videos in the queue. | +| (`dq`) `dqueue` | Downloads all videos in the queue. | + +In [brackets], optional arguments are written. + +You can use shellTube in one of two ways (or both): + +1. By selecting a video and then doing something with it +2. By doing something and specifying the video + +Method A entails using either the `video` or `search` +command to select a video, which will then be displayed +before the prompt like so: + +``` +$VIDEO-ID-HERE >> +``` + +When a video is selected, you use the `download`, `stream`, +or `metadata` commands without arguments to act on the +video. + +Method B entails just using the `download`, `stream`, or +`metadata` commands while using a URL or video ID as an +argument. + +For example: + +``` + >> download $VIDEO-ID-HERE +``` + +You can also download or stream multiple videos in a row +without user input with the queue. +The queue is a list of video IDs in the file `/tmp/yt-queue` +You can add to the queue manually or while looking at +search results, playlist videos, or channel videos by inputting +`*` rather than a number when prompted. This adds every video +listed to the queue. +When you're back at the main prompt, you can enter `lq`, `dq`, +or `sq` to list, download, or stream the queued videos. + +You could opt to not use this interactive wrapper script and +instead just use the `yt-down`, `yt-search`, and +`yt-metadata` scripts on their own. + +They are each pretty simple, and you can read their USAGE +messages at the top of each script. + + +Licensing +----------- +All of ST is released under the +[ISC](https://opensource.org/licenses/ISC) license. + +Except for the `y-down` script, which is released under the +[GPLv2](https://www.gnu.org/licenses/gpl-2.0.html). diff --git a/lib/st-download b/lib/st-download new file mode 100755 index 0000000..fe4a98e --- /dev/null +++ b/lib/st-download @@ -0,0 +1,23 @@ +#!/bin/sh +##################### +# Name: st-download.sh +# Lisc: ISC +# Main: jadedctrl +# Desc: No beer and no TV +# make Homer go +# something-something +# Cxu ne? +##################### + +if test -z "$download_cmd" +then + if command -v wget > /dev/null + then + wget -q "$1" -O "$2" + elif command -v curl > /dev/null + then + curl -s "$1" -o "$2" + fi +else + $download_cmd +fi diff --git a/lib/st-video b/lib/st-video new file mode 100755 index 0000000..f7933d2 --- /dev/null +++ b/lib/st-video @@ -0,0 +1,28 @@ +#!/bin/sh +##################### +# Name: st-video.sh +# Date: 2016-12-22 +# Lisc: ISC +# Main: jadedctrl +# Desc: Does a thing with +# a video-thingy thing +# dsfgbvesrht fd +##################### + +if [ -e "$HOME/.config/shelltube" ] +then + . "$HOME/.config/shelltube" +fi + +if test -z "$player_cmd" +then + if command -v vlc > /dev/null + then + vlc --play-and-exit "${1}" + elif command -v mplayer > /dev/null + then + mplayer --quiet "${1}" + fi +else + $player_cmd "${1}" +fi diff --git a/lib/yt-channel b/lib/yt-channel new file mode 100755 index 0000000..7a36b59 --- /dev/null +++ b/lib/yt-channel @@ -0,0 +1,191 @@ +#!/bin/sh +##################### +# Name: yt-channel.sh +# Lisc: ISC +# Main: jadedctrl +# Desc: Display a channel's videos +# or details in easy-to-read +# and easy-to-parse results. +##################### + +# Usage: yt-channel.sh [-uci] userid||channel + +if [ -e "$HOME/.config/shelltube" ] +then + . "$HOME/.config/shelltube" +else + results=21 +fi + +if [ -e "./lib/yt-meta" ] +then + alias yt-channel="./lib/yt-channel" + alias yt-search="./lib/yt-down" + alias yt-meta="./lib/yt-meta" + alias yt-search="./lib/yt-search" + alias yt-down="./lib/yt-channel" + alias st-download="./lib/st-download" + alias st-video="./lib/st-video" +fi + +interactive_mode=0 +channel_file="/tmp/$(mktemp -u yt-channel_XXXXXX)" + +# I really need to work out a better way to take flags. +# This is just awful. +# ... I'll cross that bridge later. + + +if [ "$1" = "-u" ] +then + type="user" + st-download "https://youtube.com/user/$2/videos" "$channel_file" +elif [ "$1" = "-iu" ] +then + output="$3" + interactive_mode=1 + type="user" + st-download "https://youtube.com/user/$2/videos" "$channel_file" +elif [ "$1" = "-c" ] +then + type="channel" + st-download "https://youtube.com/channel/$2/videos" "$channel_file" +elif [ "$1" = "-ic" ] +then + output="$3" + interactive_mode=1 + type="channel" + st-download "https://youtube.com/channel/$2/videos" "$channel_file" +elif [ "$1" = "-uc" ] || [ -k "$2" ] +then + echo "Usage: yt-channel.sh [-uci] userid||channel [output]" + echo "Make sure to use either the -u flag or the -c flag--" + echo "*not* both! Also, specify a userid or channel name." + exit 1 +else + echo "Usage: yt-channel.sh [-uc] userid||channel" + exit 1 +fi + +get_input() { + printf '\033[0;32m>>>\033[0m ' + read -r n + + if [ "$n" = "exit" ] + then + exit + fi + if [ "$n" == "*" ] + then + cat $temp_file | while IFS='' read -r CUR_LINE + do + echo "$CUR_LINE" | sed 's/.*href="\/watch?v=//' | sed 's/".*//' >> $output + done + cp $output /tmp/yt-queue +# test $n -ge 0 + elif [ $? -gt 1 ] + then + echo "Bad input, mate. Type in a valid number or 'exit'." + get_input + elif [ $n -gt 20 ] + then + echo "Out of range. Type in a valid number or 'exit'." + get_input + elif [ $n -gt 0 ] && [ $n -lt 20 ] + then + sed -n "${n}p" "$temp_file" | sed 's/.*href="\/watch?v=//' | sed 's/".*//' > "$output" + else + echo "Bad input, mate. Type in a valid number or 'exit'." + get_input + fi +} + + +row=0 + +# Now for displaying the search results +temp_file="/tmp/$(mktemp -u yt-channel_XXXXXX)" + +grep "href=\"\/watch?v=" "$channel_file" | grep "title=" | grep -v \ + " "$temp_file" +item_num=0 +cat "$temp_file" | while IFS='' read -r CUR_LINE +do + item_num=$((item_num+1)) + LINE="$(echo "$CUR_LINE" | sed 's/.*//')" + LINE="$(echo "$LINE" | sed 's/views<\/li>.*//')" + LINE="$(echo "$LINE" | sed 's/title="Verified"//')" + + if [ $row -eq 1 ] + then + #color='\033[1;34m' + #color2='\033[1;34m' + printf '\033[1;34m' + row=0 + elif [ $row -eq 0 ] + then + #color='\033[1;31m' + #color2='\033[1;31m' + printf '\033[1;31m' + row=1 + fi + + if echo "$LINE" | grep "View full playlist" > /dev/null + then + type="Playlist" + title=$(echo "$LINE" | sed 's/.*title="//' | sed 's/".*//') + items=$(echo "$LINE" | sed 's/.*View full playlist (//' | sed 's/).*//') + if [ $item_num -ge $((results+1)) ] + then + break + elif [ $item_num -lt 10 ] + then + printf '%s. ' "$item_num" + else + printf '%s. ' "$item_num" + fi + printf '%s' "$title" + printf ' ' + printf '%s | %s' "$type" "$items" + printf ' ' + else + type="Video" + duration=$(echo "$LINE" | sed 's/.*Duration: //' | sed 's/\..*//') + itemid=$(echo "$LINE" | sed 's/.*href="\/watch?v=//' | sed 's/".*//') + title=$(echo "$LINE" | sed 's/.* title="//' | sed 's/".*//') + + if [ $item_num -ge $((results+1)) ] + then + break + elif [ $item_num -lt 10 ] + then + printf '%s. ' "$item_num" + else + printf '%s. ' "$item_num" + fi + echo "$title" + printf ' ' + i=0 + while [ $i -lt 9 ] + do + i=$((i+1)) + char=$(echo "$duration" | cut -c$i) + if [ -z "$char" ] + then + printf ' ' + else + printf '%s' "$char" + fi + done + printf ' | %s\n' "$itemid" + fi +done + +if [ $interactive_mode -eq 1 ] +then + get_input +fi + +printf '\033[0m' + +rm "$temp_file" diff --git a/lib/yt-down b/lib/yt-down new file mode 100755 index 0000000..b1fb632 --- /dev/null +++ b/lib/yt-down @@ -0,0 +1,140 @@ +#!/bin/sh +##################### +# Name: yt-down +# Lisc: GPLv2 +# Auth: iluaster +# Main: jadedctrl +# Desc: Fetches YT videos. +##################### + +# Based on https://github.com/iluaster/Youtube_downloader + +# Usage: yt-down -[sSD] $video_id +# -s for stream; -S for stream and skip prompt; +# -D for download and skip prompt; No arg for download. + + +if [ "$1" = "-s" ] +then + stream_mode=1 + id=$2 +elif [ "$1" = "-S" ] +then + stream_mode=1 + skip_prompt=1 + id=$2 +elif [ "$1" = "-D" ] +then + stream_mode=0 + skip_prompt=1 + id=$2 +else + stream_mode=0 + id=$1 +fi + +if [ -e "./lib/yt-meta" ] +then + alias yt-channel="./lib/yt-channel" + alias yt-search="./lib/yt-down" + alias yt-meta="./lib/yt-meta" + alias yt-search="./lib/yt-search" + alias yt-down="./lib/yt-channel" + alias st-download="./lib/st-download" + alias st-video="./lib/st-video" +fi + + +if echo "$id" | grep "youtube.com" +then + id="$(echo "$id" | sed 's/.*video_id=//')" +elif [ -z "$id" ] +then + echo "No video specified." + exit 1 +else + id="$id" +fi + +name="http://www.youtube.com/get_video_info?video_id=$id" + +declare -i line=0 2> /dev/null + +if $? 2> /dev/null +then + echo > /dev/null +else + line=0 +fi + +select_option () +{ + echo "Formats:" + cat /tmp/video_type_option.txt | while IFS='' read -r i + do + line=$((line+1)) + # Replace this pipe method so $line isn't lost + echo "${line}. $i" + done + if [ $skip_prompt -eq 0 ] + then + printf '\033[0;32m>>>\033[0m ' + IFS='' + read -r n + else + n=1 + fi + + if [ $n -le 5 ]; + then + head -n "$n" /tmp/tmp3.txt | tail -n 1 > /tmp/tmp4.txt + else + echo "$line $n" + echo "Input Error!" + line=0 + select_option + fi +} + + +st-download "$name" "/tmp/${id}_url.txt" + +# Cut and filter mp4 url + +cp "/tmp/${id}_url.txt" /tmp/tmp2.txt +sed -e 's/&/\n/g' /tmp/tmp2.txt| grep 'url_encoded_fmt_stream_map'> /tmp/tmp3.txt +sed -i -e 's/%2C/,/g' /tmp/tmp3.txt +sed -i -e 's/,/\n/g' /tmp/tmp3.txt + +# Print out total video format name and quality +perl -ne 'print "$2,$1\n" if /quality%3D(.*?)%.*video%252F(.*?)(%|\n)/' /tmp/tmp3.txt > /tmp/video_type_option.txt + +# If video format name is prior to quality +perl -ne 'print "$1,$2\n" if /video%252F(.*?)%.*quality%3D(.*?)(%|\n)/' /tmp/tmp3.txt >> /tmp/video_type_option.txt +sed -i -e 's/x-flv/flv/g' /tmp/video_type_option.txt + +select_option + +# Set file extension name variable and video quality variable +extension_name=$(head -n "$n" /tmp/video_type_option.txt | tail -n 1 | cut -d "," -f 1) +quality_name=$(head -n "$n" /tmp/video_type_option.txt | tail -n 1 | cut -d "," -f 2) + +sed -i -e 's/%26/\&/g' /tmp/tmp4.txt +sed -i -e 's/&/\n/g' /tmp/tmp4.txt +grep 'http' /tmp/tmp4.txt > /tmp/tmp5.txt +grep 'sig%3D' /tmp/tmp4.txt >> /tmp/tmp5.txt +perl -pe 's/\n//g' /tmp/tmp5.txt | sed -e 's/sig%3D/\&signature%3D/g' > /tmp/tmp6.txt +sed -i -e 's/url%3D//g' /tmp/tmp6.txt +# url decoding +cat /tmp/tmp6.txt | sed -e 's/%25/%/g' -e 's/%25/%/g' -e 's/%3A/:/g' -e 's/%2F/\//g' -e 's/%3F/\?/g' -e 's/%3D/=/g' -e 's/%26/\&/g' > /tmp/tmp7.txt + + +if [ $stream_mode -eq 1 ] +then + st-video "$(cat /tmp/tmp7.txt)" +else + st-download "$(cat /tmp/tmp7.txt)" "${id}_${quality_name}.${extension_name}" +fi + + +rm -f /tmp/tmp[2-7].txt "/tmp/${id}_url.txt" /tmp/video_type_option.txt diff --git a/lib/yt-meta b/lib/yt-meta new file mode 100755 index 0000000..9f4d9fd --- /dev/null +++ b/lib/yt-meta @@ -0,0 +1,117 @@ +#!/bin/sh + +##################### +# Name: yt-meta.sh +# Date: 2016-12-10 +# Lisc: ISC +# Main: jadedctrl +# Desc: Fetches metadata about +# a specific YT video. +##################### + +# Usage: yt-meta.sh $video_id + +optnum=0 + +for argument in $@ +do + if echo $argument | grep "^-" > /dev/null + then + charcount=$(echo "$argument" | echo "$(wc -c) - 1" | bc) + while [ $charcount -gt 0 ] + do + character=$(echo "$argument" | head -c1) + argument=$(echo "$argument" | sed 's/^.//') + case $character in + c) + options="$options c" + optnum=$((optnum+1)) ;; + d) # duration + options="$options d" + optnum=$((optnum+1)) ;; + D) # date + options="$options D" + optnum=$((optnum+1)) ;; + v) + options="$options v" + optnum=$((optnum+1)) ;; + t) + options="$options t" + optnum=$((optnum+1)) ;; + i) + options="$options i" + optnum=$((optnum+1)) ;; + -) ;; + esac + charcount=$((charcount-1)) + done + else + preid="$argument" + fi +done + + +if echo "$preid" | grep "youtube.com" > /dev/null +then + id="$(echo $preid | sed 's/.*v=//')" +elif [ -z $preid ] +then + echo "No video specified." + exit 1 +else + id="$preid" +fi + +if [ -e "./lib/yt-meta" ] +then + alias yt-channel="./lib/yt-channel" + alias yt-search="./lib/yt-down" + alias yt-meta="./lib/yt-meta" + alias yt-search="./lib/yt-search" + alias yt-down="./lib/yt-channel" + alias st-download="./lib/st-download" + alias st-video="./lib/st-video" +fi + + +video_file="/tmp/$(mktemp -u yt-video_XXXXXX)" +if type "wget" &> /dev/null +then + wget -q https://youtube.com/watch?v=$id -O $video_file + wget -q https://youtube.com/results?search_query=$id -O $video_file.1 +elif type "curl" &> /dev/null +then + curl -s https://youtube.com/watch?v=$id -o $video_file + curl -s https://youtube.com/results?search_query=$id -o $video_file.1 +fi + +# Now for displaying the metadata +title="$(grep "\"title\":\"" $video_file | sed 's/.*"title":"//' | sed 's/".*//')" +author="$(grep "\"author\":\"" $video_file | sed 's/.*"author":"//' | sed 's/".*//')" +views="$(grep "\"view_count\":\"" $video_file | sed 's/.*"view_count":"//' | sed 's/".*//')" +duration="$(grep ">>\033[0m ' + read -r n + + if [ "$n" == "exit" ] + then + exit + fi + + if [ "$n" == "*" ] + then + cat $temp_file | while IFS='' read -r CUR_LINE + do + echo $CUR_LINE | sed 's/.*data-video-id="//' | sed 's/".*//' >> $output + cp $output /tmp/yt-queue + done +# test $n -ge 0 &> /dev/null + elif [ $? -gt 1 ] + then + echo "Bad input, mate. Type in a valid number or 'exit'." + get_input + elif [ $n -gt 20 ] + then + echo "Out of range. Type in a valid number or 'exit'." + get_input + elif [ $n -gt 0 ] && [ $n -lt 20 ] + then + sed -n ${n}p $temp_file | sed 's/.*data-video-id="//' | sed 's/".*//' > $output + else + echo "Bad input, mate. Type in a valid number or 'exit'." + get_input + fi +} + +# If Google adds any extra features or changes the webpage +# layout, this script'll break immediately, haha. +# ... But at least we aren't using their API, right? + +plist_file="/tmp/$(mktemp -u yt-search_XXXXXX)" + +st-download https://youtube.com/playlist?list=$plist $plist_file + +# Now for displaying the search results +temp_file="/tmp/$(mktemp -u yt-result_XXXXXX)" +grep " $temp_file + +item_num=0 +cat $temp_file | while IFS='' read -r CUR_LINE +do + item_num=$(($item_num+1)) + + if [ $row -eq 1 ] + then + #color='\033[1;34m' + #color2='\033[1;34m' + printf '\033[1;34m' + row=0 + elif [ $row -eq 0 ] + then + #color='\033[1;31m' + #color2='\033[1;31m' + printf '\033[1;31m' + row=1 + fi + + itemid=$(echo "$CUR_LINE" | sed 's/.*data-video-id="//' | sed 's/".*//') + title=$(echo "$CUR_LINE" | sed 's/.*data-title="//' | sed 's/".*//') + author=$(grep -C3 " $(echo $title)" "$plist_file" | grep "by " | sed 's/.*">//' | sed 's^.*^^') + + if [ $item_num -ge $((results+1)) ] + then + break + elif [ $item_num -lt 10 ] + then + printf '%s. ' "$item_num" + else + printf '%s. ' "$item_num" + fi + printf '%s\n' "$title" + printf ' ' + i=0 + while [ $i -lt 16 ] + do + i=$((i+1)) + char=$(echo $author | cut -c$i) + if [ -z $char ] + then + printf ' ' + else + printf '%s' "$char" + fi + done + printf ' | ' + i=0 + while [ $i -lt 5 ] + do + i=$((i+1)) + char=$(echo $duration | cut -c$i) + if [ -z $char ] + then + printf ' ' + else + printf '%s' "$char" + fi + done + printf ' | %s\n' "$itemid" +done + +printf '\033[0m' + +if [ $interactive_mode -eq 1 ] +then + get_input +fi diff --git a/lib/yt-search b/lib/yt-search new file mode 100755 index 0000000..56ec4e8 --- /dev/null +++ b/lib/yt-search @@ -0,0 +1,190 @@ +##################### +# Name: yt-result.sh +# Date: 2016-12-10 +# Lisc: ISC +# Main: jadedctrl +# Desc: Search YT videos and display +# in easy-to-read and easy-to # -parse results +##################### + +# Usage: yt-search.sh "$search_string" + +if [ -e $HOME/.config/shelltube ] +then + . $HOME/.config/shelltube +else + results=21 +fi + +if [ -e "./lib/yt-meta" ] +then + alias yt-channel="./lib/yt-channel" + alias yt-search="./lib/yt-down" + alias yt-meta="./lib/yt-meta" + alias yt-search="./lib/yt-search" + alias yt-down="./lib/yt-channel" + alias st-download="./lib/st-download" + alias st-video="./lib/st-video" +fi + +row=0 + +if [ "$1" == "-i" ] +then + interactive_mode=1 + query="$(echo "$2" | sed 's/ /+/g')" + output="$3" +else + interactive_mode=0 + query="$(echo "$1" | sed 's/ /+/g')" +fi + +function get_input() { + printf '\033[0;32m>>>\033[0m ' + read -r n + + if [ "$n" == "exit" ] + then + exit + elif [ "$n" == "*" ] + then + cat $temp_file | while IFS='' read -r CUR_LINE + do + echo "$CUR_LINE" | sed 's/.*> $output + done + cp $output /tmp/yt-queue + #test $n -ge 0 &> /dev/null + elif [ $? -gt 1 ] + then + echo "Bad input, mate. Type in a valid number or 'exit'." + get_input + elif [ $n -gt 20 ] + then + echo "Out of range. Type in a valid number or 'exit'." + get_input + elif [ $n -gt 0 ] && [ $n -lt 20 ] + then + if sed -n ${n}p $temp_file | grep "View full playlist" > /dev/null + then + sed -n ${n}p $temp_file | sed 's/.*&list=//' | sed 's/".*//' > $output + else + sed -n ${n}p $temp_file | sed 's/.* $output + fi + else + echo "Bad input, mate. Type in a valid number or 'exit'." + get_input + fi +} + +# If Google adds any extra features or changes the webpage +# layout, this script'll break immediately, haha. +# ... But at least we aren't using their API, right? + +search_file="/tmp/$(mktemp -u yt-search_XXXXXX)" + +st-download https://youtube.com/results?search_query=$query $search_file + +# Now for displaying the search results +temp_file="/tmp/$(mktemp -u yt-result_XXXXXX)" +grep " $temp_file +item_num=0 +cat $temp_file | while IFS='' read -r CUR_LINE +do + item_num=$(($item_num+1)) + # These tags trip up 'title=' and '" >' queries later on. Strip 'em. + LINE="$(echo $CUR_LINE | sed 's/.*//')" + LINE="$(echo $LINE | sed 's/views<\/li>.*//')" + LINE="$(echo $LINE | sed 's/title="Verified"//')" + + if [ $row -eq 1 ] + then + #color='\033[1;34m' + #color2='\033[1;34m' + printf '\033[1;34m' + row=0 + elif [ $row -eq 0 ] + then + #color='\033[1;31m' + #color2='\033[1;31m' + printf '\033[1;31m' + row=1 + fi + + if echo "$LINE" | grep "View full playlist" > /dev/null + then + type="Playlist" + title=$(echo "$LINE" | sed 's/.*title="//' | sed 's/".*//') + items=$(echo "$LINE" | sed 's/.*View full playlist (//' | sed 's/).*//') + itemid=$(echo "$LINE" | sed 's/.*&list=//' | sed 's/".*//') + if [ $item_num -ge $((results+1)) ] + then + break + elif [ $item_num -lt 10 ] + then + printf '%s. ' "$item_num" + else + printf '%s. ' "$item_num" + fi + printf '%s\n' "$title" + printf ' ' + printf '%s | %s | %s\n' "$type" "$items" "$itemid" + else + type="Video" + duration=$(echo "$LINE" | sed 's/.*Duration: //' | sed 's/\..*//') + itemid=$(echo "$LINE" | sed 's/.* /dev/null + then + # For /channel/ users + author=$(echo "$LINE" | sed 's/.*" >//' | sed 's/<\/a>.*//') + else + # For /user/ users + author=$(echo "$LINE" | sed 's/.*\/user\///' | sed 's/".*//') + fi + + if [ $item_num -ge $((results+1)) ] + then + break + elif [ $item_num -lt 10 ] + then + printf '%s. ' "$item_num" + else + printf '%s. ' "$item_num" + fi + printf '%s\n' "$title" + printf ' ' + i=0 + while [ $i -lt 16 ] + do + i=$((i+1)) + char=$(echo $author | cut -c$i) + if [ -z $char ] + then + printf ' ' + else + printf '%s' "$char" + fi + done + printf ' | ' + i=0 + while [ $i -lt 5 ] + do + i=$((i+1)) + char=$(echo $duration | cut -c$i) + if [ -z $char ] + then + printf ' ' + else + printf '%s' "$char" + fi + done + printf ' | %s\n' "$itemid" + fi +done + +printf '\033[0m' + +if [ $interactive_mode -eq 1 ] +then + get_input +fi diff --git a/shelltube b/shelltube new file mode 100755 index 0000000..d25016e --- /dev/null +++ b/shelltube @@ -0,0 +1,229 @@ +#!/bin/sh + +#################### +# Name: shelltube.sh +# Lisc: ISC +# Main: jadedctrl +# Desc: Full-shell YT client that avoids the YT API. + Vers=0.5.2 +##################### + +# Roadmap 1.0: +# yt-meta: +# [X] Args for specific info +# [X] Better argument handling +# yt-playlist: +# [X] Playlist support +# [ ] Better argument handling +# yt-channel: +# [X] Channel support +# [ ] Better argument handling +# yt-search: +# [|] Channel & Playlist search +# [ ] Search filters +# [ ] Better argument handling +# general: +# [|] Config video player, etc +# [|] Cli args as commands + + +if [ -e "$HOME/.config/shelltube" ] +then + . "$HOME/.config/shelltube" +fi + +if [ -e "./lib/yt-meta" ] +then + alias yt-channel="./lib/yt-channel" + alias yt-meta="./lib/yt-meta" + alias yt-playlist="./lib/yt-playlist" + alias yt-search="./lib/yt-search" + alias yt-down="./lib/yt-down" + alias st-download="./lib/st-download" + alias st-video="./lib/st-video" +fi + +search() { + output="$(mktemp -u /tmp/yt_XXXXXX)" + yt-search -i "$1" "$output" + if sed -n ${1}p "$output" | grep "^PL" > /dev/null + then + playlist "$(sed -n ${1}p "$output")" + else + selected_video="$(sed -n ${1}p "$output")" + yt-meta "$selected_video" + fi +} + +playlist() { + output="$(mktemp -u /tmp/yt_XXXXXX)" + yt-playlist -i "$1" "$output" + selected_video="$(sed -n ${1}p "$output")" + yt-meta "$selected_video" +} + +channel() { + output="$(mktemp -u /tmp/yt-channel_XXXXXX)" + case "$1" in + UC* ) + yt-channel -ic "$1" "$output" + ;; + * ) + yt-channel -iu "$1" "$output" + ;; + esac + selected_video="$(sed -n 1p "$output")" + yt-meta "$selected_video" +} + +about() { + printf '\n \033[1mshell\033[41m Tube \033[0;1;30m v%s\033[m\n\n' "$Vers" + printf '\033[32mDesc: \033[0;34mYT client written in shell.\033[m\n' + printf '\033[32mMain: \033[0;34mjadedml@openmailbox.org\033[m\n' + printf '\033[32mLisc: \033[0;34mISC; yt-down GPLv2\033[m\n' +} + +help() { + printf "\ +about | ! View the about page. +clear | cls Clear the screen. +download | dl Download the selected video. +exit | ctrl+c Exit Shelltube. +help | ? Display this message. +metadata | md Display selected video's metadata. +playlist | // Display a playlist's videos. +search | / Perform a search. +channel | chan Show newest videos of a channel. +stream | str Stream the selected video. +video | sel | url Select video based on URL or ID. +queue | lq List videos in the queue. +squeue | sq Stream all videos in the queue. +dqueue | dq Download all videos in the queue. + +Note about usage: +Both 'video ID; download' and 'download ID' are valid. You don't need to +select a video to run commands on it, but if you use metadata, download, or +stream on an unselected video you must specify the ID or URL after the command. +" +} + +parse() { + command="$1" argument="$2" + + case "$command" in + help | '?' ) + help + ;; + playlist ) + playlist "$argument" + ;; + //* ) + playlist "${command#//}" + ;; + search ) + search "$argument" + ;; + /* ) + search "${command#/} $argument" + ;; + channel ) + channel "$argument" + ;; + chan ) + channel "$argument" + ;; + video | sel | url ) + case "$argument" in + *youtube.com* ) + selected_video="$argument" + ;; + *) + selected_video="$argument" + ;; + esac + yt-meta "$selected_video" + ;; + metadata | md ) + selected_video="${argument:-$selected_video}" + yt-meta "$selected_video" + ;; + download | dl ) + selected_video="${argument:-$selected_video}" + yt-down "$selected_video" + ;; + stream | str ) + selected_video="${argument:-$selected_video}" + yt-down -s "$selected_video" + ;; + queue | lq ) + cat /tmp/yt-queue | while IFS='' read -r CUR_LINE + do + if [ $row -eq 1 ] + then + printf '\033[1;34m%s\n' "$CUR_LINE" + row=0 + else + printf '\033[1;31m%s\n' "$CUR_LINE" + row=1 + fi + done + ;; + cqueue | cq ) + rm /tmp/yt-queue + touch /tmp/yt-queue + ;; + dqueue | dq ) + for LINE in $(cat /tmp/yt-queue) + do + itemid="$(echo "$LINE" | sed 's/.*\| //')" + echo $itemid + sleep 3 + yt-down -D "$itemid" + grep -v "$itemid" /tmp/yt-queue > /tmp/yt-queue.tmp + mv /tmp/yt-queue.tmp /tmp/yt-queue + done + ;; + squeue | sq ) + for LINE in $(cat /tmp/yt-queue) + do + itemid="$(echo "$LINE" | sed 's/.*| //')" + echo $itemid + sleep 3 + yt-down -S "$itemid" + grep -v "$itemid" /tmp/yt-queue > /tmp/yt-queue.tmp + mv /tmp/yt-queue.tmp /tmp/yt-queue + done + ;; + about | ! ) + about + ;; + clear | cls ) + printf '\033[H\033[J' + ;; + exit ) + rm -f "/tmp/yt-$$" + exit + ;; + '' ) ;; + * ) + echo "Unknown command: \"$command\"" + echo "Try \"help\" or \"?\"" + ;; + esac +} + +if [ "$#" -gt 0 ] +then + for arg in "$@" + do + parse "${arg%% *}" "${arg#* }" + done +else + printf '\n \033[1mshell\033[41m Tube \033[0;1;30m v%s\033[m\n\n' "$Vers" + + while printf '\033[0;34m%s \033[0;32m>>\033[m ' "$selected_video" + do + read -r command argument + parse "$command" "$argument" + done +fi