Browse code

Filter '|' characters out of video titles.

Jenga Phoenix authored on 2019-03-16 03:55:15
Showing 6 changed files
... ...
@@ -1,50 +1,153 @@
1 1
 ===============================================================================
2
-SHELLTUBE                                    Shell scripts for easy YT-browsing
2
+SHELLTUBE                                              Browse YT with a hood on
3 3
 ===============================================================================
4
-shelltube will be a collection of (pretty POSIX) shell scripts to
5
-browse YouTube quickly, and entirely without captive UIs.
6
-Right now, there's only one script, yt-search
4
+shelltube is a simples shell-script that lets you browse Youtube--
5
+searching for playlists, videos, channels, showing their metadata
6
+(including items on playlsits and channels, etc) all from the terminal.
7 7
 
8
-shelltube is written in pure shell; its only dependencies
9
-are any modern shell (pdksh, bash, zsh), lynx, and curl/wget/ftp.
10
-Your terminal should accept ANSI color-codes, too~
8
+It YouTube quickly, and entirely without a captive UI.
11 9
 
12
-Before, shelltube was a set of scripts that culimated in a wrapper
13
-script for browsing Youtube (like mpsyt). You could even download
14
-videos from YT in pure shell! But, now, all videos require JS execution
15
-to download (as far as I can tell), so it stopped working.
10
+shelltube is written in pure shell; its only dependencies are any
11
+modern shell (pdksh, bash, zsh), lynx, and curl/wget/ftp.
16 12
 
17
-Now I'm refocusing a bit, ditching the wrapper script (begone, captive UIs,
18
-ye spectre of ole!), and starting from scratch. :)
13
+Your terminal should accept ANSI color-codes, and be >79chars wide,
14
+for best experience~
19 15
 
16
+shelltube isn't for downloading videos-- it's for *browsing* for them.
17
+Use youtube-dl or something for that, that's not my job. :P
18
+
19
+
20
+----------------------------------------
21
+INSTALLATION
22
+----------------------------------------
23
+Just place "ytlib.sh" in either the CWD, ./lib/ytlib.sh, /usr/lib/, or
24
+/usr/local/lib/
25
+
26
+Then put `gendl` and `yt` in your $PATH. /usr/local/bin/ is nice (IMO),
27
+or ~/bin/.
28
+
29
+Profit!
30
+
31
+
32
+----------------------------------------
33
+EXAMPLES
34
+----------------------------------------
35
+	yt video --search "wixoss op 1"
36
+	yt v -s "wixoss op 1"
37
+
38
+	yt playlist --search "my hero academia ops"
39
+	yt p -s "my hero academia ops"
40
+
41
+	yt playlist --title "PLY4D6ucZdLWC_yM3R_A1Hj9fAXZO_rSeK"
42
+	yt p -t "PLY4D6ucZdLWC_yM3R_A1Hj9fAXZO_rSeK"
43
+
44
+	yt playlist --list "PLY4D6ucZdLWC_yM3R_A1Hj9fAXZO_rSeK"
45
+	yt p -l "PLY4D6ucZdLWC_yM3R_A1Hj9fAXZO_rSeK"
46
+
47
+	yt video --author "https://youtube.com/watch?v=yu0HjPzFYnY"
48
+	yt v -a "https://youtube.com/watch?v=yu0HjPzFYnY"
49
+
50
+	yt video --desc "https://youtube.com/watch?v=yu0HjPzFYnY"
51
+	yt v -d "https://youtube.com/watch?v=yu0HjPzFYnY"
52
+
53
+	yt video --date "https://youtube.com/watch?v=yu0HjPzFYnY"
54
+	yt v -D "https://youtube.com/watch?v=yu0HjPzFYnY"
20 55
 
21 56
 
22 57
 ----------------------------------------
23 58
 USAGE
24 59
 ----------------------------------------
25 60
 
26
-YT-SEARCH
61
+YT
27 62
 --------------------
28
-yt-search lists videos matching a certain search query.
29
-	USAGE: yt-search [-csmb] query
63
+`yt` is the shelltube script-- it's executed with a subcommand [arguments]
64
+system, like `apt` or `git`.
65
+
66
+	USAGE: yt subcommand action [arguments]
67
+
68
+The subcommands are:
69
+	* (v)ideo
70
+	* (p)laylist
71
+
72
+They refer to actions related to videos and playlists, respectively.
30 73
 
31
-Each option [-csmb] represents a different format-method.
32
-	-b  	big      	TITLE \n DURATION | VIEWS | URL
33
-	-m	medium   	TITLE | DURATION | URL
34
-	-s	small    	TITLE | URL
35
-	-c	compact 	TITLE | ID
74
+Every subcommand and action thereof supports "-h" and "--help".
36 75
 
37
-Big takes up two lines, while the rest only use one.
38
-If you're piping output, you might wanna usa -m, -s, or -c.
39 76
 
40 77
 
41
-YT-DESC
78
+YT VIDEO
42 79
 --------------------
43
-yt-desc prints the description of a YT video.
44
-	USAGE: yt-desc url/id
80
+`yt video` is for anything related to videos-- here it is:
81
+
82
+	USAGE: yt (v)ideo [action]
83
+
84
+Here are the actions:
85
+
86
+	SHORT	LONG      	ARGUMENTS
87
+	----------------------------------------------
88
+	-s	--search	[-csmb] search_query
89
+	-t	--title  	url/id
90
+	-d	--desc  	url/id
91
+	-v	--views  	url/id
92
+	-a	--author  	[-nu] url/id
93
+	-D	--date  	url/id
94
+
95
+The only actions with weird arguments are --search and --author:
96
+	* normally, --author returns the channel URL and name on two
97
+	  seperate lines
98
+	* "--author -n" returns only the name
99
+	* "--author -u" returns only the URL
100
+
101
+	* normally, --search prints results in the "big" format (title on
102
+	  one line, other metadata on second line)
103
+	* "--search -c" for "compact" format, etc.
104
+	* "-c", "-s", "-m", "-b", for "compact", "small", "medium", and "big",
105
+	  respectively
106
+
107
+
108
+YT PLAYLIST
109
+--------------------
110
+`yt playlist` is for anything related to playlists-- here it is:
111
+
112
+	USAGE: yt (p)laylist [action]
113
+
114
+Here are the actions:
115
+
116
+	SHORT	LONG      	ARGUMENTS
117
+	----------------------------------------------
118
+	-s	--search	[-csmb] search_query
119
+	-l	--list  	[-csmb] url/id
120
+	-t	--title  	url/id
121
+	-v	--views  	url/id
122
+	-a	--author  	[-nu] url/id
123
+	-D	--date   	url/id
124
+
125
+The only actions with weird arguments are --search, --list and --author:
126
+	* --author acts just like "video --author"
127
+	* --search acts just like "video --search"
128
+	* --list acts just like --search, with [-csmb]
129
+
130
+
131
+YT CHANNEL
132
+--------------------
133
+`yt channel` is for anything related to channels-- here it is:
134
+
135
+	USAGE: yt (c)hannel [action]
136
+
137
+Here are the actions:
138
+
139
+	SHORT	LONG      	ARGUMENTS
140
+	----------------------------------------------
141
+	-s	--search	[-csmb] search_query
142
+	-l	--list  	[-csmb] url/id
143
+	-t	--title  	url/id
144
+	-d	--desc  	url/id
145
+	-v	--subscribers  	url/id
146
+	-D	--date   	url/id
45 147
 
46
-The only argument it takes is the URL/ID of the video.
47
-This script requires `lynx`.
148
+The only actions with weird arguments are --search, --list and --author:
149
+	* --search acts just like "video --search"
150
+	* --list acts just like "playlist --search"
48 151
 
49 152
 
50 153
 GENDL
... ...
@@ -70,4 +173,4 @@ BORING STUFF
70 173
 ----------------------------------------
71 174
 License is in COPYING.txt (GNU GPLv3~! <3)
72 175
 Author is Jenga Phoenix <jadedctrl@teknik.io>
73
-Sauce is at https://git.eunichx.us/shelltube
176
+Sauce is at https://git.eunichx.us/shelltube.git
74 177
deleted file mode 100644
... ...
@@ -1,44 +0,0 @@
1
-At some point in time, this SHOULD be the readme. It isn't right now, obviously.
2
-
3
-===============================================================================
4
-SHELLTUBE                                    Shell scripts for easy YT-browsing
5
-===============================================================================
6
-shelltube is a collection of (pretty POSIX) shell scripts to
7
-browse YouTube quickly, and entirely without captive UIs.
8
-
9
-shellTube is written in pure shell; its only dependencies
10
-are any modern shell (pdksh, bash, zsh) and curl/wget/ftp.
11
-Your terminal should accept ANSI color-codes, too~
12
-
13
-
14
-
15
-USAGE
16
-There are three different scripts that make up shelltube:
17
-	* yt-search
18
-	* yt-channel
19
-	* yt-meta
20
-
21
-In all three scripts:
22
-	'index' means what page of results you're on--
23
-	'results' means how many of them will be displayed.
24
-
25
-yt-search lists videos matching a certain search query.
26
-	USAGE: yt-search [-i index] [-r results] query
27
-
28
-
29
-yt-channel lists the videos of a given channel.
30
-	USAGE: yt-channel [-i index] [-r results] URL/ID/name
31
-
32
-yt-meta lists the metadata of a given video
33
-	USAGE: yt-meta URL/ID
34
-
35
-
36
-
37
-BORING STUFF
38
-License is in COPYING.txt (GNU GPLv3~! <3)
39
-Author is Jenga Phoenix <jadedctrl@teknik.io>
40
-Sauce is at https://git.eunichx.us/shelltube
41 0
new file mode 100644
... ...
@@ -0,0 +1,141 @@
1
+#!/bin/sh
2
+########################################
3
+# name: yt
4
+# lisc: gnu gplv3
5
+# main: jadedctrl
6
+# desc: browse youtube from the terminal
7
+########################################
8
+
9
+# ... there's got to be a better way to
10
+# source this.
11
+if test -e ytlib.sh; then
12
+	. ./ytlib.sh
13
+elif test -e lib/ytlib.sh; then
14
+	. ./lib/ytlib.sh
15
+elif test -e ../lib/ytlib.sh; then
16
+	. ../lib/ytlib.sh
17
+elif test -e /usr/local/lib/ytlib.sh; then
18
+	. /usr/local/lib/ytlib.sh
19
+elif test -e /usr/lib/ytlib.sh; then
20
+	. /usr/lib/ytlib.sh
21
+else
22
+	echo "ytlib.sh not found."
23
+	exit 5
24
+fi
25
+
26
+# --------------------------------------
27
+
28
+# Show usage message of shelltube itself
29
+function yt_usage {
30
+	echo "usage: yt command subcommand [arguments]"
31
+	echo "       yt (v)ideo [...]"
32
+	echo "       yt (p)laylist [...]"
33
+	exit 2
34
+}
35
+
36
+# --------------------------------------
37
+
38
+if test -z "$1"; then
39
+	yt_usage
40
+fi
41
+
42
+# --------------------------------------
43
+
44
+# Show usage message of the video subcommand
45
+function video_usage {
46
+	echo "usage: yt video --(s)earch [...]"
47
+	echo "       yt video --(t)itle [...]"
48
+	echo "       yt video --(d)esc [...]"
49
+	echo "       yt video --(a)uthor [...]"
50
+	echo "       yt video --(v)iews [...]"
51
+	echo "       yt video --(D)ate [...]"
52
+
53
+	exit 2
54
+}
55
+
56
+# Pass on commands to video subcommand
57
+function video_invocation {
58
+	local command="$1"
59
+	local arguments="$(echo "$@" | awk '{$1=""; print}')"
60
+
61
+	if test -z "$command"; then
62
+		video_usage
63
+	elif test "$(length "$arguments")" -eq 0; then
64
+		arguments="-h"
65
+	fi
66
+
67
+	case "$command" in
68
+		"--search")	video_search_invocation $arguments;;
69
+		"-s")    	video_search_invocation $arguments;;
70
+		"-d")      	video_desc_invocation $arguments;;
71
+		"--desc")   	video_desc_invocation $arguments;;
72
+		"-D")     	video_uploaded_invocation $arguments;;
73
+		"--date")   	video_uploaded_invocation $arguments;;
74
+		"--views")   	video_views_invocation $arguments;;
75
+		"-v")      	video_views_invocation $arguments;;
76
+		"--author")   	video_author_invocation $arguments;;
77
+		"-a")     	video_author_invocation $arguments;;
78
+		"--title")   	video_title_invocation $arguments;;
79
+		"-t")     	video_title_invocation $arguments;;
80
+		"--help")     	video_usage;;
81
+		"-h")     	video_usage;;
82
+	esac
83
+}
84
+
85
+# --------------------------------------
86
+
87
+# Show playlist usage message
88
+function playlist_usage {
89
+	echo "usage: yt playlist --(s)earch [...]"
90
+ 	echo "       yt playlist --(l)ist [...]"
91
+	echo "       yt playlist --(t)itle [...]"
92
+	echo "       yt playlsit --(a)uthor [...]"
93
+	echo "       yt playlist --(v)iews [...]"
94
+	echo "       yt playlist --(D)ate [...]"
95
+	exit 2
96
+}
97
+
98
+# Pass on commands to the playlist subcommand
99
+function playlist_invocation {
100
+	local command="$1"
101
+	local arguments="$(echo "$@" | awk '{$1=""; print}')"
102
+
103
+	if test -z "$command"; then
104
+		playlist_usage
105
+	elif test "$(length "$arguments")" -eq 0; then
106
+		arguments="-h"
107
+	fi
108
+
109
+	case "$command" in
110
+		"--search")	playlist_search_invocation $arguments;;
111
+		"-s")    	playlist_search_invocation $arguments;;
112
+		"--views")   	playlist_views_invocation $arguments;;
113
+		"-v")      	playlist_views_invocation $arguments;;
114
+		"--author")   	playlist_author_invocation $arguments;;
115
+		"-a")     	playlist_author_invocation $arguments;;
116
+		"--date")   	playlist_uploaded_invocation $arguments;;
117
+		"-D")     	playlist_uploaded_invocation $arguments;;
118
+		"--title")   	playlist_title_invocation $arguments;;
119
+		"-t")     	playlist_title_invocation $arguments;;
120
+		"--list")	playlist_list_invocation $arguments;;
121
+		"-l")   	playlist_list_invocation $arguments;;
122
+		"--help")     	playlist_usage;;
123
+		"-h")     	playlist_usage;;
124
+	esac
125
+}
126
+
127
+
128
+
129
+# --------------------------------------
130
+# actual invocation
131
+
132
+command="$1"
133
+arguments="$(echo "$@" | awk '{$1=""; print}')"
134
+case "$command" in
135
+	*video)  	video_invocation $arguments;;
136
+	*v)       	video_invocation $arguments;;
137
+	*channel)	channel_invocation $arguments;;
138
+	*c)      	channel_invocation $arguments;;
139
+	*playlist)	playlist_invocation $arguments;;
140
+	*p)        	playlist_invocation $arguments;;
141
+esac
0 142
deleted file mode 100755
... ...
@@ -1,44 +0,0 @@
1
-#!/bin/sh
2
-##############################
3
-# name: yt-desc
4
-# lisc: gnu gplv3
5
-# main: jadedctrl
6
-# desc: print desc of yt video
7
-##############################
8
-
9
-# Usage: yt-desc "$url/id"
10
-
11
-# STRING --> STRING
12
-# Get the description of a YT video, from HTML.
13
-function video_desc {
14
-	local html="$1"
15
-
16
-	echo "$html" \
17
-	| grep "action-panel-details" \
18
-	| sed 's/.*<p .*class="" >//' \
19
-	| sed 's%</p>.*%%' \
20
-	| lynx -stdin -dump \
21
-	| sed 's/^   //'
22
-}
23
-
24
-# --------------------------------------
25
-# invocation
26
-
27
-function usage {
28
-	echo "usage: yt-desc url/id"
29
-	exit 2
30
-}
31
-
32
-# --------------------------------------
33
-
34
-if test -z "$1"; then
35
-	usage
36
-elif echo "$1" | grep "youtube" > /dev/null; then
37
-	URL="$1"
38
-else
39
-	URL="https://www.youtube.com/watch?v=${1}"
40
-fi
41
-
42
-# --------------------------------------
43
-
44
-video_desc "$(gendl "$URL")"
45 0
deleted file mode 100755
... ...
@@ -1,250 +0,0 @@
1
-#!/bin/sh
2
-##############################
3
-# name: yt-search
4
-# lisc: gnu gplv3
5
-# main: jadedctrl
6
-# desc: search youtube simply.
7
-##############################
8
-
9
-# Usage: yt-search [-csmb] "$search_string"
10
-
11
-# --------------------------------------
12
-# a bit of math...
13
-
14
-# NUMBER NUMBER --> NUMBER
15
-# Well, subtraction. Y'know...
16
-function subtract {
17
-	local operated=$1
18
-	local operatee=$2
19
-	echo "${1}-${2}" | bc
20
-}
21
-
22
-
23
-
24
-# --------------------------------------
25
-# ... now some string manip...
26
-
27
-# NIL --> STRING
28
-# Print an ANSI "unbold" escape string.
29
-function unbold {
30
-	printf "$(tput sgr0)"
31
-}
32
-
33
-# STRING --> STRING
34
-# Print an ANSI "bold" escape string.
35
-function bold {
36
-	printf "$(tput bold)"
37
-}
38
-
39
-# STRING --> NUMBER
40
-# Return the length of a string
41
-function char_length {
42
-	subtract $(echo $1 | wc -c) 1
43
-}
44
-
45
-# STRING NUMBER [STRING] --> STRING
46
-# pad string $1 out to the minimum length $2 with padding $3 (default: "0")
47
-function min_string_length {
48
-	local string="$1"
49
-	local length=$2
50
-	if test -z "$3"; then
51
-		local padding="0"
52
-	else
53
-		local padding="$3"
54
-	fi
55
-	local new="$string"
56
-	if test $(char_length $1) -eq $2; then
57
-		echo $1
58
-	else
59
-		while test $(char_length $new) -lt $2; do
60
-			new="${new}${padding}"
61
-		done
62
-		echo $new
63
-	fi
64
-}
65
-
66
-# STRING NUMBER --> STRING
67
-# get the first $2 characters in string $1
68
-function char_get {
69
-	local number=$2
70
-	local string="$1"
71
-	string="$(min_string_length "$string" $number " ")"
72
-	echo "$string" \
73
-	| grep -o "^$(min_string_length "." $number ".")"
74
-}
75
-
76
-
77
-
78
-# --------------------------------------
79
-# ... now for the real deal~!
80
-
81
-# STRING --> STRING
82
-# Pass the raw search HTML, get raw video result-lines
83
-function result_lines {
84
-	local search_html="$1"
85
-	echo "$search_html" \
86
-	| grep "<a href=\"\/watch?v=" \
87
-	| grep -v "<span class=\"yt-thumb-simple\"" \
88
-	| grep -v "yt-lockup-playlist-item"
89
-	#| grep -v "<a href=\"/playlist" \
90
-}
91
-
92
-# STRING --> STRING 
93
-# Return the video ID of a result_line.
94
-function result_id {
95
-	local result_line="$1"
96
-	echo "$result_line" \
97
-	| sed 's%.*<a href="/watch?v=%%' \
98
-	| sed 's%".*%%'
99
-}
100
-
101
-function result_url {
102
-	local result_line="$1"
103
-	local id="$(result_id "$result_line")"
104
-	echo "https://youtube.com/watch?v=${id}"
105
-}
106
-
107
-# STRING --> STRING
108
-# Return the title of a result-line.
109
-function result_title {
110
-	local result_line="$1"
111
-	echo "$result_line" \
112
-	| sed 's%.*"  title="%%' \
113
-	| sed 's%".*%%'
114
-}
115
-
116
-function result_name {
117
-	local result_line="$1"
118
-	local title="$(result_title "$result_line")"
119
-	echo "$(bold)${title}$(unbold)"
120
-}
121
-
122
-
123
-# STRING --> STRING
124
-# Return the duration of a result-line.
125
-function result_duration {
126
-	local result_line="$1"
127
-	echo "$result_line" \
128
-	| sed 's%.*> - Duration: %%' \
129
-	| sed 's%\..*%%'
130
-}
131
-
132
-# STRING --> STRING
133
-# Return the .yt-lockup-meta-info <ul> of a result-line
134
-function result_meta_ul {
135
-	local result_line="$1"
136
-	echo "$result_line" \
137
-	| sed 's%.*<ul class="yt-lockup-meta-info">%%' \
138
-	| sed 's%</ul>.*%%'
139
-}
140
-
141
-# STRING --> STRING
142
-# Return the "Uploaded..." string of a result-line
143
-function result_uploaded {
144
-	local result_line="$1"
145
-	local result_meta_ul="$(result_meta_ul "$result_line")"
146
-	echo "$result_meta_ul" \
147
-	| sed 's%<li>%%' \
148
-	| sed 's% ago</li>.*%%'
149
-}
150
-
151
-# STRING --> NUMBER
152
-# Return the view-count of a result-line
153
-function result_views {
154
-	local result_line="$1"
155
-	local result_meta_ul="$(result_meta_ul "$result_line")"
156
-	echo "$result_meta_ul" \
157
-	| sed 's%.*<li>%%g' \
158
-	| sed 's% views</li>.*%%' \
159
-	| sed 's%,%%g'
160
-}
161
-
162
-# STRING --> STRING
163
-# Format a result-line into a mediumly-pretty, one-line string~
164
-function result_format_compact {
165
-	local result_line="$1"
166
-	local title="$(char_get "$(result_name "$result_line")" 40)$(unbold)"
167
-	local id="$(result_id "$result_line")"
168
-
169
-	echo "$name | $id"
170
-}
171
-
172
-# STRING --> STRING
173
-# Format a result-line into a mediumly-pretty, one-line string~
174
-function result_format_small {
175
-	local result_line="$1"
176
-	local name="$(char_get "$(result_name "$result_line")" 40)$(unbold)"
177
-	local url="$(result_url "$result_line")"
178
-
179
-	echo "$name | $url"
180
-}
181
-
182
-# STRING --> STRING
183
-# Format a result-line into a mediumly-pretty, one-line string~
184
-function result_format_medium {
185
-	local result_line="$1"
186
-	local name="$(char_get "$(result_name "$result_line")" 40)$(unbold)"
187
-	local duration="$(result_duration "$result_line")"
188
-	local url="$(result_url "$result_line")"
189
-
190
-	echo "$name | $duration | $url"
191
-}
192
-
193
-# STRING --> STRING
194
-# Format a result-line into a pretty string~
195
-function result_format_big {
196
-	local result_line="$1"
197
-	local name="$(char_get "$(result_name "$result_line")" 79)$(unbold)"
198
-	local duration="$(result_duration "$result_line")"
199
-	local uploaded="$(result_uploaded "$result_line")"
200
-	local views="$(result_views "$result_line")"
201
-	local url="$(result_url "$result_line")"
202
-
203
-	echo "$name"
204
-	echo "$duration |  $uploaded |  $views  |  $url"
205
-}
206
-
207
-
208
-
209
-# --------------------------------------
210
-# invocation <3
211
-
212
-function usage {
213
-	echo "usage: yt-search [-csmb] query"
214
-	exit 2
215
-}
216
-
217
-# --------------------------------------
218
-
219
-if test -z "$1"; then
220
-	usage
221
-elif test -n "$2"; then
222
-	QUERY="$2"
223
-	case "$1" in
224
-		"-c") FORMAT="compact" ;;
225
-		"-s") FORMAT="small" ;;
226
-		"-m") FORMAT="medium" ;;
227
-		"-b") FORMAT="big" ;;
228
-	esac
229
-else
230
-	QUERY="$1"
231
-	FORMAT="big"
232
-fi
233
-
234
-# --------------------------------------
235
-
236
-QUERY="$(echo "$QUERY" | sed 's/ /+/g')"
237
-search_html="$(gendl "https://youtube.com/results?search_query=$QUERY")"
238
-result_lines="$(result_lines "$search_html")" 
239
-
240
-IFS='
241
-'
242
-
243
-for result in $result_lines; do
244
-	case "$FORMAT" in
245
-		"compact") result_format_compact "$result" ;;
246
-		"small") result_format_small "$result" ;;
247
-		"medium") result_format_medium "$result" ;;
248
-		"big") result_format_big "$result" ;;
249
-	esac
250
-done
251 0
new file mode 100644
... ...
@@ -0,0 +1,869 @@
1
+#/bin/sh
2
+########################################
3
+# name: ytlib.sh
4
+# desc: library for shelltube (`yt`)
5
+# main: jadedctrl <jadedctrl@teknik.io>
6
+# code: git.eunichx.us/shelltube.git
7
+########################################
8
+
9
+# --------------------------------------
10
+# generic functions
11
+
12
+# STRING --> STRING
13
+# Return the first 'word' (space-delimiter) of a string.
14
+function car {
15
+	local string="$1"
16
+
17
+	echo "$string" \
18
+	| awk '{print $1}'
19
+}
20
+
21
+# STRING --> STRING
22
+# Return all words after the first word of a string.
23
+function cdr {
24
+	local string="$1"
25
+
26
+	echo "$string" \
27
+	| awk '{$1=""; print}' \
28
+	| sed 's/^ //'
29
+}
30
+
31
+# NUMBER NUMBER --> NUMBER
32
+# Well, subtraction. Y'know...
33
+function subtract {
34
+	local operated=$1
35
+	local operatee=$2
36
+	echo "${1}-${2}" \
37
+	| bc
38
+}
39
+
40
+# STRING --> NUMBER
41
+# Count how many words are in a string.
42
+function length {
43
+	local string="$1"
44
+
45
+	echo "$string" \
46
+	| wc -w
47
+}
48
+
49
+# STRING --> NUMBER
50
+# Count how many lines are in a string.
51
+function line_length {
52
+	local string="$1"
53
+
54
+	echo "$string" \
55
+	| wc -l
56
+}
57
+
58
+# STRING --> NUMBER
59
+# Return the length of a string in chars.
60
+function char_length {
61
+	local string="$1"
62
+
63
+	subtract $(echo "$string" | wc -c) 1
64
+}
65
+
66
+# STRING NUMBER [STRING] --> STRING
67
+# pad string $1 out to the minimum length $2 with padding $3 (default: "0")
68
+function min_string_length {
69
+	local length="$2"
70
+	local string="$1"
71
+
72
+	if test -z "$3"; then
73
+		local padding="0"
74
+	else
75
+		local padding="$3"
76
+	fi
77
+	local new="$string"
78
+	if test "$length" -le "$(char_length "$string")"; then
79
+		echo "$string"
80
+	else
81
+		while test "$(char_length "$new")" -lt "$length"; do
82
+			new="${new}${padding}"
83
+		done
84
+		echo "$new"
85
+	fi
86
+}
87
+
88
+# STRING NUMBER --> STRING
89
+# get the first $2 characters in string $1
90
+function char_get {
91
+	local number="$1"
92
+	local string="$2"
93
+
94
+	string="$(min_string_length "$string" $number " ")"
95
+	echo "$string" \
96
+	| grep -o "^$(min_string_length "." $number ".")"
97
+}
98
+
99
+
100
+
101
+# --------------------------------------
102
+# ansi colors and such
103
+
104
+# NIL --> STRING
105
+# Print an ANSI "unbold" escape string.
106
+function unbold {
107
+	printf "$(tput sgr0)"
108
+}
109
+
110
+# STRING --> STRING
111
+# Print an ANSI "bold" escape string.
112
+function bold {
113
+	printf "$(tput bold)"
114
+}
115
+
116
+# STRING --> STRING
117
+# Format a URL appropriately.
118
+function format_url {
119
+	local url="$1"
120
+
121
+	# playlist/playlist video
122
+	if echo "$url" | grep -q "playlist?"; then
123
+		echo "$url" \
124
+		| sed 's%.*list=%%'
125
+	# video
126
+	else
127
+		echo "$url"
128
+	fi
129
+}
130
+
131
+
132
+
133
+# --------------------------------------
134
+# result parsing
135
+# (playlist items, search -items)
136
+
137
+# STRING --> STRING
138
+# Pass the raw search HTML, get raw video result-lines
139
+function result_lines {
140
+	local search_html="$1"
141
+	echo "$search_html" \
142
+	| grep "<a href=\"\/watch?v=" \
143
+	| grep -v "<span class=\"yt-thumb-simple\"" \
144
+	| sed 's/|//g'
145
+	#| grep -v "<a href=\"/playlist" \
146
+}
147
+
148
+# STRING --> STRING 
149
+# Return the video ID of a result_line.
150
+function result_id {
151
+	local result_line="$1"
152
+
153
+	if echo "$result_line" | grep -q "playlist-item"; then
154
+		echo "$result_line" \
155
+		| sed 's%.*?list=%%' \
156
+		| sed 's%".*%%'
157
+	elif echo "$result_line" | grep -q "data-title"; then
158
+		echo "$result_line" \
159
+		| sed 's%.* data-video-id="%%' \
160
+		| sed 's%"><td class=".*%%' \
161
+		| sed 's%".*%%'
162
+	else
163
+		echo "$result_line" \
164
+		| sed 's%.*<a href="/watch?v=%%' \
165
+		| sed 's%".*%%'
166
+	fi
167
+}
168
+
169
+# STRING --> STRING
170
+# Return the URL of a result-line.
171
+function result_url {
172
+	local result_line="$1"
173
+	local id="$(result_id "$result_line")"
174
+
175
+	# playlist ID
176
+	if echo "$id" | grep -q "^PL"; then
177
+		echo "https://youtube.com/playlist?list=${id}"
178
+	# video ID
179
+	else	# search result
180
+		echo "https://youtube.com/watch?v=${id}"
181
+	fi
182
+}
183
+
184
+# STRING --> STRING
185
+# Return the title of a result-line.
186
+function result_title {
187
+	local result_line="$1"
188
+
189
+
190
+	# playlist video
191
+	if echo "$result_line" | grep -q "data-title"; then
192
+		echo "$result_line" \
193
+		| sed 's%.*data-title="%%' \
194
+		| sed 's%" data-video-id.*%%' \
195
+		| sed 's%".*%%'
196
+	# video
197
+	else
198
+		echo "$result_line" \
199
+		| sed 's%.*"  title="%%' \
200
+		| sed 's%".*%%'
201
+	fi
202
+}
203
+
204
+# STRING --> STRING
205
+# Return the duration of a result-line.
206
+function result_duration {
207
+	local result_line="$1"
208
+
209
+	# playlist
210
+	if echo "$result_line" | grep -q "playlist-item"; then
211
+		echo "$result_line" \
212
+		| sed 's%.*View full playlist (%%' \
213
+		| sed 's% videos.*%%' \
214
+		| sed 's%$%v%'
215
+	# playlist video
216
+	elif echo "$result_line" | grep -q "data-title"; then
217
+		echo "00:00"
218
+	# video
219
+	else	
220
+		echo "$result_line" \
221
+		| sed 's%.*> - Duration: %%' \
222
+		| sed 's%\..*%%'
223
+	fi
224
+}
225
+
226
+# STRING --> STRING
227
+# Return the channel of a result-line.
228
+function result_channel {
229
+	local result_line="$1"
230
+
231
+	# playlist
232
+	if echo "$result_line" | grep -q "playlist-item"; then
233
+		# playlist with /user/
234
+		if echo "$result_line" | grep -q "/user/"; then
235
+			echo "$result_line" \
236
+			| sed 's%.*/user/%%' \
237
+			| sed 's%</a>.*%%' \
238
+			| sed 's%.*>%%'
239
+		# playlist with /channel/
240
+		else
241
+			echo "$result_line" \
242
+			| sed 's%.*/channel/%%' \
243
+			| sed 's%</a>.*%%' \
244
+			| sed 's%.*>%%'
245
+		fi
246
+	# playlist video
247
+	elif echo "$result_line" | grep -q "data-title"; then
248
+		echo "Someone, bby <3"
249
+	# video	
250
+	else
251
+		# video with /channel/
252
+		if echo "$result_line" | grep -q "/channel/"; then
253
+			echo "$result_line" \
254
+			| sed 's%.*href="/channel/%%' \
255
+			| sed 's%</a>.*%%' \
256
+			| sed 's%.*" >%%'
257
+		# video with /user/	
258
+		elif echo "$result_line" | grep -q "/user/"; then
259
+			echo "$result_line" \
260
+			| sed 's%.*href="/user/%%' \
261
+			| sed 's%".*%%'
262
+		fi
263
+	fi
264
+}
265
+
266
+# STRING --> STRING
267
+# Return the .yt-lockup-meta-info <ul> of a result-line
268
+function result_meta_ul {
269
+	local result_line="$1"
270
+
271
+	echo "$result_line" \
272
+	| sed 's%.*<ul class="yt-lockup-meta-info">%%' \
273
+	| sed 's%</ul>.*%%'
274
+}
275
+
276
+# STRING --> STRING
277
+# Return the "Uploaded..." string of a result-line
278
+function result_uploaded {
279
+	local result_line="$1"
280
+
281
+	local result_meta_ul="$(result_meta_ul "$result_line")"
282
+
283
+	# playlist
284
+	if echo "$result_line" | grep -q "playlist-item"; then
285
+		echo "Sometime"
286
+	# playlist video	
287
+	elif echo "$result_line" | grep -q "data-title"; then
288
+		echo "Sometime"
289
+	# video
290
+	else
291
+		echo "$result_meta_ul" \
292
+		| sed 's%<li>%%' \
293
+		| sed 's% ago</li>.*%%'
294
+	fi
295
+}
296
+
297
+# STRING --> NUMBER
298
+# Return the view-count of a result-line
299
+function result_views {
300
+	local result_line="$1"
301
+	local result_meta_ul="$(result_meta_ul "$result_line")"
302
+
303
+	echo "$result_meta_ul" \
304
+	| sed 's%.*<li>%%g' \
305
+	| sed 's% views</li>.*%%' \
306
+	| sed 's%,%%g'
307
+}
308
+
309
+# STRING --> STRING
310
+# Return a result's formatted URL
311
+function result_formatted_url {
312
+	local result_line="$1"
313
+
314
+	format_url "$(result_url "$result_line")"
315
+}
316
+
317
+
318
+
319
+
320
+# --------------------------------------
321
+
322
+# STRING --> STRING
323
+# Format a result-line into a mediumly-pretty, one-line string~
324
+function result_format_compact {
325
+	local result_line="$1"
326
+	local title="$(result_title "$result_line")"
327
+
328
+	local format_title="$(bold)$(char_get 40 "$title")$(unbold)"
329
+	local id="$(result_id "$result_line")"
330
+
331
+	echo "$format_title | $id"
332
+}
333
+
334
+# STRING --> STRING
335
+# Format a result-line into a mediumly-pretty, one-line string~
336
+function result_format_small {
337
+	local result_line="$1"
338
+	local title="$(result_title "$result_line")"
339
+	local url="$(result_formatted_url "$result_line")"
340
+
341
+	local format_title="$(bold)$(char_get 40 "$title")$(unbold)"
342
+
343
+	echo "$format_title | $url"
344
+}
345
+
346
+# STRING --> STRING
347
+# Format a result-line into a mediumly-pretty, one-line string~
348
+function result_format_medium {
349
+	local result_line="$1"
350
+	local title="$(result_title "$result_line")"
351
+	local duration="$(result_duration "$result_line")"
352
+	local url="$(result_formatted_url "$result_line")"
353
+
354
+	local format_title="$(bold)$(char_get 40 "$title")$(unbold)"
355
+	local format_duration="$(char_get 5 "$duration")"
356
+
357
+	echo "$format_title | $format_duration | $url"
358
+}
359
+
360
+# STRING --> STRING
361
+# Format a result-line into a pretty string~
362
+function result_format_big {
363
+	local result_line="$1"
364
+	local title="$(result_title "$result_line")"
365
+	local duration="$(result_duration "$result_line")"
366
+	local uploaded="$(result_uploaded "$result_line")"
367
+	local channel="$(result_channel "$result_line")"
368
+	local url="$(result_formatted_url "$result_line")"
369
+
370
+	local format_title="$(bold)$(char_get 79 "$title")$(unbold)"
371
+	local format_duration="$(char_get 7 "$duration")"
372
+	local format_uploaded="$(char_get 8 "$uploaded")"
373
+	local format_channel="$(char_get 15 "$channel")"
374
+
375
+	echo "$format_title"
376
+	echo "$format_duration |  $format_uploaded |  $format_channel  |  $url"
377
+}
378
+
379
+
380
+
381
+
382
+# --------------------------------------
383
+# playlsit metadata
384
+
385
+# STRING --> STRING
386
+# Get the title of a playlist, from HTML.
387
+function playlist_title {
388
+	local html="$1"
389
+
390
+	video_title "$html"
391
+}
392
+
393
+# STRING --> STRING
394
+# Get the video-count of a playlist, from HTML.
395
+function playlist_duration {
396
+	local html="$1"
397
+
398
+	playlist_header_details "$html" \
399
+	| sed 's%.*</a></li>%%' \
400
+	| sed 's%</li>.*%%' \
401
+	| sed 's%<li>%%'
402
+}
403
+
404
+# STRING --> STRING
405
+# Get the view-count of a playlist, from HTML.
406
+function playlist_views {
407
+	local html="$1"
408
+
409
+	playlist_header_details "$html" \
410
+	| sed 's%.*</a></li>%%' \
411
+	| sed 's%</li><li>Last.*%%' \
412
+	| sed 's%.*</li><li>%%' \
413
+	| sed 's% views%%' \
414
+	| sed 's%,%%'
415
+}
416
+
417
+# STRING --> STRING
418
+# Get the uploaded date of a playlist, from HTML.
419
+function playlist_uploaded {
420
+	local html="$1"
421
+
422
+	playlist_header_details "$html" \
423
+	| sed 's%.*</a></li>%%' \
424
+	| sed 's%.*</li><li>%%' \
425
+	| sed 's%Last updated on %%' \
426
+	| sed 's%</li>.*%%'
427
+}
428
+
429
+# STRING --> STRING
430
+# Get the author name of a playlist, from HTML.
431
+function playlist_author_name {
432
+	local html="$1"
433
+
434
+	playlist_header_details "$html" \
435
+	| sed 's%</li><li>.*%%' \
436
+	| sed 's%.* >%%' \
437
+	| sed 's%</.*%%'
438
+}
439
+
440
+# STRING --> STRING
441
+# Get the author URL of a playlist, from HTML.
442
+function playlist_author_url {
443
+	local html="$1"
444
+
445
+	local author_name="$(playlist_author_name "$html")"
446
+
447
+	playlist_header_details "$html" \
448
+	| sed 's%'"$author_name"'.*%%' \
449
+	| sed 's%.*href="%%' \
450
+	| sed 's%".*%%' \
451
+	| sed 's%^%https://youtube.com%'
452
+}
453
+
454
+# STRING --> STRING
455
+# Return the metadata header for playlist HTML
456
+function playlist_header_details {
457
+	local html="$1"
458
+
459
+	echo "$html" \
460
+	| grep "pl-header-details"
461
+}
462
+
463
+# --------------------------------------
464
+# video metadata
465
+
466
+# STRING --> STRING
467
+# Get the description of a YT video, from HTML.
468
+function video_desc {
469
+	local html="$1"
470
+
471
+	echo "$html" \
472
+	| grep "action-panel-details" \
473
+	| sed 's/.*<p .*class="" >//' \
474
+	| sed 's%</p>.*%%' \
475
+	| lynx -stdin -dump \
476
+	| sed 's/^   //'
477
+}
478
+
479
+# STRING --> STRING
480
+# Get the views of a YT video, from HTML.
481
+function video_views {
482
+	local html="$1"
483
+
484
+	echo "$html" \
485
+	| grep "watch-view-count" \
486
+	| sed 's/.*"watch-view-count">//' \
487
+	| sed 's/ views.*//' \
488
+	| sed 's/,//g'
489
+}
490
+
491
+# STRING --> STRING
492
+# Get the uploader's name of a YT video, from HTML.
493
+function video_author_name {
494
+	local html="$1"
495
+
496
+	echo "$html" \
497
+	| grep "\"name\": " \
498
+	| sed 's/.*"name": "//' \
499
+	| sed 's/".*//'
500
+}
501
+
502
+# STRING --> STRING
503
+# Get the URL to a video uploader's channel, from HTML
504
+function video_author_url {
505
+	local html="$1"
506
+
507
+	local author_name="$(video_author_name "$html")"
508
+	local relative_url="$(echo "$html" \
509
+				| grep "$author_name" \
510
+				| grep "channel" \
511
+				| grep "href" \
512
+				| sed 's%.*="/%/%' \
513
+				| sed 's/".*//')"
514
+	echo "https://youtube.com${relative_url}"
515
+}
516
+
517
+# STRING --> STRING
518
+# Get the title of a video, from HTML.
519
+function video_title {
520
+	local html="$1"
521
+
522
+	echo "$html" \
523
+	| grep "meta name=\"title\"" \
524
+	| sed 's/.*content="//' \
525
+	| sed 's/".*//' \
526
+	| sed 's/ - Youtube//'
527
+}
528
+
529
+
530
+
531
+# --------------------------------------
532
+
533
+# STRING STRING --> STRING
534
+# Display results from a string of result_lines and a format-option
535
+function results_display {
536
+	local result_lines="$1"
537
+	local format="$2"
538
+
539
+	IFS='
540
+'
541
+
542
+	for result in $result_lines; do
543
+		case "$format" in
544
+			"compact") result_format_compact "$result" ;;
545
+			"small") result_format_small "$result" ;;
546
+			"medium") result_format_medium "$result" ;;
547
+			"big") result_format_big "$result" ;;
548
+		esac
549
+	done
550
+}
551
+
552
+
553
+
554
+# --------------------------------------
555
+# playlist usage
556
+
557
+# Print playlist usage.
558
+function playlist_list_usage {
559
+	echo "usage: yt playlist --list [-csmb] url/id"
560
+	exit 2
561
+}
562
+
563
+# Print playlist usage.
564
+function playlist_search_usage {
565
+	echo "usage: yt playlist --search [-csmb] search_query"
566
+	exit 2
567
+}
568
+
569
+# Print playlist usage.
570
+function playlist_views_usage {
571
+	echo "usage: yt playlist --views url/id"
572
+	exit 2
573
+}
574
+
575
+# Print playlist usage.
576
+function playlist_author_usage {
577
+	echo "usage: yt playlist --author [-un] url/id"
578
+	exit 2
579
+}
580
+
581
+# Print playlist usage.
582
+function playlist_date_usage {
583
+	echo "usage: yt playlist --date url/id"
584
+	exit 2
585
+}
586
+
587
+# Print playlist usage.
588
+function playlist_title_usage {
589
+	echo "usage: yt playlist --title url/id"
590
+	exit 2
591
+}
592
+
593
+
594
+
595
+# --------------------------------------
596
+# playlist invocation
597
+
598
+# Invoke the playlist --list command
599
+function playlist_list_invocation {
600
+	if test "$1" = "-h" -o "$1" = "--help"; then playlist_list_usage; fi
601
+
602
+	if test -n "$2"; then
603
+		local url="$2"
604
+		case "$1" in
605
+			"-c") local format="compact" ;;
606
+			"-s") local format="small" ;;
607
+			"-m") local format="medium" ;;
608
+			"-b") local format="big" ;;
609
+		esac
610
+	else
611
+		local url="$1"
612
+		local format="big"
613
+	fi
614
+
615
+	if echo "$url" | grep -qv "youtube.com"; then
616
+		url="https://www.youtube.com/playlist?list=${url}"
617
+	fi
618
+
619
+	playlist_html="$(gendl "$url")"
620
+	result_lines="$(result_lines "$playlist_html")" 
621
+
622
+	results_display "$result_lines" "$format"
623
+}
624
+
625
+# Invoke the playlist --search command
626
+function playlist_search_invocation {
627
+	if test "$1" = "-h" -o "$1" = "--help"; then playlist_search_usage; fi
628
+
629
+	if test -n "$2"; then
630
+		local query="$2"
631
+		case "$1" in
632
+			"-c") local format="compact" ;;
633
+			"-s") local format="small" ;;
634
+			"-m") local format="medium" ;;
635
+			"-b") local format="big" ;;
636
+		esac
637
+	else
638
+		local query="$1"
639
+		local format="big"
640
+	fi
641
+
642
+	query="$(echo "$query" | sed 's/ /+/g')"
643
+
644
+	local search_url="https://youtube.com/results?search_query=${query}"
645
+	search_url="${search_url}&sp=EgIQAw%253D%253D"
646
+
647
+	local search_html="$(gendl "$search_url")"
648
+	local result_lines="$(result_lines "$search_html")" 
649
+
650
+	results_display "$result_lines" "$format"
651
+}
652
+
653
+# Invoke playlist --title
654
+function playlist_title_invocation {
655
+	if test "$1" = "-h" -o "$1" = "--help"; then playlist_title_usage; fi
656
+	
657
+	local url="$1"
658
+
659
+	playlist_title "$(gendl "$url")"
660
+}
661
+
662
+# Invoke playlist --desc
663
+function playlist_desc_invocation {
664
+	if test "$1" = "-h" -o "$1" = "--help"; then playlist_desc_usage; fi
665
+
666
+	if echo "$1" | grep "youtube" > /dev/null; then URL="$1"
667
+	else
668
+		URL="https://www.youtube.com/playlist?list=${1}"
669
+	fi
670
+
671
+	playlist_desc "$(gendl "$URL")"
672
+}
673
+
674
+# Invoke playlist --views
675
+function playlist_views_invocation {
676
+	case "$1" in
677
+		"-h")	playlist_views_usage ;;
678
+		"--help")
679
+			playlist_views_usage ;;
680
+		*youtube*)
681
+			local url="$1" ;;
682
+		*)	local url="https://www.youtube.com/playlist?list=${1}" ;;
683
+	esac
684
+
685
+	playlist_views "$(gendl "$url")"
686
+}
687
+
688
+# Invoke playlist --date
689
+function playlist_uploaded_invocation {
690
+	if test "$1" = "-h" -o "$1" = "--help"; then playlist_date_usage; fi
691
+
692
+	if echo "$1" | grep "youtube" > /dev/null; then URL="$1"
693
+	else
694
+		URL="https://www.youtube.com/playlist?list=${1}"
695
+	fi
696
+
697
+	playlist_uploaded "$(gendl "$URL")"
698
+}
699
+
700
+# Invoke playlist --author
701
+function playlist_author_invocation {
702
+	case "$1" in
703
+		"--help")
704
+			playlist_author_usage ;;
705
+		"-h")	playlist_author_usage ;;
706
+		"-u")	view="url"
707
+			url="$2"
708
+			;;
709
+		"-n")	view="name"
710
+			url="$2"
711
+			;;
712
+		*)	view="both"
713
+			url="$1"
714
+			;;
715
+	esac
716
+
717
+	if echo "$url" | grep -qv "youtube"; then
718
+		url="https://www.youtube.com/playlist?list=${1}"
719
+	fi
720
+
721
+	html="$(gendl "$url")"
722
+
723
+	case "$view" in
724
+		"url")	playlist_author_url "$html" ;;
725
+		"name") playlist_author_name "$html" ;;
726
+		"both") echo "$(playlist_author_name "$html")"
727
+			echo "$(playlist_author_url "$html")"
728
+			;;
729
+	esac	
730
+}
731
+
732
+# --------------------------------------
733
+# video usage
734
+
735
+# Print video --search usage
736
+function video_search_usage {
737
+	echo "usage: yt video --search [-csmb] query"
738
+	exit 2
739
+}
740
+
741
+# Print video --desc usage
742
+function video_desc_usage {
743
+	echo "usage: yt video --desc url/id"
744
+	exit 2
745
+}