Welcome to HBH! If you had an account on hellboundhacker.org you will need to reset your password using the Lost Password system before you will be able to login.

CLI Youtube Viewer - Perl Code Bank


CLI Youtube Viewer
Search and play videos from Youtube with MPlayer. Deps on Unix: perl-libwww, mplayer Deps on Windows: Active-Perl, SMPlayer
                #!/usr/bin/perl
#
# Copyright (C) 2010-2011 Trizen <echo dHJpemVueEBnbWFpbC5jb20K | base64 -d>.
#
# This program is free software: you can redistribute it and/or modify
# it under the terms of the GNU General Public License as published by
# the Free Software Foundation, either version 3 of the License, or
# (at your option) any later version.
#
# This program is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
# GNU General Public License for more details.
#
# You should have received a copy of the GNU General Public License
# along with this program.  If not, see <http://www.gnu.org/licenses/>.
#
#-------------------------------------------------------
#  (C) 2010-2011 by Trizen
#  Created on: 02 Jun 2010
#  Latest edit on: 03 July 2011
#  Website: http://trizen.go.ro
#  Email: echo dHJpemVueEBnbWFpbC5jb20K | base64 -d
#-------------------------------------------------------
#
# [?] What is this script for?
#  - This script is useful to search and watch YouTube videos with MPlayer...
#  - Have fun!
#
# [!] Most important changes are written in the changelog!
#
# [CHANGELOG]
# - Added few options to control cache of MPlayer and lower cache for lower video resolutions  - NEW (v2.5.1)
# - Added colours for text (--colours) or $colours = 1, 360p support (-3), playlist support    - NEW (v2.5.0)
# - Added support for today and all time Youtube tops (usage: -t, --tops, -a, --all-time)      - (v2.4.*)
# - Re-added the support for the next page / Added support for download (-d, --download)       - (v2.4.*)
# - Added support for Youtube CCaptions. (Depends on: 'gcap' - http://gcap.googlecode.com)     - (v2.4.*)
# - First version with Windows support. Require SMPlayer to play videos. See MPlayer Line      - (v2.4.*)
# - Code has been changed in a proportion of ~60% and optimized for speed // --480 became -4   - (v2.4.*)
# - Added mega-powers of omnibox to the STDIN :)                                               - (v2.3.*)
# - Re-added the option to list and play youtube videos from a user profile. Usage: -u [user]  - (v2.3.*)
# - Added a new option to play only the audio track of a videoclip. Usage: [words] -n          - (v2.3.*)
# - Added option for fullscreen (-f, --fullscreen). Usage: youtube-viewer [words] -f           - (v2.3.*)
# - Added one new option '-c'. It shows available categories and will let you to choose one.   - (v2.3.*)
# - Added one new option '-m'. It shows 3 pages of youtube video results. Usage: [words] -m    - (v2.3.*)
# - For "-A" option has been added 3 pages of youtube video results (50 clips)                 - (v2.3.*)
# - Added "-prefer-ipv4" to the mplayer line (videoclips starts in no time now).               - (v2.3.*)
# - Search and play videos at 480p, 720p. Ex: [words] --480, [words] -A --480                  - (v2.3.*)
# - Added support to play a video at 480p even if it's resolution is higher. Ex: [url] --480   - (v2.2.*)
# - Added a nice feature which prints some informations about the current playing video        - (v2.2.*)
# - Added support to play videos by your order. Example: after search results, insert: 3 5 2 1 - (v2.1.*)
# - Added support for next pages of video results (press <ENTER> after search results)         - (v2.1.*)
# - Added support to continue playing searched videos, usage: "youtube-viewer [words] -A"      - (v2.1.*)
# - Added support to print counted videos and support to insert a number instead of video code - (v2.1.*)
# - Added support to search YouTube Videos in script (ex: youtube-viewer avatar trailer 2009)  - (v2.0.*)
# - Added support for script to choose automat quality if it is lower than 1080p               - (v2.0.*)
# - Added support to choose the quality only between 720p and 1080p (if it is available)       - (v2.0.*)
# - Added support for an YouTube video code (ex: youtube-viewer WVTWCPoUt8w)                   - (v1.0.*)
# - Added support for 720p and 1080p YouTube Videos...                                         - (v1.0.*)

# Special thanks to:
# - Army (for bugs reports and for his great ideas)
# - dhn (for adding youtube-viewer in freshports.org)

use URI::Escape;
use HTML::Entities;
my $os                   = $^O;
my $appname              = 'youtube-viewer';
my $version              = '2.5.1';
my $colours              = 0;
my $cache                = 30000;
my $cache_min            = 5;
my $user_lower_cache     = 0;
my $order_by             = 'relevance';
my $time_p               = 'all_time';
my $mplayer_settings     = "-prefer-ipv4 -cache $cache -cache-min $cache_min";
my $mplayer_srt_settings = '-unicode -utf8';
if ( $os =~ /(?:win|dos)/i ) {
    $MPlayer_exe = $ENV{'ProgramFiles'} . '\\SMPlayer\\mplayer\\mplayer.exe';
    unless ( -e $MPlayer_exe ) {
        warn "\n\n!!! Please install SMPlayer to stream Youtube videos.\n\n";
    }
    $MPlayerLine = qq["$MPlayer_exe" $mplayer_settings];
}
else {
    $MPlayerLine = "mplayer $mplayer_settings";
}

sub UserAgent {
    require LWP::UserAgent;
    $lwp = 'LWP::UserAgent'->new;
    $lwp->agent('Mozilla/5.0 (X11; U; Linux i686; en-US) Chrome/10.0.648.45');
    $lwp->env_proxy;
    $lwp->timeout(15);
    $lwp->show_progress(1) if $debug;
    $lwp_is_set = 1;
}
if ( not $os =~ /(?:win|dos)/i ) {
    $bred   = "\e[1;31m";
    $bgreen = "\e[1;32m";
    $reset  = "\e[0m";
}
else {
    $bred   = '';
    $bgreen = '';
    $reset  = '';
}
foreach my $arg (@ARGV) {
    if ( $arg =~ /^-/ ) {
        $stdin_argvs .= " $arg ";
    }
    else {
        $Search .= "$arg ";
    }
    next unless $arg =~ /^-/;
    if ( $arg =~ /^-+cache=(\d+)$/ ) {
        my $cache = $1;
        $MPlayerLine =~ s/-cache\s+\d+/-cache $cache/;
        $user_cache = 1;
        next;
    }
    if ( $arg =~ /^-+(?:l|lower.?cache)$/ ) {
        $user_lower_cache = 1;
        next;
    }
    if ( $arg =~ /^-+cache.?min=(\d+)$/ ) {
        my $cache_min = $1;
        $MPlayerLine =~ s/-cache-min\s+\d+/-cache-min $cache_min/;
        $user_cache_min = 1;
        next;
    }
    if ( $arg =~ /^-+(?:n|no.?video)$/ ) {
        $MPlayerLine =~ s/mplayer /mplayer -novideo /;
        $MPlayerLine =~ s/mplayer\.exe"/mplayer.exe" -novideo/;
        $stdin_argvs .= ' --480';
        next;
    }
    if ( $arg =~ /^-+time=(.+)/ ) {
        $time_p = $1;
        next;
    }
    if ( $arg =~ /^-+(?:T|tty|M|mplayer)=(.+)/ ) {
        $MPlayerLine .= " $1";
        next;
    }
    if ( $arg =~ /^-+(?:o|order.?by)=(.+)/ ) {
        $order_by = $1;
        next;
    }
    if ( $arg =~ /^-+(?:sub|lang)=([\w]+)$/ ) {
        $default_sub = lc $1;
        next;
    }
    if ( $arg =~ /^-+(?:colou?rs?|C|cl)$/ ) {
        $colours = 1;
        next;
    }
    if ( $arg =~ /^-+(?:d|download)$/ ) {
        $download_video = 1;
        next;
    }
    if ( $arg =~ /^-+(?:a|all.?time)$/ ) {
        $all_time = 1;
        next;
    }
    if ( $arg eq '--debug' ) {
        $debug = 1;
        next;
    }
    if ( $arg =~ /^-+(?:A|all)$/ ) {
        $playback = 1;
        $stdin_argvs .= ' --1080';
        next;
    }
    if ( $arg =~ /^-+(?:m|more)$/ ) {
        $MoreResults = 1;
        next;
    }
    if ( $arg =~ /^-+(?:fs?|fullscreen)$/ ) {
        $MPlayerLine =~ s/mplayer /mplayer -fs /;
        $MPlayerLine =~ s/mplayer.exe"/mplayer.exe" -fs/;
    }
}
if ( $colours and not $os =~ /(?:win|dos)/i ) {
    $cblack  = "\e[40m";
    $byellow = "\e[1;33m";
    $bpurle  = "\e[1;35m";
    $bblue   = "\e[1;34m";
}
else {
    $bblue   = '';
    $cblack  = '';
    $bpurle  = '';
    $byellow = '';
}
$stdin_argvs ||= '';
$default_sub ||= 'en';
$Search      ||= '';
foreach my $arg (@ARGV) {
    ++$i;
    next unless $arg =~ /^-/;
    if ( $arg =~ /^[-]+(?:h|help|\?|usage)$/i ) {
        &help;
    }
    if ( $arg =~ /^[-]+(?:v|version)$/i ) {
        &version;
    }
    if ( $arg =~ /^[-]+(?:pl?|playlists?)$/ ) {
        &search_playlists;
    }
    if ( $arg =~ /^[-]+(?:c|categories)$/ ) {
        &categories_area;
    }
    if ( $arg =~ /^[-]+(?:a|all[_-]?time|t|tops)$/ ) {
        &youtube_tops;
    }
    if ( $arg =~ /^[-]+(?:u|username)$/ ) {
        if ( $ARGV[$i] ) {
            unless ( $ARGV[$i] =~ /^-/ ) {
                $user = $ARGV[$i];
            }
        }
        unless ($user) {
            $i -= 2;
            if ( $ARGV[$i] ) {
                unless ( $ARGV[$i] =~ /^-/ ) {
                    $user = $ARGV[$i];
                }
            }
        }
        if ($user) {
            &videos_from_username($user);
        }
    }
}
foreach $_ (@ARGV) {
    if ( not $_ =~ /^-/ or length $_ == 11 ) {
        $non_argv = 1;
        last;
    }
}
&insert_url unless $non_argv;
foreach my $code (@ARGV) {
    if ( $code =~ /^([\w-]{11})$/ ) {
        $code = $1;
        if ( $code =~ /[\d]+|[A-Z]+|-/ ) {
            $dont_exit = 1;
            &get_youtube($code);
        }
    }
    elsif ( $code =~ /view_play_list\?p=([A-Z0-9]+)/ ) {
        $playlist = 1;
        &list_playlist($1);
    }
    elsif ( $code =~ m[(?:v|embed)[=/]+([\w-]{11})] ) {
        $code      = $1;
        $dont_exit = 1;
        if ( length $code == 11 ) {
            &get_youtube($code);
        }
        else {
            next;
        }
    }
    elsif ( $code =~ m[^http://] and not $code =~ /youtube\.com/ ) {
        &code_from_content($code);
    }
    else {
        next;
    }
}

sub help {
    my $appname = uc $appname;
    print "\n\t" . '=' x 25 . " $appname " . '=' x 25 . qq[
\t\t\t\t\t\t  by Trizen (trizen.go.ro)
\n Usage: youtube-viewer [<url> | <video_id>] [-(4|7|1)]
                       [-u <username>] [-categories] [-(a|t)]
                       [<keywords>] [-fs] [-novideo] [-(m|p)]
\nBase Options: youtube-viewer [...]
   <url>                : play an YouTube video by URL
   <code>               : play an YouTube video by code
   <keywords>           : search and list YouTube videos
   <playlist_url>       : list a playlist of Youtube videos
\nYoutube options:
   -t, --tops           : shows today Youtube tops
   -a, --all-time       : shows all time Youtube tops
   -c, --categories     : shows available YouTube categories
   -m, --more           : shows more video results (50 clips)
   -p, --playlist       : searches for Youtube playlists
   -u <username>        : lists videos uploaded by a specific user
   -order-by=<ORDER>    : order entries by: published, viewCount or rating
   -time=<TIME>         : valid values are: today, this_week and this_month
   -2, -3, -4, -7, -1   : plays videos at 240p, 360p, 480p, 720p and 1080p
\nMPlayer options:
   -f, --fullscreen     : plays all videos in fullscreen mode
   -n, --novideo        : plays only the audio track of video(s)
   -l, --lower-cache    : set a lower cache for MPlayer (for slow connections)
   -mplayer='SETTINGS'  : add some extra options to the MPlayer line
   -sub=<LANG>          : subtitle language (default: en) (depends on gcap)
   -cache=<VALUE>       : set cache for MPlayer (default: $cache)
   -cache-min=<VALUE>   : set cache-min for MPlayer (default: $cache_min)
\nOther options:
   -d, --download       : downloads youtube video(s) with LWP
   -A, --all            : plays all video results in order
   -C, --colors         : use colors for text output
   -v, --version        : prints version and exits
   -h, --help           : prints help and exits
\nTips and tricks:
  1. After search results, press <ENTER> for the next page
  2. After search results, insert: <number> (--download, -d, -1, -4, -7)
  3. After search results, insert more numbers to play videos in your order
  4. Play all audio tracks of video results by adding "-A -n" after keywords.
  5. Play all video results in fullscreen mode at 720p: "<keywords> -A -f -7"
  6. Play all videos from a user at 480p: "<username> -u -4" and insert "all"
\n];
    exit;
}

sub version {
    print "Youtube Viewer $version\n";
    exit;
}

sub code_from_content {
    &UserAgent unless $lwp_is_set;
    $connect = $lwp->get( $_[0] ) if $_[0];
    if ( $connect->content =~ m[youtube\.com/(?:v|embed)/([\w-]{11})] ) {
        &get_youtube($1);
    }
}

sub insert_url {
    print "\n$bred=>>$reset$bgreen "
      . "Insert an YouTube URL or search something...\n$reset> ";
    chomp( $youtube = <STDIN> );
    if ( $youtube =~ m[(?:v|embed)[=/]+([\w-]{11})] ) {
        &get_youtube($1);
    }
    elsif ( $youtube =~ /view_play_list\?p=([A-Z0-9]+)/ ) {
        $playlist = 1;
        &list_playlist($1);
    }
    elsif ( $youtube =~ m[^http://] and not $youtube =~ /youtube\.com/ ) {
        &code_from_content($youtube);
    }
    elsif ($youtube) {
        $stdin_argvs .= ' ' . $youtube;
        $Search = $youtube;
        $number = 0;
        &search;
    }
    else {
        warn "\n$bred(x_x) Unable to continue...$reset\n\n";
        exit;
    }
}

sub videos_from_username {
    $yt_api_url = "http://gdata.youtube.com/feeds/api/users/$_[0]/uploads";
    &YoutubeAPI;
}

sub search_playlists {
    $playlists = 1;
    unless ($lwp_is_set) {
        &UserAgent;
    }
    my $url = $_[0]
      || "http://gdata.youtube.com/feeds/api/playlists/snippets?q=$Search"
      . '&start-index=1';
    if ($MoreResults) {
        $url .= '&max-results=50&v=2';
    }
    else {
        $url .= '&max-results=20&v=2';
    }
    my (@playlists) = split( m?<title>?, $lwp->get($url)->content, 0 );
    my $n = -1;
    foreach $_ (@playlists) {
        if ( $_ =~ m[^([^<]*)</title>] ) {
            my $title = $1;
            if ( $n == -1 ) {
                ++$n;
                next;
            }
            $title = decode_entities($title);
            $line  = "<title=$title>";
        }
        if ( $_ =~ m[<summary>([^<]*)</summary>] ) {
            $summary = $1;
            $summary =~ s/\s+/ /g;
            $summary = $1 if $summary =~ /^(.{10})/;
            $summary = decode_entities($summary);
            $line .= "<summary=$summary>";
        }
        else {
            $line .= '<summary=>';
        }
        if ( $_ =~ m[<yt:playlistId>([^<]+)</yt:playlistId>] ) {
            ++$n;
            $line .= "<playlist=$1>";
        }
        else {
            next;
        }
        if ( $_ =~ m[<yt:countHint>(\d+)</yt:countHint>] ) {
            $line .= "<count=$1>";
        }
        else {
            $line .= '<count=0>';
        }
        if ( $_ =~ m[<name>([^<]+)</name>] ) {
            $line .= "<author=$1>";
        }
        else {
            $line .= '<author=Unknown>';
        }
        $line = "<#=$n>" . $line;
        push @list_of_playlists, $line;
    }
    print "\n";
    foreach $_ (@list_of_playlists) {
        if (
            /^<#=(\d+)><title=([^>]*)><summary=([^>]*)>
?<playlist=([^>]+)><count=(\d+)><author=([^>]+)>$/
          ) {
            if ( $1 < 10 ) {
                print ' ';
            }
            print "$cblack$bred$1$reset$cblack - $byellow$2 $3$reset"
              . "$cblack (${bpurle}by $6$reset$cblack) "
              . "($bblue$5$reset$cblack)$reset\n";
        }
    }
    print "\n$bred=>>$reset ${bgreen}Pick one playlist$reset\n> ";
    chomp( $pick = <STDIN> );
    if ( not $pick =~ /^\s*\d+\s*$/ and $pick =~ /^(?:\s*|)$/ ) {
        if ( $url =~ /start-index=(\d+)/ ) {
            $old_index = $1;
            $new_index = $1 + 20;
            if ($MoreResults) {
                $new_index += 30;
            }
            $url =~ s/start-index=\d+/start-index=$new_index/;
            undef @list_of_playlists;
            &search_playlists($url);
        }
    }
    elsif ( $pick =~ /^\D+/ and not $pick =~ /^\s+\d+/ ) {
        $Search = $pick;
        undef @list_of_playlists;
        &search_playlists;
    }
    elsif ( $pick =~ /^\s*(\d+)/ ) {
        $pick = $1;
    }
    foreach $_ (@list_of_playlists) {
        if ( $_ =~ /^<#=$pick>[\w\W]+<playlist=([^>]+)/ ) {
            &list_playlist($1);
        }
    }
}

sub list_playlist {
    if ( $_[0] and $_[0] =~ /^([A-Z0-9]+)$/ ) {
        $yt_api_url = "http://gdata.youtube.com/feeds/api/playlists/$1";
        &YoutubeAPI;
    }
}

sub youtube_tops {
    print "\n";
    $n = 0;
    unless ($all_time) {
        $today = 1;
    }
    $youtube_top_url = 'http://gdata.youtube.com/feeds/api/standardfeeds';
    foreach my $line (
        'top_rated',      'top_favorites',
        'most_viewed',    'most_popular',
        'most_recent',    'most_discussed',
        'most_responded', 'recently_featured'
      ) {
        ++$n;
        my $top_name = ucfirst $line;
        $top_name =~ s/_/ /;
        print "$bred$n$reset - $top_name\n";
        push @tops, "$n - $youtube_top_url/$line";
    }
    print "\n$bred=>>$bgreen Pick one of$reset\n> ";
    chomp( my $pick = quotemeta <STDIN> );
    foreach $_ (@tops) {
        if ( $_ =~ /^$pick - (.+)/ ) {
            $yt_api_url = $1;
            if ($today) {
                unless ( $yt_api_url =~ /recent/ ) {
                    $yt_api_url .= '?time=today';
                }
            }
            &YoutubeAPI;
        }
    }
}

sub categories_area {
    &UserAgent unless $lwp_is_set;
    $connect =
      $lwp->get('http://gdata.youtube.com/schemas/2007/categories.cat');
    @cates = split( /category term=/, $connect->content, 0 );
    $n = 0;
    print "\n";
    foreach my $cat (@cates) {
        if ( $cat =~ /^'([^']+)' label='([^']+)'/ and not $cat =~ /deprecated/ )
        {
            ++$n;
            my $cat_name  = $1;
            my $cat_label = $2;
            $cat_label =~ s/&amp;/&/;
            if ( $n < 10 ) {
                print ' ';
            }
            print "$bred$n$reset - $cat_label\n";
            push @categories, "$n - $cat_name";
        }
    }
    print "\n$bgreen=>> Insert a category number\n>$reset ";
    chomp( $pickcat = quotemeta <STDIN> );
    foreach my $cat (@categories) {
        if ( $cat =~ /^$pickcat - (.+)/ ) {
            $yt_api_url = 'http://gdata.youtube.com/feeds/api/standardfeeds/'
              . "recently_featured_$1";
            &YoutubeAPI;
        }
    }
}

sub MPlayer {
    print "** STREAMING: $streaming\n\n" if $debug;
    if ( $download_video or $tmp_download_video ) {
        $title =~ s[/][|]g;
        if ( not -e "$title.mp4" ) {
            print "** Saving to: '$title.mp4'\n";
            $lwp->show_progress(1);
            $lwp->mirror( $streaming, "$title.mp4" );
            $lwp->show_progress(0);
        }
        else {
            warn "** '$title.mp4' already exists...\n";
        }
        undef $tmp_download_video if $tmp_download_video;
    }
    else {
        print "** MPlayer Line: $MPlayerLine\n\n" if $debug;
        `$MPlayerLine "$streaming"`;
    }
    print "\n";
    if ($Picks) {
        &foreach_pick;
    }
    if ( $playlist or $video_results and not $dont_exit ) {
        &print_results;
    }
    unless ($dont_exit) {
        exit;
    }
}

sub YoutubeAPI {
    undef @Videos;
    if ($MoreResults) {
        $results = 50;
    }
    else {
        $results = 20;
    }
    if ( not $yt_api_url =~ /\?/ ) {
        $yt_api_url .= '?start-index=1';
    }
    else {
        $yt_api_url .= '&start-index=1';
    }
    $yt_api_url .= "&max-results=$results";
    &parse_content($yt_api_url);
    &print_results;
}
unless ( $dont_exit or $playlists ) {
    &search;
}

sub search {
    $PageNumber = 1;
    $FirstPage  = 1;
    $Search =~ s/^\s+|\s+$//g;
    $Search = uri_escape($Search);
    if ($MoreResults) {
        $results = 50;
    }
    else {
        $results = 20;
    }
    $ys = "http://gdata.youtube.com/feeds/api/videos?q=$Search"
      . "&max-results=$results&time=$time_p&orderby=$order_by&start-index=1";
    &parse_content($ys);
    &print_results;
}

sub parse_content {
    &UserAgent unless $lwp_is_set;
    undef @Videos;
    my (@content) = split( /<entry>/, $lwp->get( $_[0] )->content, 0 );
    foreach $_ (@content) {
        if ($debug) {
            print "$_\n\n";
        }
        next unless $_ =~ /^<id>/;
        if ( $_ =~ m[<name>([^<]+)</name>] ) {
            $video_line = "<author=$1>";
        }
        if ( $_ =~ m[v=([\w-]+)&amp;feature=youtube_gdata'/>] ) {
            $video_line .= "<v=$1>";
        }
        if ( $_ =~ m[>([^<]+)</title>] ) {
            $video_line .= "<title=$1>";
        }
        if ( $_ =~ /<media:category label=['"]([^']+)['"]/ ) {
            $category_label = $1;
            $category_label =~ s/&amp;/&/;
            $video_line .= "<category=$category_label>";
        }
        else {
            $video_line .= '<category=None>';
        }
        if ( $_ =~ /<published>([\d-]+)/ ) {
            $video_line .= "<published=$1>";
        }
        else {
            $video_line .= '<published=0>';
        }
        if ( $_ =~ /duration[^']+'(\d+)'/ ) {
            $video_line .= "<time=$1>";
        }
        else {
            $video_line .= '<time=0>';
        }
        if ( $_ =~ /viewCount='(\d+)'/ ) {
            $video_line .= "<views=$1>";
        }
        else {
            $video_line .= '<views=0>';
        }
        if ( $_ =~ /<media:description type='plain'>([^<]+)/ ) {
            $video_line .= "<description=$1>";
        }
        else {
            $video_line .= '<description=No description available...>';
        }
        if ($debug) {
            print "$video_line\n\n";
        }
        push @Videos, $video_line;
    }
}

sub print_results {
    $#codes = -1;
    my $number = 0;
    print "\n";
    exit unless scalar @Videos;
    foreach $line (@Videos) {
        if (
            $line =~ /^<author=([^>]+)><v=([^>]+)><title=([^>]+)>
<category=([^>]+)><published=([^>]+)><time=
([^>]*)><views=([^>]*)><description=([^>]+)>$/x
          ) {
            ++$number;
            my $author      = $1;
            my $code        = $2;
            my $title       = decode_entities($3);
            my $category    = $4;
            my $published   = $5;
            my $time        = format_time($6);
            my $views       = $7;
            my $description = $8;
            push @codes,
                "$number>title=$title>published=$published>"
              . "category=$category>time=$time>code="
              . "$code>views=$views>desc=$description>";
            print "$bred";

            if ( $number < 10 ) {
                unless ($video_results) {
                    $video_results = 1;
                }
                print "$cblack ";
            }
            print "$cblack$bred$number$reset$cblack - $byellow$title$reset"
              . "$cblack (${bpurle}by $author$reset$cblack) "
              . "($bblue$time$reset$cblack)$reset\n";
        }
    }
    if ($playback) {
        for ( $i = 1 ; $i <= $number ; ++$i ) {
            push @picks, $i;
        }
        $playback_mode = 1;
        &picks_area;
    }
    print "\n$bred=>>$reset$bgreen Insert a number or "
      . "search something else\n$reset> ";
    chomp( my $youtube = <STDIN> );
    $PickBackup = $youtube;
    if ( $youtube =~ /^(?:q|quit|exit)$/ ) {
        exit;
    }
    elsif ( $PickBackup =~ m[^http://] and not $PickBackup =~ /youtube\.com/ ) {
        &code_from_content($PickBackup);
    }
    elsif ( $PickBackup =~ /([\d]+) -([\w\s-]+)/ ) {
        $youtube     = $1;
        $stdin_argvs = " -$2";
        @options     = split( m? ?, "-$2", 0 );
        foreach $_ (@options) {
            if ( $_ =~ /^[-]+(?:d|download)$/ ) {
                $tmp_download_video = 1;
                last;
            }
        }
    }
    if ( $youtube =~ /^\s*([\d]+)\s*$/ ) {
        if ( $youtube > $number or not $youtube ) {
            print "\n";
            &print_results;
        }
        else {
            &foreach_code($1);
        }
    }
    elsif ( $youtube =~ /^\s*$/ ) {
        &next_page;
    }
    elsif ( $youtube eq 'all' ) {
        $stdin_argvs .= ' --1080 --play-all';
        undef @picks if $#picks > -1;
        for ( $i = 1 ; $i <= $number ; ++$i ) {
            push @picks, $i;
        }
        &picks_area;
    }
    elsif ( $youtube =~ /view_play_list\?p=([A-Z0-9]+)/ ) {
        &list_playlist($1);
    }
    elsif ( $youtube =~ m[(?:v|embed)[=/]+([\w-]{11})] ) {
        &get_youtube($1);
    }
    elsif ( $youtube =~ /\d+[,\s]+\d+/ ) {
        @picks = split( m?\D?, $youtube, 0 );
        &picks_area;
    }
    else {
        $Search = $youtube;
        &search;
    }
}

sub next_page {
    $PageNumber = $FirstPage;
    ++$PageNumber;
    if ($ys) {
        if ( $ys =~ /index=([\d]+)/ ) {
            $old_index   = $1;
            $start_index = $old_index + $results;
            $ys =~ s/index=$old_index/index=$start_index/;
            &parse_content($ys);
            &print_results;
        }
    }
    elsif ($yt_api_url) {
        undef @Videos;
        $ys = '';
        if ( $yt_api_url =~ /index=([\d]+)/ ) {
            $old_index   = $1;
            $start_index = $old_index + $results;
            $yt_api_url =~ s/index=$old_index/index=$start_index/;
            &parse_content($yt_api_url);
            &print_results;
        }
    }
}

sub picks_area {
    $NrOfPicks = scalar @picks;
    $no        = 0;
    $lastpick  = '';
    &foreach_pick;
}

sub foreach_pick {
    for ( $number = $no ; $number <= $NrOfPicks ; ++$number ) {
        $no   = $number;
        $pick = $picks[$number];
        if ($pick) {
            next if $lastpick eq $pick;
        }
        if ( not $playback_mode ) {
            &print_results if $number eq $NrOfPicks;
        }
        else {
            &next_page if $number eq $NrOfPicks;
        }
        $Picks    = 1;
        $lastpick = $pick;
        &foreach_code($pick);
    }
}

sub foreach_code {
    foreach $line (@codes) {
        if ($debug) {
            print "** FOREACHCODE: $line\n\n";
        }
        if (
            $line =~ /^$_[0]>title=([^>]+)>published=([^>]+)>
category=([^>]+)>time=([^>]+)>code=([\w-]{11})
>views=([\d]*)>desc=([^>]+)>$/x
          ) {
            my $description = decode_entities($7);
            &get_youtube( $5, $1, $4, $6, $3, $2, $description );
        }
    }
}

sub select_resolution {
    $streaming =~ s/^[\w]*%[\w]*http:/http:/;
    if ( not $streaming =~ /itag=34/ and $streaming =~ /itag=([\d]+)/ ) {
        my $itag = $1;
        $streaming =~ s/.*http(.+)itag=$itag([^%]*).+/http$1itag=$itag$2/;
        $streaming =~ s/%.*//;
        unless ( $stdin_argvs =~ / -+f/ ) {
            $MPlayerLine =~ s/-fs //;
        }
        &lower_cache;
        &description;
        &MPlayer;
    }
    elsif ( $stdin_argvs =~ / -+2/ ) {
        &lower_quality(5);
        &description;
        &MPlayer;
    }
    elsif ( $stdin_argvs =~ / -+3/ ) {
        &lower_quality(34);
        &description;
        &MPlayer;
    }
    elsif ( $stdin_argvs =~ / -+4/ ) {
        &lower_quality;
        &description;
        &MPlayer;
    }
    elsif ( $stdin_argvs =~ / -+7/ ) {
        if ( $streaming =~ /itag=22/ ) {
            $streaming =~ s/.*http(.+)itag=22([^%]*).+/http$1itag=22$2/;
            &fullscreen_check;
            &description;
            &MPlayer;
        }
        else {
            &lower_quality;
            &description;
            &MPlayer;
        }
    }
    elsif ( $stdin_argvs =~ / -+1/ ) {
        if ( $streaming =~ /itag=37/ ) {
            $streaming =~ s/.*http(.+)itag=37([^%]*).+/http$1itag=37$2/;
            &fullscreen_check;
            &description;
            &MPlayer;
        }
        elsif ( $streaming =~ /itag=22/ ) {
            $streaming =~ s/.*http(.+)itag=22([^%]*).+/http$1itag=22$2/;
            &fullscreen_check;
            &description;
            &MPlayer;
        }
        else {
            &lower_quality;
            &description;
            &MPlayer;
        }
    }
    else {
        &description;
        &check_resolution;
    }
}

sub format_time {
    my $sec = shift @_ || return (0);
    my $time = $sec / 3600 % 24 . ':' . $sec / 60 % 60 . ':' . $sec % 60;
    $time =~ s/^0://;
    unless ( $time =~ /:/ ) {
        $time = "0:$time";
    }
    if ( $time =~ /(.):(.):(.+)/ ) {
        $time = "$1:0$2:$3";
    }
    if ( $time =~ /^(.+):(.)$/ ) {
        $time = "$1:0$2";
    }
    return $time;
}

sub description {
    my ( $date, $rating );
    if ( $connect->content =~ /rating average='([\d\.]+)'/ ) {
        $rating = $1;
        $rating =~ s/^([\d\.]{4}).*/$1/;
    }
    elsif ( $connect->content =~ /avg_rating=([^&]+)/ ) {
        $rating = $1;
        $rating =~ s/^([\d\.]{4}).*/$1/;
    }
    unless ($title) {
        my $feed_url = 'http://gdata.youtube.com/feeds/api/videos/' . $code;
        my $content  = $lwp->get($feed_url)->content;
        if ( $content =~ m[media:title type='plain'>([^<]+)</media:title>] ) {
            $title = decode_entities($1);
        }
        if ( $content =~ /viewCount='([\d]+)'/ ) {
            $views = $1;
        }
        if ( $content =~ /<published>([\d-]+)/ ) {
            $date = $1;
            $date =~ s/-/./g;
            $date =~ s/(.+)\.(.+)\.(.+)/$3.$2.$1/;
        }
        if ( $content =~ m[<media:description type='plain'>([^<]+)</media] ) {
            $description = decode_entities($1);
        }
        if ( $content =~ /duration[^\d]+(\d+)/ ) {
            $duration = format_time($1);
        }
        if ( $content =~ /category label='([^']+)'/ ) {
            $category = $1;
            $category =~ s/&amp;/&/;
        }
    }
    if ( not $date and $published ) {
        $date = $published;
        $date =~ s/-/./g;
        $date =~ s/(.+)\.(.+)\.(.+)/$3.$2.$1/;
    }
    if ($views) {
        $views = reverse($views);
        $views =~ s/([\d]{3})/$1./g;
        $views = reverse($views);
        $views =~ s/^\.//;
    }
    if ($description) {
        print "\n$bred=>> " . $bgreen . $title . $reset . "\n" . '-' x 80;
        print "\n" . $description . "\n" . '-' x 80 . "\n";
    }
    else {
        print "\n";
    }
    print "$bred=>> ${bgreen}View & Download$reset\n" . '-' x 80;
    my $get = $1 if $streaming =~ m[((http://)[^%]+)];
    print "\n* URL $url\n* GET $get\n" . '-' x 80 . "\n";
    my $count = length $title;
    if ( $count <= 40 ) {
        print "$bred\t\t=>> ";
    }
    elsif ( $count >= 40 and $count <= 55 ) {
        print "$bred\t=>> ";
    }
    elsif ( $count >= 56 ) {
        print "$bred  =>> ";
    }
    print "$bgreen$title$reset$bred <<=\n$reset";
    my $author = $1 if $connect->content =~ /&author=([^&]+)/;
    print "\n** Author    : $author\n" if $author;
    print "** Category  : $category\n" if $category;
    print "** Duration  : $duration\n" if $duration;
    print "** Rating    : $rating\n"   if $rating;
    print "** Views     : $views\n"    if $views;
    print "** Published : $date\n"     if $date;
    print '-' x 80 . "\n\n";
}

sub get_youtube {
    ( $code, $title, $duration, $views, $category, $published, $description ) =
      @_;
    undef @_;
    my $youtube = "http://www.youtube.com/get_video_info?&video_id=$code"
      . '&el=detailpage&ps=default&eurl=&gl=US&hl=en';
    unless ($lwp_is_set) {
        &UserAgent;
    }
    $connect = $lwp->get($youtube);
    $url     = "http://www.youtube.com/watch?v=$code";
    $MPlayerLine =~ s/ $mplayer_srt_settings -sub.*//;
    if ( $ENV{'PATH'} ) {
        @paths = split( m?:?, $ENV{'PATH'}, 0 );
        foreach my $path (@paths) {
            if ( -e "$path/gcap" ) {
                $gcap = "$path/gcap";
                last;
            }
        }
    }
    else {
        $gcap = '/usr/bin/gcap';
    }
    if (    -e $gcap
        and not $MPlayerLine  =~ / -novideo/
        and $connect->content =~ /&has_cc=True&/
        and not $download_video
        and not $tmp_download_video ) {
        chdir '/tmp/';
        print "\n";
        system "gcap $url" unless -e "${code}_$default_sub.srt";
        my (@srt_files) = glob('*.srt');
        undef $srt_file if $srt_file;
        foreach $line (@srt_files) {
            if ( $line =~ /${code}_$default_sub\.srt/ ) {
                $srt_file = "${code}_$default_sub.srt";
                $MPlayerLine .= " $mplayer_srt_settings -sub $srt_file";
            }
        }
        unless ($srt_file) {
            foreach $line (@srt_files) {
                if ( $line =~ /$code([\w]*)\.srt/ ) {
                    $srt_file = "$code$1.srt";
                    $MPlayerLine .= " $mplayer_srt_settings -sub $srt_file";
                }
            }
        }
    }
    print "\n\n" . uri_unescape( $connect->content ) . "\n\n" if $debug;
    if ( $connect->content =~ /fmt_url_map=([^&]+)&/ ) {
        $streaming = $1;
        $streaming =~ s/%3A/:/gi;
        $streaming =~ s[%2F][/]gi;
        $streaming =~ s/%26/&/g;
        $streaming =~ s/%3D/=/gi;
        $streaming =~ s/%3F/?/gi;
        $streaming =~ s/%252C/,/gi;
        &select_resolution;
    }
    else {
        warn "\n$bred(x_x) Something went wrong...$reset\n\n";
        warn "$bred(x_x) Unable to stream: $reset$url\n\n";
        if ( $video_results and not $dont_exit ) {
            unless ( $stdin_argvs =~ / -+(?:all|A|play-all)/ or $NrOfPicks ) {
                sleep 1;
                &print_results;
            }
        }
        else {
            unless ( $video_results or $dont_exit ) {
                exit;
            }
        }
    }
}

sub check_resolution {
    if ( $streaming =~ /itag=37/ and not $stdin_argvs =~ / -+(?:all|A)/ ) {
        &pick;
    }
    elsif ( $stdin_argvs =~ / -+(?:all|A)/ ) {
        if ( $streaming =~ /itag=37/ ) {
            $streaming =~ s/.*http(.+)itag=37([^%]*).+/http$1itag=37$2/;
            &default_cache;
            &fullscreen_check;
            &description;
            &MPlayer;
        }
    }
    elsif ( $streaming =~ /itag=22/ ) {
        $streaming =~ s/.*http(.+)itag=22([^%]*).+/http$1itag=22$2/;
        &default_cache;
        &fullscreen_check;
        &MPlayer;
    }
    else {
        &lower_quality;
        &MPlayer;
    }
}

sub fullscreen_check {
    $MPlayerLine =~ s/mplayer -p/mplayer -fs -p/;
    $MPlayerLine =~ s/mplayer.exe" -p/mplayer.exe" -fs -p/;
}

sub pick {
    print "$bred=>>$reset $bgreen Please choose "
      . 'the quality of video (default: 1)';
    print "\n$reset";
    print "\n  $bred 1$reset - 1280x720  (720p)\n"
      . "  $bred 2$reset - 1920x1080 (1080p)\n  ";
    print '=' x 23 . "\n";
    print "\n$bgreen=>> Pick format:$reset ";
    chomp( my $pick = <STDIN> );
    print '-' x 80 . "\n\n";
    if ( $pick eq 2 ) {
        $streaming =~ s/.*http(.+)itag=37([^%]*).+/http$1itag=37$2/;
        &default_cache;
        &fullscreen_check;
        &MPlayer;
    }
    else {
        $streaming =~ s/.*http(.+)itag=22([^%]*).+/http$1itag=22$2/;
        &default_cache;
        &fullscreen_check;
        &MPlayer;
    }
}

sub lower_quality {
    if ( $_[0] and $_[0] =~ /^\d+$/ ) {
        if ( $streaming =~ /itag=$_[0]/ ) {
            $streaming =~ s/.*http(.+)itag=$_[0]([^%]*).*/http$1itag=$_[0]$2/;
            &lower_cache;
        }
    }
    else {
        foreach $_ ( 35, 34 ) {
            if ( $streaming =~ /itag=$_/ ) {
                $streaming =~ s/.*http(.+)itag=$_([^%]*).*/http$1itag=$_$2/;
                &lower_cache;
                last;
            }
        }
    }
    unless ( $stdin_argvs =~ / -+f/ ) {
        $MPlayerLine =~ s/-fs //;
    }
}

sub lower_cache {
    $MPlayerLine =~ s/-cache\s*\d+/-cache 1000/      unless $user_cache;
    $MPlayerLine =~ s/-cache-min\s*\d+/-cache-min 3/ unless $user_cache_min;
}

sub default_cache {
    if ( not $user_lower_cache ) {
        $MPlayerLine =~ s/-cache\s*\d+/-cache $cache/ unless $user_cache;
        $MPlayerLine =~ s/-cache-min\s*\d+/-cache-min $cache_min/
          unless $user_cache_min;
    }
    else {
        &lower_cache;
    }
}

            
Comments
Sorry but there are no comments to display