Welcome to HBH! If you have tried to register and didn't get a verification email, please using the following link to resend the verification email.

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