www.sandromaffiodo.com
/homepage /list +nerd

Contact: yt tw fb in mail git


Tags: [all] obfuscated rubik arduino vgax terminal ebook epub esp8266 espvgax game javascript php scifi ioccc piano music book youtube curl

YouTube from Terminal (Part 2)

This is the second part of the Nerd guide to play Youtube videos from your terminal.

In the first part these bash function has been added to my .bashrc (or .bash_profile on Mac OS X):

function yt {
    mpv --ontop --geometry=320x200+0+0 $(youtube-dl -g -f 18 $1)    
}
#download Youtube video using youtube-dl
function dyt {
    curl $(youtube-dl -g -f 18 $1) -o video.mp4
}

Now, the missing part is to search something and play all results. The follow solution will play all results in sequence. Youtube results are paginated on multiple HTML pages. In this case this script will play only the first page of results (who care.. these NERD scripts are insane):

#search Youtube and play all results
function yts {
    curl "https://www.youtube.com/results?search_query=$(echo $* | sed -E 's/ /%20/g')" -L | grep -o '/watch?[^\"]*' | uniq | grep -v "list=" | while read -r line; do yt "https://www.youtube.com$line"; done;
}

To use this function you only need only to type

yts MY LONG SEARCH STRING

To skip a video that you do not like you need to close mpv window. To terminate the script (looping throught all results) you need to send CTRL-C to the terminal running yts.

If you want to download all files, instead of playing them, you can use dyt instead of yt.

Let's break this function in pieces:

$(echo '$*' | sed -E 's/ /%20/g')

Grab all parameters passed to yts function ($*) and replace all whitespaces with %20 (the space character encoded for HTML URL)

curl "https://www.youtube.com/results?search_query=$(echo '$*' | sed -E 's/ /%20/g')" -L

Download youtube search results, following HTTP redirection (-L)

grep -o '/watch?[^\"]*' | uniq

Extract all /watch?* video URL. Some URL are duplicated so with uniq the output of the command is a list of unique URLs without duplicates

grep -v "list="

Exclude all lines that contains "list="; these lines are for Youtube playlists

while read -r line; do yt "https://www.youtube.com$line"; done;

Loop throught each line. For each line execute yt function to view the video (or dyt if you want to download videos).

Full code for play and search

#play Youtube video using youtube-dl
function yt {
    mpv --ontop --geometry=320x200+0+0 $(youtube-dl -g -f 18 $1)    
}
#download Youtube video using youtube-dl
function dyt {
    curl $(youtube-dl -g -f 18 $1) -o video.mp4
}
#search Youtube and play all results
function yts {
    curl "https://www.youtube.com/results?search_query=$(echo '$*' | sed -E 's/ /%20/g')" -L | grep -o '/watch?[^\"]*' | uniq | grep -v "list=" | while read -r line; do dyt "https://www.youtube.com$line"; done;
}

YouTube from Terminal (Part 1)

Sometimes a NERD watch Youtube without a browser opened. NERDS use text browsers like LYNX or W3M :-D

In the past years i've tryed mps-youtube and youtube-viewer, both are terminal apps that allow you to search, view and download videos from Youtube, but this time i want something more customizable, also based on youtube-dl.

Solution 1: play video from URL

You need only these two tools: youtube-dl and mpv. I think that these are the same tools used by mps-youtube. This solution is quick and dirty.

Installation on Mac (via brew) is easy:

brew install youtube-dl mpv

On Linux, Debian based distros, you can use apt:

apt-get install youtube-dl mpv

After that you can open your video with this command (replace VIDEO_URL with your Youtube video URL):

mpv $(youtube-dl -g -f 18 VIDEO_URL)

The magic number 18 is to select MP4 360p videos. If you want to select others format you can choose from one of these:

MAGIC NUMBER FORMAT RESOLUTION CODECS
171 webm audio only vorbis
140 m4a audio only mp4a
133 mp4 426x240 avc1 video only
134 mp4 640x360 avc1 video only
135 mp4 854x480 avc1 video only
247 webm 1280x720 vp9 video only
136 mp4 1280x720 avc1 video only
248 webm 1920x1080 vp9 video only
137 mp4 1920x1080 avc1 video only
43 webm 640x360 vp8 + vorbis
18 mp4 640x360 avc1 + mp4a
22 mp4 1280x720 avc1 + mp4a

If you want to be lazy in typing commands (like a real NERD needs to be), you can add this function to your .bashrc (or .bash_profile if you use Mac OS X) and use have this solution ready anytime you need to watch videos from terminal:

function yt {
    mpv $(youtube-dl -g -f 18 $1)   
} 

To use this function you only need only to type

yt VIDEO_URL

Download videos

If you want to download videos, instead of playing them, you only need to replace mpv with curl:

function dyt {
    curl $(youtube-dl -g -f 18 $1) -o video.mp4
} 

Picture in Picture alike

When i work on my computer i like to have the video that i am watching on one corner of the screen, possibly on top of the others windows (this mode is normally called PIP: picture in picture). With mpv you can use two parameters to configure the position of the window and the stay-on-top mode:

mpv --ontop --geometry=WIDTHxHEIGHT+X+Y

Add these parameters to your scripts to have mpv play like a PIP!

Experiment without youtube-dl (little more complex)

You don't like to use existent tools. You are a NERD and you like to do everything with a bunch of curl, grep and sed commands. Supposing that you do not wont to rewrite curl or mpv (you dont?), you can use curl to extract the required video URL and play that with mpv:

function ytc {
    mpv $(echo -ne $(curl $1 | grep -o 'https[^\"]*' | grep videoplayback | grep itag%3D18 | sed -E "s/%/\\\\x/g"))
}

This is it. HTML scraping: the worst thing you should do, EVER. Let's break each command apart:

curl $1 | grep -o 'https[^\"]*'

curl youtube page and extract all HTTPS links contained in the page. If you look at the HTML page returned from Youtube, you will see that inside HTML there is a big JSON string that contains all HTTPS URLs for the final video playback. These links contains the videoplayback substring. see screenshot-1

grep videoplayback

select only lines that contains videoplayback substring

grep itag%3D18

select only lines with itag=18 (my preferred format is 18, you can choose others format from the table above). %3D is the character = escaped inside the HTTP URL

sed -E "s/%/\\\\x/g"

convert each HTTP encoded characters from %NN to \xNN. This is the standard C/bash escape for characters expressed as hexadecimal two digit number

echo -ne

echo results converting all \xNN sequences to its ASCII equivalents. After that you obtain the final URL. Something like this: r11---sn-hpa7zn7r.googlevideo.com/videoplayback?initcwndbps=472500&sparams=clen%2Cdur%2Cei%2Cgir%2Cid%2Cinitcwndbps%2Cip%2Cipbits%2Citag%2Clmt%2Cmime%2Cmm%2Cmn%2Cms%2Cmv%2Cnh%2Cpl%2Cratebypass%2Crequiressl%2Csource%2Cupn%2Cexpire&ip=87.8.231.48&key=yt6&mn=sn-hpa7zn7r&signature=23D980F8415F6F313EF422E95BA85AA55FCD22BA.96645A049DC436870F36DD48BFE64DE20283F787&mm=31&ms=au&id=o-AP4my72PmmcNCaYptxcQ92Q3knmzotCfM9FaAHfHAW5E&ei=PAw6WP2GE4HXcPy_haAF&mv=m&mt=1480198892&dur=590.483&lmt=1428034888381069&source=youtube&upn=vncEZvHsRZc&itag=18&requiressl=yes&clen=40049035&nh=IgpwcjA0Lm1pbDAxKgw3Mi4xNC4yMDQuNzM&ipbits=0&ratebypass=yes&pl=19&expire=1480220828&gir=yes&mime=video%2Fmp4

mpv

run mpv, finally

PLEASE NOTE that this solution do not work for all Youtube videos. Use youtube-dl instead, it works better and it is less insane.

Full code

#play Youtube video using youtube-dl
function yt {
    mpv --ontop --geometry=320x200+0+0 $(youtube-dl -g -f 18 $1)    
}
#download Youtube video using youtube-dl
function dyt {
    curl $(youtube-dl -g -f 18 $1) -o video.mp4
}
#play Youtube video without youtube-dl (do not work for all videos) 
function ytc {
    mpv $(echo -ne $(curl $1 | grep -o 'https[^\"]*' | grep videoplayback | grep itag%3D18 | sed -E "s/%/\\\\x/g"))
}
#download Youtube video without youtube-dl (do not work for all videos) 
function ytc {
    curl $(echo -ne $(curl $1 | grep -o 'https[^\"]*' | grep videoplayback | grep itag%3D18 | sed -E "s/%/\\\\x/g")) -o video.mp4
}

Have FUN (or use a normal, more easy, soft clickable, quite adorable WebBrowser like everyone do)