diff -Nru youtube-viewer-3.2.0/bin/gtk-youtube-viewer youtube-viewer-3.2.4/bin/gtk-youtube-viewer --- youtube-viewer-3.2.0/bin/gtk-youtube-viewer 2015-12-18 02:45:32.000000000 +0000 +++ youtube-viewer-3.2.4/bin/gtk-youtube-viewer 2016-09-04 15:06:02.000000000 +0000 @@ -1,24 +1,21 @@ #!/usr/bin/perl -# Copyright (C) 2010-2015 Trizen . +# Copyright (C) 2010-2016 Trizen . # -# 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 free software; you can redistribute it and/or modify it +# under the terms of either: the GNU General Public License as published +# by the Free Software Foundation; or the Artistic License. # # 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. +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. # -# You should have received a copy of the GNU General Public License -# along with this program. If not, see . +# See http://dev.perl.org/licenses/ for more information. # #------------------------------------------------------- # GTK Youtube Viewer # Created on: 12 September 2010 -# Latest edit on: 01 October 2015 +# Latest edit on: 27 July 2016 # Website: http://github.com/trizen/youtube-viewer #------------------------------------------------------- @@ -33,6 +30,9 @@ no if $] >= 5.018, warnings => 'experimental::smartmatch'; +use WWW::YoutubeViewer v3.2.4; +use WWW::YoutubeViewer::RegularExpressions; + use Gtk2 qw(-init); use File::ShareDir qw(dist_dir); use File::Spec::Functions qw( @@ -49,7 +49,7 @@ binmode(STDOUT, ':utf8'); my $appname = 'GTK Youtube Viewer'; -my $version = '3.2.0'; +my $version = $WWW::YoutubeViewer::VERSION; my $execname = 'gtk-youtube-viewer'; # Share directory @@ -62,8 +62,29 @@ my $key = 'aXalQYmzI8gPkMSLyMhpApfMAiU2b23Qz2nE3mq'; # Configuration dir/file -my $xdg_config_home = $ENV{XDG_CONFIG_HOME} - || catdir((my $home_dir = $ENV{HOME} || $ENV{LOGDIR} || (getpwuid($<))[7] || `echo -n ~`), '.config'); +my $home_dir; +my $xdg_config_home = $ENV{XDG_CONFIG_HOME}; + +if ($xdg_config_home and -d -w $xdg_config_home) { + require File::Basename; + $home_dir = File::Basename::dirname($xdg_config_home); + + if (not -d -w $home_dir) { + $home_dir = curdir(); + } +} +else { + $home_dir = + $ENV{HOME} + || $ENV{LOGDIR} + || ($^O eq 'MSWin32' ? '\Local Settings\Application Data' : ((getpwuid($<))[7] || `echo -n ~`)); + + if (not -d -w $home_dir) { + $home_dir = curdir(); + } + + $xdg_config_home = catdir($home_dir, '.config'); +} # Configuration dir/file my $config_dir = catdir($xdg_config_home, 'youtube-viewer'); @@ -101,6 +122,9 @@ } ## end of compatibility +# Video queue for the enqueue feature +my @VIDEO_QUEUE; + sub which_command { my ($cmd) = @_; @@ -155,13 +179,20 @@ srt => q{--sub-file *SUB*}, audio => q{--audio-file *AUDIO*}, fs => q{--fullscreen}, - arg => q{--really-quiet --title *TITLE*}, + arg => q{--really-quiet --title *TITLE* --no-ytdl}, }, + mplayer => { + cmd => q{mplayer}, + srt => q{-sub *SUB*}, + audio => q{-audiofile *AUDIO*}, + fs => q{-fs}, + arg => q{-prefer-ipv4 -really-quiet -title *TITLE*}, + }, smplayer => { - cmd => "smplayer", - fs => "-fullscreen", - srt => "-sub *SUB*", - arg => "-close-at-end -media-title *TITLE* *URL*", + cmd => q{smplayer}, + srt => q{-sub *SUB*}, + fs => q{-fullscreen}, + arg => q{-close-at-end -media-title *TITLE* *URL*}, }, }, video_player_selected => undef, # autodetect it later @@ -206,6 +237,7 @@ http_proxy => undef, debug => 0, fullscreen => 0, + audio_only => 0, use_threads => 0, use_threads_for_thumbs => 0, # this is unstable @@ -217,6 +249,7 @@ terminal => undef, # autodetect it later terminal_exec => q{-e '%s'}, youtube_viewer => undef, + youtube_viewer_args => [], youtube_users_file => $youtube_users_file, history => 1, history_limit => 10_000, @@ -316,10 +349,14 @@ 'spinbutton3' => \my $spin_published_within, 'thumbs_checkbutton' => \my $thumbs_checkbutton, 'fullscreen_checkbutton' => \my $fullscreen_checkbutton, - 'clear_list_checkbutton' => \my $clear_search_list_checkbox, + 'clear_list_checkbutton' => \my $clear_list_checkbutton, 'dash_checkbutton' => \my $dash_checkbutton, + 'audio_only_checkbutton' => \my $audio_only_checkbutton, 'gif_spinner' => \my $gif_spinner, 'hbox2' => \my $hbox2, + 'feeds_title' => \my $feeds_title, + 'channel_name_save' => \my $save_channel_name_entry, + 'channel_id_save' => \my $save_channel_id_entry, ); while (my ($key, $value) = each %objects) { @@ -388,9 +425,6 @@ $mainw->set_title("$appname $version"); $mainw->set_icon($app_icon_pixbuf); -# Regular expressions -use WWW::YoutubeViewer::RegularExpressions; - our $CONFIG; require $config_file; # Load the configuration file @@ -415,12 +449,12 @@ if (not defined $CONFIG{cache_dir}) { my $cache_dir = - (defined($ENV{XDG_CACHE_HOME}) and -w $ENV{XDG_CACHE_HOME}) + ($ENV{XDG_CACHE_HOME} and -d -w $ENV{XDG_CACHE_HOME}) ? $ENV{XDG_CACHE_HOME} : catdir($home_dir, '.cache'); - if (not -w $cache_dir) { - $cache_dir = '.cache'; + if (not -d -w $cache_dir) { + $cache_dir = catdir(curdir(), '.cache'); } $CONFIG{cache_dir} = catdir($cache_dir, 'youtube-viewer'); @@ -435,7 +469,7 @@ { my $split_string = sub { - ((map { s/^[[:punct:]]+//r =~ s/[[:punct:]]+\z//r } split(' ', $_[0])), split(/\W+/, $_[0])); + grep { $_ ne '' } split(/\W+/, lc($_[0])); }; my %history_dict; @@ -447,7 +481,7 @@ my $str_ref = \$str; # Create models from each word of the string - foreach my $word ($split_string->(lc($str))) { + foreach my $word ($split_string->($str)) { my $ref = \%history_dict; foreach my $char (split(//, $word)) { $ref = $ref->{$char} //= {}; @@ -463,12 +497,11 @@ my ($buffer) = @_; $completion // return; - my $text = lc($buffer->get_text); - - my (@matches, @words); - foreach my $word ($split_string->($text)) { + my $text = $buffer->get_text; + my @tokens = $split_string->($text); - next if $word eq ''; + my (@words, @matches, %analyzed); + foreach my $word (@tokens) { my $ref = \%history_dict; foreach my $char (split(//, $word)) { @@ -482,8 +515,13 @@ } if (defined $ref and exists $ref->{values}) { - push @words, $word; - push @matches, @{$ref->{values}}; + push @words, $word; + foreach my $match (@{$ref->{values}}) { + if (not exists $analyzed{$match}) { + undef $analyzed{$match}; + unshift @matches, $$match; + } + } } else { @matches = (); # don't include partial matches @@ -491,13 +529,10 @@ } } - state $x = require List::Util; - @matches = grep { - my $lc_str = lc(${$_}); - not defined(List::Util::first(sub { index($lc_str, $_) == -1 }, @words)); - } @matches; + foreach my $token (@tokens) { + @matches = grep { index(lc($_), $token) != -1 } @matches; + } - my %seen; my $store = Gtk2::ListStore->new('Glib::String'); my $i = 0; @@ -505,16 +540,63 @@ map { $_->[0] } sort { $b->[1] <=> $a->[1] } map { - my $lc_str = lc(${$_}); - [${$_}, + my @parts = $split_string->($_); + + my $end_w = $#words; + my $end_p = $#parts; + + my $min_end = $end_w < $end_p ? $end_w : $end_p; + + my $order_score = 0; + for (my $i = 0 ; $i <= $min_end ; ++$i) { + my $word = $words[$i]; + + for (my $j = $i ; $j <= $end_p ; ++$j) { + my $part = $parts[$j]; + + my $matched; + my $continue = 1; + while ($part eq $word) { + $order_score += 1 - 1 / (length($word) + 1)**2; + $matched ||= 1; + $part = $parts[++$j] // do { $continue = 0; last }; + $word = $words[++$i] // do { $continue = 0; last }; + } + + if ($matched) { + $order_score += 1 - 1 / (length($word) + 1) + if ($continue and index($part, $word) == 0); + last; + } + elsif (index($part, $word) == 0) { + $order_score += length($word) / length($part); + last; + } + } + } + + my $prefix_score = 0; + foreach my $i (0 .. $min_end) { + ( + ($parts[$i] eq $words[$i]) + ? do { + $prefix_score += 1; + 1; + } + : (index($parts[$i], $words[$i]) == 0) ? do { + $prefix_score += length($words[$i]) / length($parts[$i]); + 0; + } + : 0 + ) + || last; + } + + ## printf("score('@parts', '@words') = %.4g + %.4g = %.4g\n", + ## $order_score, $prefix_score, $order_score + $prefix_score); - ( # Calculate a score for each match - ((($lc_str =~ s/\W+//gr) ^ ($text =~ s/\W+//gr)) =~ /^[\0]+/ ? $+[0]**2 : 0) + - scalar(grep { $lc_str =~ /\b\Q$_\E\b/ } @words)**2 + - scalar(grep { $lc_str =~ /\b\Q$_\E/ } @words) - ) - ] - } grep { !$seen{$_}++ } @matches + [$_, $order_score + $prefix_score] + } @matches ) { $store->set($store->append, 0, $str); last if ++$i == $CONFIG{entry_completion_limit}; @@ -634,7 +716,6 @@ # Locate youtube-viewer $CONFIG{youtube_viewer} //= which_command('youtube-viewer') // 'youtube-viewer'; -require WWW::YoutubeViewer; my $yv_obj = WWW::YoutubeViewer->new( escape_utf8 => 1, key => $key, @@ -679,10 +760,13 @@ # Fullscreen mode $fullscreen_checkbutton->set_active($CONFIG{fullscreen}); + # Audio-only mode + $audio_only_checkbutton->set_active($CONFIG{audio_only}); + # DASH mode $dash_checkbutton->set_active($CONFIG{dash_support}); - $clear_search_list_checkbox->set_active($CONFIG{clear_search_list}); + $clear_list_checkbutton->set_active($CONFIG{clear_search_list}); $panel_account_type_combobox->set_active($CONFIG{active_panel_account_combobox}); $channel_type_combobox->set_active($CONFIG{active_channel_type_combobox}); $subscriptions_order_combobox->set_active($CONFIG{active_subscriptions_order_combobox}); @@ -758,19 +842,10 @@ apply_configuration(); # YouTube usernames -my %users_table = map { lc($_) => $_ } ( - 'KhanAcademy', 'VSauce', 'Gotbletu', 'ScienceChannel', - 'SpaceRip', 'TEDtalksDirector', 'MIT', 'SixtySymbols', - 'SciShow', 'NumberPhile', 'ComputerPhile', 'UCBerkeley', - 'UCTelevision', 'BigThink', 'ProfessorFink', 'UCTVSeminars', - '1Veritasium', 'MinutePhysics', 'BrianTWill', 'SingingBanana', - 'TheRoyalInstitution', 'ItsOkayToBeSmart', 'CrashCourse', 'MyCodeSchool' - ); set_usernames(); sub donate { - my $url = 'https://www.paypal.com/cgi-bin/webscr?cmd=_s-xclick&hosted_button_id=75FUVBE6Q73T8'; - system "xdg-open \Q$url\E &"; + open_external_url('https://www.paypal.com/cgi-bin/webscr?cmd=_s-xclick&hosted_button_id=75FUVBE6Q73T8'); } # ---------------- Threads ---------------- # @@ -786,8 +861,8 @@ require Thread::Queue; no warnings 'redefine'; - state $lwp_get = \&{WWW::YoutubeViewer::lwp_get}; - *{WWW::YoutubeViewer::lwp_get} = \&threads_lwp_get; + state $lwp_get = \&WWW::YoutubeViewer::lwp_get; + *WWW::YoutubeViewer::lwp_get = \&threads_lwp_get; $queue = 'Thread::Queue'->new; $jobs = 'Thread::Queue'->new; @@ -845,13 +920,13 @@ my $object_buffer = $object->get_buffer; my $start_iter = $object_buffer->get_start_iter; my $end_iter = $object_buffer->get_end_iter; - return $object_buffer->get_text($start_iter, $end_iter, undef); + $object_buffer->get_text($start_iter, $end_iter, undef); } sub new_image_from_pixbuf { my ($object_name, $pixbuf) = @_; my $object = $gui->get_object($object_name) // return; - return scalar($object->new_from_pixbuf($pixbuf)); + scalar($object->new_from_pixbuf($pixbuf)); } # Setting application icons @@ -859,7 +934,6 @@ $gui->get_object('username_list')->set_image(new_image_from_pixbuf('icon_from_pixbuf', $user_icon_pixbuf)); $gui->get_object('uploads_button')->set_image(new_image_from_pixbuf('icon_from_pixbuf', $user_icon_pixbuf)); $gui->get_object('button6')->set_image(new_image_from_pixbuf('icon_from_pixbuf', $feed_icon_pixbuf)); - $gui->get_object('button23')->set_image(new_image_from_pixbuf('icon_from_pixbuf', $feed_icon_pixbuf)); } # Treeview signals @@ -872,12 +946,329 @@ sub menu_popup { my ($treeview, $event) = @_; - #return 0 unless $treeview->get_selection->get_selected(); - + # Ignore non-right-clicks if ($event->button != 3) { return 0; } - my $menu = $gui->get_object('detailsmenu'); + + ##my ($path, $col, $cell_x, $cell_y) = ...; + my $path = ($treeview->get_path_at_pos($event->x, $event->y))[0] // return 0; + + my $selection = $treeview->get_selection; + $selection->select_path($path); + + my $iter = $selection->get_selected() // return 0; + my $type = $liststore->get($iter, 7); + + # Ignore the right-click on 'next-page' entry + $type eq 'next_page' and return 0; + + # Create the main right-click menu + my $menu = 'Gtk2::Menu'->new; + + # Video menu + if ($type eq 'video') { + + my $video_id = $liststore->get($iter, 3); + + # More details + { + my $item = 'Gtk2::ImageMenuItem'->new("Show more details"); + $item->set_image('Gtk2::Image'->new_from_icon_name("window-new", q{menu})); + $item->signal_connect(activate => \&show_details_window); + $item->show; + $menu->append($item); + } + + # Youtube comments + { + my $item = 'Gtk2::ImageMenuItem'->new("YouTube comments"); + $item->set_image('Gtk2::Image'->new_from_icon_name("edit-copy", q{menu})); + $item->signal_connect(activate => \&show_feeds_window); + $item->show; + $menu->append($item); + } + + # Separator + { + my $item = 'Gtk2::SeparatorMenuItem'->new; + $item->show; + $menu->append($item); + } + + # Video submenu + { + my $video = 'Gtk2::Menu'->new; + my $cat = 'Gtk2::ImageMenuItem'->new("Video"); + $cat->set_image('Gtk2::Image'->new_from_icon_name("video-x-generic", q{menu})); + $cat->show; + + # Play + { + my $item = 'Gtk2::ImageMenuItem'->new("Play"); + $item->signal_connect(activate => \&get_code); + $item->set_property(tooltip_text => "Play the video"); + $item->set_image('Gtk2::Image'->new_from_icon_name("media-playback-start", q{menu})); + $item->show; + $video->append($item); + } + + # Enqueue + { + my $item = 'Gtk2::ImageMenuItem'->new("Enqueue"); + $item->signal_connect(activate => sub { enqueue_video($video_id) }); + $item->set_property(tooltip_text => "Enqueue video to play it later"); + $item->set_image('Gtk2::Image'->new_from_icon_name("list-add", q{menu})); + $item->show; + $video->append($item); + } + + # Favorite + { + my $item = 'Gtk2::ImageMenuItem'->new("Favorite"); + $item->set_property(tooltip_text => "Save the video to favorites"); + $item->signal_connect( + activate => sub { + $yv_obj->favorite_video($video_id) + or warn "Failed to favorite the video <$video_id>: $!"; + } + ); + $item->set_image('Gtk2::Image'->new_from_icon_name("emblem-favorite", q{menu})); + $item->show; + $video->append($item); + } + + # Download + { + my $item = 'Gtk2::ImageMenuItem'->new("Download"); + $item->set_property(tooltip_text => "Download the video"); + $item->signal_connect(activate => \&download_video); + $item->set_image('Gtk2::Image'->new_from_icon_name("emblem-downloads", q{menu})); + $item->show; + $video->append($item); + } + + # Separator + { + my $item = 'Gtk2::SeparatorMenuItem'->new; + $item->show; + $video->append($item); + } + + # Like + { + my $item = 'Gtk2::ImageMenuItem'->new("Like"); + $item->set_property(tooltip_text => "Send a positive rating"); + $item->signal_connect( + activate => sub { + $yv_obj->send_rating_to_video($video_id, 'like') + or warn "Failed to send a positive rating to <$video_id>: $!"; + } + ); + $item->set_image('Gtk2::Image'->new_from_icon_name("go-up", q{menu})); + $item->show; + $video->append($item); + } + + # Disike + { + my $item = 'Gtk2::ImageMenuItem'->new("Dislike"); + $item->set_property(tooltip_text => "Send a negative rating"); + $item->signal_connect( + activate => sub { + $yv_obj->send_rating_to_video($video_id, 'dislike') + or warn "Failed to send a negative rating to <$video_id>: $!"; + } + ); + $item->set_image('Gtk2::Image'->new_from_icon_name("go-down", q{menu})); + $item->show; + $video->append($item); + } + + # Separator + { + my $item = 'Gtk2::SeparatorMenuItem'->new; + $item->show; + $video->append($item); + } + + # Related videos + { + my $item = 'Gtk2::ImageMenuItem'->new("Related videos"); + $item->set_property(tooltip_text => "Display videos that are related to this video"); + $item->signal_connect(activate => \&show_related_videos); + $item->set_image('Gtk2::Image'->new_from_icon_name("video-x-generic", q{menu})); + $item->show; + $video->append($item); + } + + # Open the YouTube video page + { + my $item = 'Gtk2::ImageMenuItem'->new("YouTube page"); + $item->signal_connect(activate => sub { open_external_url(make_youtube_url('video', $video_id)) }); + $item->set_property(tooltip_text => "Open the YouTube page of this video"); + $item->set_image('Gtk2::Image'->new_from_icon_name("applications-internet", q{menu})); + $item->show; + $video->append($item); + } + + $cat->set_submenu($video); + $menu->append($cat); + } + } + elsif ($type eq 'playlist') { + + my $playlist_id = $liststore->get($iter, 3); + + # More details + { + my $item = 'Gtk2::ImageMenuItem'->new("Videos"); + $item->set_property(tooltip_text => "Display the videos from this playlist"); + $item->signal_connect(activate => sub { list_playlist($playlist_id) }); + $item->set_image('Gtk2::Image'->new_from_icon_name("folder-open", q{menu})); + $item->show; + $menu->append($item); + } + + # Separator + { + my $item = 'Gtk2::SeparatorMenuItem'->new; + $item->show; + $menu->append($item); + } + } + + my $channel_id = $liststore->get($iter, 6); + + # Author submenu + { + my $author = 'Gtk2::Menu'->new; + my $cat = 'Gtk2::ImageMenuItem'->new("Author"); + $cat->set_image('Gtk2::Image'->new_from_pixbuf($user_icon_pixbuf)); + $cat->show; + + # More videos from this author + { + my $item = 'Gtk2::ImageMenuItem'->new("Uploads"); + $item->signal_connect(activate => sub { uploads('channel', $channel_id) }); + $item->set_property(tooltip_text => "Show more videos from this author"); + $item->set_image('Gtk2::Image'->new_from_icon_name("emblem-shared", q{menu})); + $item->show; + $author->append($item); + } + + # Favorites of this author + { + my $item = 'Gtk2::ImageMenuItem'->new("Favorites"); + $item->signal_connect(activate => sub { favorites('channel', $channel_id) }); + $item->set_property(tooltip_text => "Show favorite videos of this author"); + $item->set_image('Gtk2::Image'->new_from_icon_name("emblem-favorite", q{menu})); + $item->show; + $author->append($item); + } + + # Playlists created by this author + { + my $item = 'Gtk2::ImageMenuItem'->new("Playlists"); + $item->signal_connect(activate => \&show_playlists_from_selected_author); + $item->set_property(tooltip_text => "Show playlists created by this author"); + $item->set_image('Gtk2::Image'->new_from_icon_name("emblem-documents", q{menu})); + $item->show; + $author->append($item); + } + + # Liked videos by this author + { + my $item = 'Gtk2::ImageMenuItem'->new("Likes"); + $item->signal_connect(activate => sub { likes('channel', $channel_id) }); + $item->set_property(tooltip_text => "Show liked videos by this author"); + $item->set_image('Gtk2::Image'->new_from_icon_name("emblem-default", q{menu})); + $item->show; + $author->append($item); + } + + # Separator + { + my $item = 'Gtk2::SeparatorMenuItem'->new; + $item->show; + $author->append($item); + } + + # Subscribe to channel + { + my $item = 'Gtk2::ImageMenuItem'->new("Subscribe"); + $item->signal_connect( + activate => sub { + $yv_obj->subscribe_channel($channel_id) + or warn "Failed to subscribe to channel <$channel_id>: $!"; + } + ); + $item->set_property(tooltip_text => "Subscribe to this channel"); + $item->set_image('Gtk2::Image'->new_from_pixbuf($feed_icon_pixbuf)); + $item->show; + $author->append($item); + } + + # Open the YouTube channel page + { + my $item = 'Gtk2::ImageMenuItem'->new("YouTube page"); + $item->signal_connect(activate => sub { open_external_url(make_youtube_url('channel', $channel_id)) }); + $item->set_property(tooltip_text => "Open the YouTube page of this channel"); + $item->set_image('Gtk2::Image'->new_from_icon_name("applications-internet", q{menu})); + $item->show; + $author->append($item); + } + + if ($type eq 'video' or $type eq 'playlist') { + $cat->set_submenu($author); + $menu->append($cat); + } + else { + $menu = $author; + } + } + + if (@VIDEO_QUEUE) { + + # Separator + { + my $item = 'Gtk2::SeparatorMenuItem'->new; + $item->show; + $menu->append($item); + } + + # Play enqueued videos + { + my $item = 'Gtk2::ImageMenuItem'->new("Play enqueued videos"); + $item->signal_connect(activate => \&play_enqueued_videos); + $item->set_property(tooltip_text => "Play the enqueued videos (if any)"); + $item->set_image('Gtk2::Image'->new_from_icon_name("media-playback-start", q{menu})); + $item->show; + $menu->append($item); + } + } + + if ($type eq 'video' or $type eq 'playlist') { + + # Separator + { + my $item = 'Gtk2::SeparatorMenuItem'->new; + $item->show; + $menu->append($item); + } + + # Play with CLI youtube-viewer + { + my $item = 'Gtk2::ImageMenuItem'->new("Play in terminal"); + $item->signal_connect(activate => \&play_selected_video_with_cli_youtube_viewer); + $item->set_property(tooltip_text => "Play with youtube-viewer in a new terminal"); + $item->set_image('Gtk2::Image'->new_from_icon_name("computer", q{menu})); + $item->show; + $menu->append($item); + } + + } + $menu->popup(undef, undef, undef, undef, $event->button, $event->time); return 0; } @@ -918,18 +1309,18 @@ CTRL+H : help window CTRL+L : login window CTRL+P : preferences window -CTRL+U : username list window -CTRL+Y : CLI youtube viewer -CTRL+D : video details window -CTRL+F : show feeds window +CTRL+Y : start CLI youtube viewer +CTRL+U : show the saved user-list +CTRL+D : show more video details for a selected video +CTRL+C : show the comments for a selected video CTRL+W : show the warnings window CTRL+G : show videos favorited by the author of a selected video CTRL+R : show related videos for a selected video CTRL+M : show videos from the author of a selected video CTRL+K : show playlists from the author of a selected video -CTRL+S : add the author name of a selected video into the users list +CTRL+S : add the author of a selected video to the user-list CTRL+Q : close the application -DEL : remove the selected video from the list +DEL : remove the selected entry from the list F11 : minimize-maximize the main window -Preferences window @@ -968,12 +1359,12 @@ $accel->connect(ord('u'), ['control-mask'], ['visible'], \&show_users_list_window); $accel->connect(ord('y'), ['control-mask'], ['visible'], \&run_cli_youtube_viewer); $accel->connect(ord('d'), ['control-mask'], ['visible'], \&show_details_window); -$accel->connect(ord('f'), ['control-mask'], ['visible'], \&show_feeds_window); +$accel->connect(ord('c'), ['control-mask'], ['visible'], \&show_feeds_window); $accel->connect(ord('s'), ['control-mask'], ['visible'], \&add_user_to_favorites); $accel->connect(ord('r'), ['control-mask'], ['visible'], \&show_related_videos); -$accel->connect(ord('g'), ['control-mask'], ['visible'], \&get_user_favorited_videos); -$accel->connect(ord('m'), ['control-mask'], ['visible'], \&show_more_videos_from_username); -$accel->connect(ord('k'), ['control-mask'], ['visible'], \&show_playlists_from_username); +$accel->connect(ord('g'), ['control-mask'], ['visible'], \&show_user_favorited_videos); +$accel->connect(ord('m'), ['control-mask'], ['visible'], \&show_videos_from_selected_author); +$accel->connect(ord('k'), ['control-mask'], ['visible'], \&show_playlists_from_selected_author); $accel->connect(ord('w'), ['control-mask'], ['visible'], \&show_warnings_window); $accel->connect(0xffff, ['lock-mask'], ['visible'], \&delete_selected_row); $accel->connect(0xffc8, ['lock-mask'], ['visible'], \&maximize_unmaximize_mainw); @@ -1127,8 +1518,6 @@ sub show_details_window { my ($code, $iter) = get_selected_entry_code(); $code // return; - - #return unless $code =~ /$valid_video_id_re/; $details_window->show; set_entry_details($code, $iter); return 1; @@ -1140,19 +1529,20 @@ } sub set_comments { - my $videoID = get_selected_entry_code() // return; - - return unless $videoID =~ /$valid_video_id_re/; - + my $videoID = get_selected_entry_code(type => 'video') // return; $feeds_liststore->clear; display_comments($yv_obj->comments_from_video_id($videoID)); } # Feeds window sub show_feeds_window { - my $videoID = get_selected_entry_code() // return; + my ($videoID, $iter) = get_selected_entry_code(type => 'video'); + $videoID // return; + + my $info = $liststore->get($iter, 0); + my ($video_title) = $info =~ m{^(.*?)}s; - return unless $videoID =~ /$valid_video_id_re/; + $feeds_title->set_markup("$video_title"); $feeds_window->show; $feeds_statusbar->pop(0); @@ -1276,19 +1666,26 @@ $yv_obj->set_maxResults($CONFIG{maxResults} = $spin_results->get_value); } +# Page number sub spin_start_with_page_changed { $yv_obj->set_page($spin_start_with_page->get_value); } +# Clear search list sub toggled_clear_search_list { - $CONFIG{clear_search_list} = $clear_search_list_checkbox->get_active() || 0; + $CONFIG{clear_search_list} = $clear_list_checkbutton->get_active() || 0; } # Fullscreen mode -sub toggled_mplayer_fullscreen { +sub toggled_fullscreen { $CONFIG{fullscreen} = $fullscreen_checkbutton->get_active() || 0; } +# Audio-only mode +sub toggled_audio_only { + $CONFIG{audio_only} = $audio_only_checkbutton->get_active() || 0; +} + # DASH mode sub toggled_dash_support { $CONFIG{dash_support} = $dash_checkbutton->get_active() || 0; @@ -1400,51 +1797,174 @@ #add_top_row($name, $type); } -# ------------ Usernames list window ------------ # -sub set_usernames { - if (-e $CONFIG{youtube_users_file}) { - if (open my $fh, '<', $CONFIG{youtube_users_file}) { - while (defined(my $user = <$fh>)) { - chomp $user; - $users_table{lc $user} = $user; +{ + my %channels; + + # ------------ Usernames list window ------------ # + sub set_usernames { + if (-e $CONFIG{youtube_users_file}) { + if (open my $fh, '<:utf8', $CONFIG{youtube_users_file}) { + while (defined(my $entry = <$fh>)) { + + $entry = unpack('A*', $entry); + my ($channel, $label) = split(' ', $entry, 2); + + if (defined($channel) and $channel =~ /$valid_channel_id_re/) { + if (defined($label) and $label =~ /\S/) { + $channels{$channel} = $label; + } + else { + $channels{$channel} = undef; + } + } + } + close $fh; + } + } + else { + # Default channels + %channels = ( + map { $_ => undef } ( + 'KhanAcademy', 'VSauce', 'Gotbletu', 'ScienceChannel', + 'SpaceRip', 'TEDtalksDirector', 'MIT', 'SixtySymbols', + 'SciShow', 'NumberPhile', 'ComputerPhile', 'UCBerkeley', + 'UCTelevision', 'BigThink', 'ProfessorFink', 'UCTVSeminars', + '1Veritasium', 'MinutePhysics', 'BrianTWill', 'SingingBanana', + 'TheRoyalInstitution', 'ItsOkayToBeSmart', 'CrashCourse', 'MyCodeSchool' + ) + ); + } + + foreach my $channel (sort { ($channels{$a} // lc($a)) cmp($channels{$b} // lc($b)) } keys %channels) { + my $iter = $users_liststore->append; + + if (defined $channels{$channel}) { + $users_liststore->set($iter, 0, $channel); + $users_liststore->set($iter, 1, $channels{$channel}); + $users_liststore->set($iter, 2, 'channel'); + } + else { + $users_liststore->set($iter, 0, $channel); + $users_liststore->set($iter, 1, $channel); + $users_liststore->set($iter, 2, 'username'); + } + + $users_liststore->set($iter, 3, $user_icon_pixbuf); + } + } + + sub save_channel { + my $channel_name = $save_channel_name_entry->get_text; + my $channel_id = $save_channel_id_entry->get_text; + + # Validate the channel id + if (defined($channel_id) and $channel_id =~ /$valid_channel_id_re/) { + + # Get the channel name when empty + if (not defined($channel_name) or not $channel_name =~ /\S/) { + $channel_name = $yv_obj->channel_title_from_id($channel_id) // die "Invalid channel ID: <<$channel_id>>"; + } + } + elsif (defined($channel_name) and $channel_name =~ /$valid_channel_id_re/) { + $channel_id = $yv_obj->channel_id_from_username($channel_name); + + if (not defined $channel_id) { + die "Can't get channel ID from username: <<$channel_name>>"; } - close $fh; } + elsif (defined($channel_id) and $channel_id =~ /\S/) { + die "Invalid channel ID: <<$channel_id>>"; + } + else { + return; + } + + save_channel_by_id($channel_id, $channel_name); } - foreach my $user (sort { lc $a cmp lc $b } values %users_table) { + + sub save_channel_by_id { + my ($channel_id, $channel_name) = @_; + + # Validate the channel ID + if (not defined($channel_id) or not $channel_id =~ /$valid_channel_id_re/) { + return; + } + + # Channel ID already exists in the list + if (exists($channels{$channel_id})) { + return; + } + + # Get the channel name + if (not defined($channel_name) or not $channel_name =~ /\S/) { + $channel_name = $yv_obj->channel_title_from_id($channel_id) // $channel_id; + } + + # Store it internally + $channels{$channel_id} = $channel_name; + + # Append it to the list my $iter = $users_liststore->append; - $users_liststore->set($iter, 0, $user); - $users_liststore->set($iter, 1, $user_icon_pixbuf); + $users_liststore->set($iter, 0, $channel_id); + $users_liststore->set($iter, 1, $channel_name); + $users_liststore->set($iter, 2, 'channel'); + $users_liststore->set($iter, 3, $user_icon_pixbuf); + } + + sub add_user_to_favorites { + my $channel_id = get_channel_id_for_selected_video() // return; + save_channel_by_id($channel_id); + } + + sub remove_selected_user { + my $selection = $users_treeview->get_selection // return; + my $iter = $selection->get_selected // return; + my $channel_id = $users_liststore->get($iter, 0); + delete $channels{$channel_id}; + $users_liststore->remove($iter); + } + + sub save_usernames_to_file { + open(my $fh, '>:utf8', $CONFIG{youtube_users_file}) or return; + foreach my $channel ( + sort { ($channels{$a} // $a) cmp($channels{$b} // $b) } + keys %channels + ) { + if (defined($channels{$channel})) { + say $fh "$channel $channels{$channel}"; + } + else { + say $fh $channel; + } + } + close $fh; } -} -sub add_username { - my $user = $gui->get_object('username_entry')->get_text; - $users_table{lc $user} = $user; - my $iter = $users_liststore->append; - $users_liststore->set($iter, 0, $user); - $users_liststore->set($iter, 1, $user_icon_pixbuf); -} + # Get playlists from username + sub playlists_from_selected_username { + my $selection = $users_treeview->get_selection() // return; + my $iter = $selection->get_selected() // return; -sub add_user_to_favorites { - my $user = get_channel_id_for_selected_video() or return; - $gui->get_object('username_entry')->set_text($user); - add_username(); - $feeds_statusbar->push(0, "Successfully added '${user}' into the username list (see: Menu->Users)"); -} + my $type = $users_liststore->get($iter, 2); + my $channel = $users_liststore->get($iter, 0); -sub remove_selected_user { - my $iter = $users_treeview->get_selection->get_selected; - my $selected_user = $users_liststore->get($iter, 0); - delete $users_table{lc $selected_user}; - $users_liststore->remove($iter); -} + playlists($type, $channel); + } -sub save_usernames_to_file { - open my $fh, '>', $CONFIG{youtube_users_file} or return 0; - local $, = "\n"; - print $fh sort { lc $a cmp lc $b } values %users_table; - close $fh; + sub videos_from_selected_username { + my $selection = $users_treeview->get_selection() // return; + my $iter = $selection->get_selected() // return; + + my $type = $users_liststore->get($iter, 2); + my $channel = $users_liststore->get($iter, 0); + + uploads($type, $channel); + } + + sub videos_from_saved_channel { + hide_users_list_window(); + videos_from_selected_username(); + } } # ----- My panel settings ----- # @@ -1541,9 +2061,12 @@ sub get_selected_entry_code { my (%options) = @_; my $iter = $treeview->get_selection->get_selected // return; - if (not $options{force}) { - return unless defined $liststore->get($iter, 4); + + if (exists $options{type}) { + my $type = $liststore->get($iter, 7) // return; + $type eq $options{type} or return; } + my $code = $liststore->get($iter, 3); return wantarray ? ($code, $iter) : $code; } @@ -1645,7 +2168,7 @@ } sub get_code { - my ($code, $iter) = get_selected_entry_code(force => 1); + my ($code, $iter) = get_selected_entry_code(); $code // return; my $type = $liststore->get($iter, 7); @@ -1668,8 +2191,12 @@ display_results($results); } - : $type eq 'video' ? play_video($yv_obj->parse_json_string($liststore->get($iter, 8))) - : return; + : $type eq 'video' ? ( + $CONFIG{audio_only} + ? execute_cli_youtube_viewer("--id=$code") + : play_video($yv_obj->parse_json_string($liststore->get($iter, 8))) + ) + : return; } sub _make_row_description { @@ -1798,7 +2325,9 @@ $liststore->set($iter, 7, 'subscription'); $row_description = _make_row_description($row_description); - $liststore->set($iter, 3, $yv_utils->get_channel_id($subscription)); + my $channel_id = $yv_utils->get_channel_id($subscription); + $liststore->set($iter, 3, $channel_id); + $liststore->set($iter, 6, $channel_id); $liststore->set( $iter, 0, @@ -1806,7 +2335,7 @@ . encode_entities($yv_utils->get_title($subscription)) . "\n\n" . "$symbols{face}\t " - . encode_entities($yv_utils->get_channel_id($subscription)) . "\n" + . encode_entities($channel_id) . "\n" . "$symbols{crazy_arrow}\t " . $yv_utils->get_publication_date($subscription) . "\n\n" @@ -1824,11 +2353,12 @@ sub add_video_entry { my ($video) = @_; - my $iter = $liststore->append; + my $iter = $liststore->append; + my $channel_id = $yv_utils->get_channel_id($video); my $row_description = $yv_utils->get_description($video); $liststore->set($iter, 4, $row_description); - $liststore->set($iter, 6, $yv_utils->get_channel_id($video)); + $liststore->set($iter, 6, $channel_id); $liststore->set($iter, 7, 'video'); $liststore->set($iter, 8, $yv_obj->make_json_string($video)); $row_description = _make_row_description($row_description); @@ -1844,10 +2374,10 @@ . $yv_utils->set_thousands($yv_utils->get_likes($video)) . "\n" . "$symbols{down_arrow}\t " . $yv_utils->set_thousands($yv_utils->get_dislikes($video)) . "\n" - . "$symbols{ellipsis}\t " - . $yv_utils->get_caption($video) . "\n" . "$symbols{face}\t " - . encode_entities($yv_utils->get_channel_title($video)) . "\n" . "" + . encode_entities($yv_utils->get_channel_title($video)) . "\n" + . "$symbols{ellipsis}\t " + . encode_entities($channel_id) . "\n" . "" . encode_entities($row_description) . "" ); @@ -1881,7 +2411,9 @@ $liststore->set($iter, 7, 'channel'); $row_description = _make_row_description($row_description); - $liststore->set($iter, 3, $yv_utils->get_channel_id($channel)); + my $channel_id = $yv_utils->get_channel_id($channel); + $liststore->set($iter, 3, $channel_id); + $liststore->set($iter, 6, $channel_id); $liststore->set( $iter, 0, @@ -1891,7 +2423,7 @@ . "$symbols{face}\t " . encode_entities($yv_utils->get_channel_title($channel)) . "\n" . "$symbols{play}\t " - . encode_entities($yv_utils->get_channel_id($channel)) . "\n" + . encode_entities($channel_id) . "\n" . "$symbols{crazy_arrow}\t " . $yv_utils->get_publication_date($channel) . "\n\n" @@ -1911,13 +2443,14 @@ my $iter = $liststore->append; my $row_description = $yv_utils->get_description($playlist); + my $playlist_id = $yv_utils->get_playlist_id($playlist); $liststore->set($iter, 4, $row_description); $row_description = _make_row_description($row_description); $liststore->set($iter, 6, $yv_utils->get_channel_id($playlist)); $liststore->set($iter, 7, 'playlist'); - $liststore->set($iter, 3, $yv_utils->get_playlist_id($playlist)); + $liststore->set($iter, 3, $playlist_id); $liststore->set( $iter, 0, @@ -1927,7 +2460,7 @@ . "$symbols{face}\t " . encode_entities($yv_utils->get_channel_title($playlist)) . "\n" . "$symbols{play}\t " - . encode_entities($yv_utils->get_playlist_id($playlist)) . "\n" + . encode_entities($playlist_id) . "\n" . "$symbols{crazy_arrow}\t " . $yv_utils->format_date($yv_utils->get_publication_date($playlist)) . "\n\n" . '' . encode_entities($row_description) . '' @@ -1941,12 +2474,6 @@ } } -sub print_channel_suggestions { - my $results = $yv_obj->get_channel_suggestions(); - $liststore->clear if $CONFIG{clear_search_list}; - display_results($results); -} - sub list_playlist { my ($playlist_id) = @_; @@ -1962,23 +2489,6 @@ return; } -# Get playlists from username -sub playlists_from_selected_username { - my $iter = $users_treeview->get_selection->get_selected; - playlists('username', $users_liststore->get($iter, 0)); -} - -sub videos_from_selected_username { - my $iter = $users_treeview->get_selection->get_selected; - my $username = $users_liststore->get($iter, 0); - uploads('user', $username); -} - -sub get_username_from_list { - hide_users_list_window(); - videos_from_selected_username(); -} - sub favorites_from_text_entry { my ($text_entry) = @_; favorites($channel_type_combobox->get_active_text, $text_entry->get_text); @@ -2023,7 +2533,7 @@ sub is_valid_username { my ($username) = @_; die "Invalid username: <$username>\n" - unless $username =~ /$valid_username_re/; + unless $username =~ /$valid_channel_id_re/; return 1; } @@ -2130,10 +2640,11 @@ sub play_video { my ($video) = @_; - my $streaming = get_streaming_url($yv_utils->get_video_id($video)); + my $video_id = $yv_utils->get_video_id($video); + my $streaming = get_streaming_url($video_id); if (defined $streaming->{info}{status} and $streaming->{info}{status} =~ /\bfail/i) { - die "[x_x] Error on: " . sprintf($CONFIG{youtube_video_url}, $video->{videoID}) . "\n", + die "[x_x] Error on: " . sprintf($CONFIG{youtube_video_url}, $video_id) . "\n", "[x_x] Reason: " . $streaming->{info}{reason} =~ s/\+/ /gr . "\n"; } @@ -2221,15 +2732,16 @@ 'download-dir' => quotemeta(rel2abs($CONFIG{downloads_dir})), 'fullscreen' => $CONFIG{fullscreen} ? q{} : undef, 'no-dash' => $CONFIG{dash_support} ? undef : q{}, + 'no-video' => $CONFIG{audio_only} ? q{} : undef, ); while (my ($argv, $value) = each %options) { push( @args, do { - $value ? '--' . $argv . '=' . $value - : defined $value ? '--' . $argv - : next; + $value ? '--' . $argv . '=' . $value + : defined($value) ? '--' . $argv + : next; } ); } @@ -2252,8 +2764,8 @@ } } -sub _make_youtube_url { - my ($code, $type) = @_; +sub make_youtube_url { + my ($type, $code) = @_; my $format = ( ($type eq 'subscription' || $type eq 'channel') ? $CONFIG{youtube_channel_url} @@ -2269,61 +2781,47 @@ return "https://www.youtube.com"; } -sub open_youtube_url { - my ($code, $iter) = get_selected_entry_code(); - $code // return; - - my $type = $liststore->get($iter, 7); - my $url = _make_youtube_url($code, $type); +sub open_external_url { + my ($url) = @_; my $exit_code = execute_external_program(join(q{ }, $CONFIG{web_browser} // $ENV{WEBBROWSER} // 'xdg-open', quotemeta($url))); - warn "Can't open YouTube URL - exit code: $exit_code\n" if $exit_code != 0; - return 1; -} -my @queue_codes; + if ($exit_code != 0) { + warn "Can't open URL <<$url>> -- exit code: $exit_code\n"; + } -sub queue_playback { - my $code = get_selected_entry_code() // return; - print "[*] Added: <$code>\n" if $yv_obj->get_debug; - push @queue_codes, $code; return 1; } -sub play_videos_from_queue { - if (@queue_codes) { - execute_cli_youtube_viewer('--video-ids=' . join(q{,}, splice @queue_codes)); - } +sub enqueue_video { + my ($video_id) = @_; + print "[*] Added: <$video_id>\n" if $yv_obj->get_debug; + push @VIDEO_QUEUE, $video_id; return 1; } -sub play_all_video_results { - my $model = $treeview->get_model; - my $iter = $model->get_iter_first // return; - - my @ids; - - do { - push @ids, $liststore->get($iter, 3); - } while defined($iter = $model->iter_next($iter)); - - execute_cli_youtube_viewer('--video-ids=' . join(q{,}, grep { /$valid_video_id_re/ } @ids)); - +sub play_enqueued_videos { + if (@VIDEO_QUEUE) { + execute_cli_youtube_viewer('--video-ids=' . join(q{,}, splice @VIDEO_QUEUE)); + } return 1; } sub play_selected_video_with_cli_youtube_viewer { - my $code = get_selected_entry_code() // return; + my ($code, $iter) = get_selected_entry_code(); + $code // return; - if ($code =~ /$valid_video_id_re/) { + my $type = $liststore->get($iter, 7); + + if ($type eq 'video') { execute_cli_youtube_viewer("--video-id=$code"); } - elsif ($code =~ /$valid_playlist_id_re/) { + elsif ($type eq 'playlist') { execute_cli_youtube_viewer("--pp=$code"); } else { - warn "Can't play: $code\n"; + warn "Can't play $type: $code\n"; } return 1; @@ -2337,7 +2835,9 @@ $CONFIG{terminal}, sprintf( $CONFIG{terminal_exec}, - join(q{ }, $CONFIG{youtube_viewer}, get_options_as_arguments(), @arguments) + join(q{ }, + $CONFIG{youtube_viewer}, get_options_as_arguments(), + @arguments, @{$CONFIG{youtube_viewer_args}}), ) ); my $code = execute_external_program($command); @@ -2349,15 +2849,7 @@ } sub download_video { - my ($code, $iter) = get_selected_entry_code(); - $code // return; - - my $type = $liststore->get($iter, 7); - if ($type ne 'video') { - warn "Can't download resource: $type\n"; - return; - } - + my $code = get_selected_entry_code(type => 'video') // return; execute_cli_youtube_viewer("--video-id=$code", '--download'); return 1; } @@ -2368,7 +2860,8 @@ if (defined $value and $value =~ m{^https?://}) { $feeds_liststore->remove($iter); - my $results = $yv_obj->next_page($value, comments => 1); + my ($url, $token) = split(/;/, $value); + my $results = $yv_obj->next_page($url, $token); if ($yv_utils->has_entries($results)) { display_comments($results); } @@ -2380,67 +2873,32 @@ return 1; } -sub get_user_favorited_videos { +sub show_user_favorited_videos { my $username = get_channel_id_for_selected_video() // return; favorites('channel', $username); } sub get_channel_id_for_selected_video { - my $iter = $treeview->get_selection->get_selected() or return; - return $liststore->get($iter, 6); + my $selection = $treeview->get_selection() // return; + my $iter = $selection->get_selected() // return; + $liststore->get($iter, 6); } sub show_related_videos { - my $code = get_selected_entry_code() // return; + my $video_id = get_selected_entry_code(type => 'video') // return; - my $results = $yv_obj->related_to_videoID($code); + my $results = $yv_obj->related_to_videoID($video_id); if ($yv_utils->has_entries($results)) { $liststore->clear if $CONFIG{clear_search_list}; display_results($results); } else { - die "No related video for videoID: <$code>\n"; + die "No related video for videoID: <$video_id>\n"; } } -sub favorite_video { - my $code = get_selected_entry_code() // return; - - $feeds_statusbar->push( - 0, $yv_obj->favorite_video($code) - ? 'Video favorited.' - : 'Error!' - ); -} - -sub subscribe_channel { - my $channel_id = get_channel_id_for_selected_video(); - $feeds_statusbar->push(0, - $yv_obj->subscribe_channel($channel_id) - ? "Successfully subscribed to channel: $channel_id." - : 'Error!'); -} - -sub like_selected_video { - my $code = get_selected_entry_code() // return; - $feeds_statusbar->push( - 0, $yv_obj->send_rating_to_video($code, 'like') - ? 'Video liked.' - : 'Error!' - ); -} - -sub dislike_selected_video { - my $code = get_selected_entry_code() // return; - $feeds_statusbar->push( - 0, $yv_obj->send_rating_to_video($code, 'dislike') - ? 'Video disliked.' - : 'Error!' - ); -} - sub send_comment_to_video { - my $videoID = get_selected_entry_code() // return; + my $videoID = get_selected_entry_code(type => 'video') // return; my $comment = get_text($gui->get_object('comment_textview')); $feeds_statusbar->push(0, @@ -2472,21 +2930,20 @@ ); } - # - ## This needs work!!! - # - #my $iter = $feeds_liststore->append; - #$feeds_liststore->set($iter, 0, "\n=>> NEXT PAGE\n"); - #$feeds_liststore->set($iter, 1, $url); + if (exists $res->{nextPageToken}) { + my $iter = $feeds_liststore->append; + $feeds_liststore->set($iter, 0, "\nLOAD MORE...\n"); + $feeds_liststore->set($iter, 1, "$url;$res->{nextPageToken}"); + } return 1; } -sub show_more_videos_from_username { +sub show_videos_from_selected_author { uploads('channel', get_channel_id_for_selected_video() || return); } -sub show_playlists_from_username { +sub show_playlists_from_selected_author { my $request = $yv_obj->playlists(get_channel_id_for_selected_video() || return); if ($yv_utils->has_entries($request)) { $liststore->clear if $CONFIG{clear_search_list}; @@ -2521,7 +2978,7 @@ $gui->get_object('video_details_label')->set_label($main_details . $secondary_details); # Setting the link button - my $url = _make_youtube_url($code, $type); + my $url = make_youtube_url($type, $code); my $linkbutton = $gui->get_object('linkbutton1'); $linkbutton->set_label($url); $linkbutton->set_uri($url); diff -Nru youtube-viewer-3.2.0/bin/youtube-viewer youtube-viewer-3.2.4/bin/youtube-viewer --- youtube-viewer-3.2.0/bin/youtube-viewer 2015-12-18 02:45:32.000000000 +0000 +++ youtube-viewer-3.2.4/bin/youtube-viewer 2016-09-04 15:06:02.000000000 +0000 @@ -1,30 +1,30 @@ #!/usr/bin/perl # -# Copyright (C) 2010-2015 Trizen . +# Copyright (C) 2010-2016 Trizen . # -# 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 free software; you can redistribute it and/or modify it +# under the terms of either: the GNU General Public License as published +# by the Free Software Foundation; or the Artistic License. # # 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. +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. # -# You should have received a copy of the GNU General Public License -# along with this program. If not, see . +# See http://dev.perl.org/licenses/ for more information. # #------------------------------------------------------- # Appname: youtube-viewer # Created on: 02 June 2010 -# Latest edit on: 01 October 2015 +# Latest edit on: 02 June 2016 # Website: https://github.com/trizen/youtube-viewer #------------------------------------------------------- # -# youtube-viewer is a command line utility for viewing youtube-videos in MPlayer. +# youtube-viewer is a command line utility for streaming YouTube videos in mpv/vlc/mplayer. # # [CHANGELOG] +# - Added the `--highlight` option to remember and highlight watched videos in a session. - NEW (v3.2.2) +# - Added the `--channel-videos=s` command-line option to display videos from a channel ID. - NEW (v3.2.1) +# - Added the `i..` range, which plays all the videos, starting with video `i`. (#114) - NEW (v3.2.1) # - Added support for downloading multiple videos in parallel (--dl-parallel) - NEW (v3.1.4) # - Migration to APIv3; some features has been lost in the process, but nothing too critical. - NEW (v3.1.4) # - Added built-in support for [auto-generated] closed-captions (gcap is no longer required) - NEW (v3.1.3) @@ -111,13 +111,17 @@ =head1 LICENSE AND COPYRIGHT -Copyright 2010-2015 Trizen. +Copyright 2010-2016 Trizen. This program is free software; you can redistribute it and/or modify it under the terms of either: the GNU General Public License as published by the Free Software Foundation; or the Artistic License. -See http://dev.perl.org/licenses/ for more information. +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 L for more information. =cut @@ -132,6 +136,9 @@ no if $] >= 5.018, warnings => 'experimental::smartmatch'; +use WWW::YoutubeViewer v3.2.4; +use WWW::YoutubeViewer::RegularExpressions; + use File::Spec::Functions qw( catdir catfile @@ -145,7 +152,7 @@ binmode(STDOUT, ':utf8'); my $appname = 'Youtube Viewer'; -my $version = '3.2.0'; +my $version = $WWW::YoutubeViewer::VERSION; my $execname = 'youtube-viewer'; # A better support: @@ -162,19 +169,35 @@ my %opt; my $term_width = 80; +# Keep track of watched videos by their ID +my %watched_videos; + # Unchangeable data goes here my %constant = (win32 => $^O eq 'MSWin32'); # doh -my $xdg_config_home = $ENV{XDG_CONFIG_HOME} - || catdir( - ( - my $home_dir = - $ENV{HOME} - || $ENV{LOGDIR} - || ($constant{win32} ? '\Local Settings\Application Data' : ((getpwuid($<))[7] || `echo -n ~`)) - ), - '.config' - ); +my $home_dir; +my $xdg_config_home = $ENV{XDG_CONFIG_HOME}; + +if ($xdg_config_home and -d -w $xdg_config_home) { + require File::Basename; + $home_dir = File::Basename::dirname($xdg_config_home); + + if (not -d -w $home_dir) { + $home_dir = curdir(); + } +} +else { + $home_dir = + $ENV{HOME} + || $ENV{LOGDIR} + || ($constant{win32} ? '\Local Settings\Application Data' : ((getpwuid($<))[7] || `echo -n ~`)); + + if (not -d -w $home_dir) { + $home_dir = curdir(); + } + + $xdg_config_home = catdir($home_dir, '.config'); +} # Configuration dir/file my $config_dir = catdir($xdg_config_home, $execname); @@ -204,9 +227,6 @@ return; } -# Regular expressions -use WWW::YoutubeViewer::RegularExpressions; - # Main configuration my %CONFIG = ( @@ -224,9 +244,17 @@ srt => q{--sub-file *SUB*}, audio => q{--audio-file *AUDIO*}, fs => q{--fullscreen}, - arg => q{--really-quiet --title *TITLE*}, + arg => q{--really-quiet --title *TITLE* --no-ytdl}, novideo => q{--no-video}, }, + mplayer => { + cmd => q{mplayer}, + srt => q{-sub *SUB*}, + audio => q{-audiofile *AUDIO*}, + fs => q{-fs}, + arg => q{-prefer-ipv4 -really-quiet -title *TITLE*}, + novideo => q{-novideo}, + }, }, video_player_selected => ( @@ -270,6 +298,7 @@ # Others http_proxy => undef, + confirm => 0, debug => 0, page => 1, colors => $constant{win32} ^ 1, @@ -288,6 +317,8 @@ keep_original_video => 0, download_and_play => 0, autohide_watched => 0, + highlight_watched => 0, + highlight_color => 'bold', remove_played_file => 0, history => 0, history_limit => 10_000, @@ -390,6 +421,7 @@ 3-8, 3..8 : same as 3 4 5 6 7 8 8-3, 8..3 : same as 8 7 6 5 4 3 8 2 12 4 6 5 1 : play the videos in your order +10.. : play all the videos onwards from 10 :q(ueue)=i,i,... : enqueue videos for playing them later :pq, :play-queue : play the enqueued videos (if any) :anp, :nnp : auto-next-page, no-next-page @@ -457,12 +489,12 @@ if (not defined $CONFIG{cache_dir}) { my $cache_dir = - (defined($ENV{XDG_CACHE_HOME}) and -w $ENV{XDG_CACHE_HOME}) + ($ENV{XDG_CACHE_HOME} and -d -w $ENV{XDG_CACHE_HOME}) ? $ENV{XDG_CACHE_HOME} : catdir($home_dir, '.cache'); - if (not -w $cache_dir) { - $cache_dir = '.cache'; + if (not -d -w $cache_dir) { + $cache_dir = catdir(curdir(), '.cache'); } $CONFIG{cache_dir} = catdir($cache_dir, 'youtube-viewer'); @@ -534,7 +566,6 @@ $key =~ s/(.{$i})(.)/$2$1/g while --$i; } -require WWW::YoutubeViewer; my $yv_obj = WWW::YoutubeViewer->new( escape_utf8 => 1, key => $key, @@ -591,7 +622,7 @@ --cats-region=s : region code for categories (default: us) * Videos - -u --user=s : list videos uploaded by a specific user + -uv --user-vid=s : list videos uploaded by a specific user -cv --channel-vid=s : list videos uploaded to a specific channel -uf --user-fav=s : list the videos favorited by a specific user -id --videoids=s,s : play YouTube videos by their IDs @@ -599,17 +630,17 @@ --search=s : search for YouTube videos (default mode) * Playlists - -p --playlists : search for playlists of videos - --pid=s : list a playlist of videos by playlistID - --pp=s,s : play the videos from the given playlist IDs - --ps=s : add videos by ID or URL to a post-selected playlist - or in a given playlistID specified with `--pid` - --position=i : the position in a playlist where to add a video - -up --user-pl=s : list the playlists created by a specific user + -p --playlists : search for playlists of videos + --pid=s : list a playlist of videos by playlistID + --pp=s,s : play the videos from the given playlist IDs + --ps=s : add videos by ID or URL to a post-selected playlist + or in a given playlistID specified with `--pid` + --position=i : the position in a playlist where to add a video + -up --user-pl=s : list the playlists created by a specific user + -cp --channel-pl=s : list the playlists belonging to a specific channel ID * Channels --channels : search for Youtube channels - --channel-suggest : show the suggested YouTube channels for you * * Shows -us --user-shows=s : display the shows belonging to a user @@ -709,6 +740,8 @@ --combine-multi! : combine multiple videos into one play instance --get-term-width! : allow $execname to read your terminal width --autohide! : automatically hide watched videos + --highlight! : remember and highlight selected videos + --confirm! : show a confirmation message after each play * Closed-captions --get-captions! : download the closed captions for videos @@ -723,6 +756,9 @@ -W --fixed-width! : adjust the results to fit inside the term width -i --info=s : show some info for a videoID or URL -e --extract=s : extract information from videos (see: -T) + --extract-file=s : extract the information from videos in this file + --dump=format : dump metadata information in `videoID.format` files + valid formats: json, perl -q --quiet : do not display any warning --really-quiet : do not display any warning or output --escape-info! : quotemeta() the fields of the `--extract` @@ -783,6 +819,17 @@ > Arguments that require an ID/URL, you can specify more than one, separated by whitespace (quoted), or separated by commas. +-> My channel + > Starting with version 3.2.1, it's possible to use the string "mine" + in place where a channel ID is required. Doing this, "mine" will be + replaced with your channel ID. (requires authentication) + + Examples: + $execname --channel-playlists=mine + $execname --channel-videos=mine + $execname --likes=mine + $execname --favorites=mine + -> More STDIN help: > ":r", ":return" will return to the previous section. For example, if you search for playlists, then select a playlist @@ -1085,20 +1132,21 @@ } # ... OTHER OPTIONS ... # - if (defined $opt->{shuffle_playlist}) { - $opt{shuffle} = delete $opt->{shuffle_playlist}; + if (defined $opt->{extract_info_file}) { + open my $fh, '>:utf8', delete($opt->{extract_info_file}); + $opt{extract_info_fh} = $fh; } if (defined $opt->{colors}) { $opt{_colors} = $opt->{colors}; if (delete $opt->{colors}) { state $x = require Term::ANSIColor; - *colored = \&Term::ANSIColor::colored; + *colored = \&Term::ANSIColor::colored; + *colorstrip = \&Term::ANSIColor::colorstrip; } else { - *colored = sub { - return $_[0]; - }; + *colored = sub { $_[0] }; + *colorstrip = sub { $_[0] }; } } @@ -1130,7 +1178,7 @@ } if (defined $opt->{dislike_video}) { - rate_videos('dislike', split(/[,\s]+/, delete $opt->{like_video})); + rate_videos('dislike', split(/[,\s]+/, delete $opt->{dislike_video})); } if (defined $opt->{play_video_ids}) { @@ -1170,14 +1218,6 @@ print_channels($yv_obj->search_channels($value, @{$keywords})); } - if (delete $opt->{channel_suggestions}) { - my $results = $yv_obj->get_channel_suggestions(); - - if (defined $results) { - print_channels($results, 'channel_suggestions'); - } - } - if (delete $opt->{categories}) { print_categories($yv_obj->video_categories($opt{cats_region})); } @@ -1195,7 +1235,7 @@ } if (defined $opt->{user_videos}) { - if ($opt->{user_videos} =~ /$valid_username_re/) { + if ($opt->{user_videos} =~ /$valid_channel_id_re/) { print_videos($yv_obj->uploads_from_username(delete $opt->{user_videos})); } else { @@ -1208,7 +1248,7 @@ } if (defined $opt->{user_shows}) { - if ($opt->{user_shows} =~ /$valid_username_re/) { + if ($opt->{user_shows} =~ /$valid_channel_id_re/) { print_shows($yv_obj->get_shows_from_username(delete $opt->{user_shows})); } else { @@ -1234,6 +1274,10 @@ print_playlists($yv_obj->playlists_from_username(delete $opt->{user_playlists})); } + if (defined $opt->{channel_playlists}) { + print_playlists($yv_obj->playlists(delete $opt->{channel_playlists})); + } + if (defined $opt->{favorites}) { my $channel_id = delete($opt->{favorites}); print_videos( @@ -1259,7 +1303,7 @@ if (defined $opt->{user_favorited_videos}) { my $username = delete $opt->{user_favorited_videos}; - if ($username =~ /$valid_username_re/) { + if ($username =~ /$valid_channel_id_re/) { print_videos($yv_obj->favorites_from_username($username)); } else { @@ -1269,7 +1313,7 @@ if (defined $opt->{user_liked_videos}) { my $username = delete $opt->{user_liked_videos}; - if ($username =~ /$valid_username_re/) { + if ($username =~ /$valid_channel_id_re/) { print_videos($yv_obj->likes_from_username($username)); } else { @@ -1339,19 +1383,21 @@ 'dislikes' => \$opt{dislikes}, 'subscribe=s' => \$opt{subscribe_channel}, 'user-subscribe=s' => \$opt{subscribe_username}, - 'favorite|favorite-video|fav=s' => \$opt{favorite_video}, - 'channel-suggestions' => \$opt{channel_suggestions}, 'cv|channel|channel-videos=s' => \$opt{channel_id_videos}, + 'cp|channel-playlists=s' => \$opt{channel_playlists}, + + # English-UK friendly + 'favorite|favourite|favorite-video|favourite-video|fav=s' => \$opt{favorite_video}, - 'login|authenticate' => \$opt{authenticate}, - 'logout' => \$opt{logout}, - 'user|username|u|uv=s' => \$opt{user_videos}, - 'shows|user-shows|us=s' => \$opt{user_shows}, - 'user-playlists|up=s' => \$opt{user_playlists}, - 'user-favorites|uf=s' => \$opt{user_favorited_videos}, - 'user-likes|ul=s' => \$opt{user_liked_videos}, - 'related-videos|rl|rv=s' => \$opt{related_videos}, - 'http_proxy=s' => \$opt{http_proxy}, + 'login|authenticate' => \$opt{authenticate}, + 'logout' => \$opt{logout}, + 'user|user-videos|u|uv=s' => \$opt{user_videos}, + 'shows|user-shows|us=s' => \$opt{user_shows}, + 'user-playlists|up=s' => \$opt{user_playlists}, + 'user-favorites|uf=s' => \$opt{user_favorited_videos}, + 'user-likes|ul=s' => \$opt{user_liked_videos}, + 'related-videos|rl|rv=s' => \$opt{related_videos}, + 'http_proxy=s' => \$opt{http_proxy}, 'catlang|cl|hl=s' => \$opt{hl}, 'category|cat-id|cat=i' => \$opt{videoCategoryId}, @@ -1387,8 +1433,19 @@ 'convert-to|convert_to=s' => \$opt{convert_to}, 'keep-original-video!' => \$opt{keep_original_video}, 'e|extract|extract-info=s' => \$opt{extract_info}, + 'extract-file=s' => \$opt{extract_info_file}, 'escape-info!' => \$opt{escape_info}, + 'dump=s' => sub { + my (undef, $format) = @_; + $opt{dump} = ( + ($format =~ /json/i) ? 'json' : ($format =~ /perl/i) ? 'perl' : do { + warn "[!] Invalid format <<$format>> for option --dump\n"; + undef; + } + ); + }, + # MPlayer 'player|vplayer|video-player|video_player=s' => \$opt{video_player_selected}, 'append-mplayer|append-arg|arg=s' => \$MPLAYER{user_defined_arguments}, @@ -1402,6 +1459,7 @@ 'caption=s' => \$opt{videoCaption}, 'fullscreen|fs|f!' => \$opt{fullscreen}, 'dash!' => \$opt{dash_support}, + 'confirm!' => \$opt{confirm}, 'convert-command|convert-cmd=s' => \$opt{convert_cmd}, 'dash-m4a|dash-mp4-audio!' => \$opt{dash_mp4_audio}, @@ -1414,10 +1472,11 @@ 'info|i|video-info=s' => \$opt{print_video_info}, 'get-term-width!' => \$opt{get_term_width}, 'page=i' => \$opt{page}, - 'novideo|n!' => \$opt{novideo}, + 'novideo|no-video|n!' => \$opt{novideo}, 'autohide!' => \$opt{autohide_watched}, + 'highlight!' => \$opt{highlight_watched}, 'results=i' => \$opt{maxResults}, - 'shuffle|s!' => \$opt{shuffle_playlist}, + 'shuffle|s!' => \$opt{shuffle}, 'more|m!' => \$opt{more_results}, 'combine-multiple-videos|combine!' => \$opt{combine_multiple_videos}, 'pos|position=i' => \$opt{position}, @@ -1850,8 +1909,8 @@ sub get_and_play_playlists { foreach my $id (@_) { my $videos = $yv_obj->videos_from_playlist_id(get_valid_playlist_id($id) // next); - local $opt{play_all} = 1; - print_videos($videos, auto => 1); + local $opt{play_all} = length($opt{std_input}) ? 0 : 1; + print_videos($videos, auto => $opt{play_all}); } return 1; } @@ -1999,7 +2058,7 @@ return if not authenticated(); foreach my $channel (@ids) { - if ($channel =~ /$valid_username_re/) { + if ($channel =~ /$valid_channel_id_re/) { if ($is_channel ? $yv_obj->subscribe_channel($channel) : $yv_obj->subscribe_channel_from_username($channel)) { print "** Successfully subscribed to channel: $channel\n"; } @@ -2249,25 +2308,70 @@ return $num =~ /^[0-9]{1,2}\z/ && $num != 0 && $num <= @{$array_ref}; } -sub chop_title { - my ($title, $title_length) = @_; +sub adj_width { + my ($str, $len, $prepend) = @_; - $title_length > 0 or do { - warn "[WARN] Insufficient space for title: increase your terminal width!\n"; - return $title; + $len > 0 or do { + warn "[WARN] Insufficient space for the title: increase your terminal width!\n"; + return $str; }; - state $x = require Text::CharWidth; - my $title_width_len = Text::CharWidth::mbswidth($title); - if ($title_width_len != $title_length) { - while (Text::CharWidth::mbswidth($title) > $title_length) { - chop $title; + state $pkg = ( + eval { + require Unicode::GCString; + 'Unicode::GCString'; + } // eval { + require Text::CharWidth; + 'Text::CharWidth'; + } // do { + warn "[WARN] Please install Unicode::GCString or Text::CharWidth in order to use this functionality.\n"; + ''; + } + ); + + # + ## Unicode::GCString + # + if ($pkg eq 'Unicode::GCString') { + + my $gcstr = Unicode::GCString->new($str); + my $str_width = $gcstr->columns; + + if ($str_width != $len) { + while ($str_width > $len) { + $gcstr = $gcstr->substr(0, -1); + $str_width = $gcstr->columns; + } + + $str = $gcstr->as_string; + my $spaces = ' ' x ($len - $str_width); + $str = $prepend ? "$spaces$str" : "$str$spaces"; + } + + return $str; + } + + # + ## Text::CharWidth + # + if ($pkg eq 'Text::CharWidth') { + + my $str_width = Text::CharWidth::mbswidth($str); + + if ($str_width != $len) { + while ($str_width > $len) { + chop $str; + $str_width = Text::CharWidth::mbswidth($str); + } + + my $spaces = ' ' x ($len - $str_width); + $str = $prepend ? "$spaces$str" : "$str$spaces"; } - $title .= ' ' x ($title_length - Text::CharWidth::mbswidth($title)); + return $str; } - return $title; + return $str; } # ... PRINT SUBROUTINES ... # @@ -2309,16 +2413,17 @@ my @authors = map { $yv_utils->get_channel_title($_) } @{$channels}; my @dates = map { $yv_utils->get_publication_date($_) } @{$channels}; - my $author_width = List::Util::max(map { length($_) } @authors); - my $dates_width = List::Util::max(map { length($_) } @dates); + my $author_width = List::Util::min(List::Util::max(map { length($_) } @authors), int($term_width / 5)); + my $dates_width = List::Util::max(map { length($_) } @dates); my $title_length = $term_width - ($author_width + $dates_width + 2 + 3 + 1 + 2); print "\n"; foreach my $i (0 .. $#{$channels}) { my $channel = $channels->[$i]; - printf "%s. %s %*s [%*s]\n", colored(sprintf('%2d', $i + 1), 'bold'), - chop_title($yv_utils->get_title($channel), $title_length), - $author_width, $authors[$i], $dates_width, $dates[$i]; + printf "%s. %s %s [%*s]\n", colored(sprintf('%2d', $i + 1), 'bold'), + adj_width($yv_utils->get_title($channel), $title_length), + adj_width($authors[$i], $author_width, 1), + $dates_width, $dates[$i]; } last; } @@ -2500,15 +2605,16 @@ state $x = require List::Util; - my $max_author_len = List::Util::max(map { length($_->{name}) } @{$shows}); - my $count_width = List::Util::max(map { length($_->{seasons}) } @{$shows}); + my $max_author_len = List::Util::min(List::Util::max(map { length($_->{name}) } @{$shows}), int($term_width / 5)); + my $count_width = List::Util::max(map { length($_->{seasons}) } @{$shows}); my $title_length = $term_width - ($max_author_len + $count_width + 2 + 3 + 1 + 2); foreach my $show (@{$shows}) { print "\n" if $i == 0; - printf "%s. %s %*s [%*s]\n", colored(sprintf('%2d', ++$i), 'bold'), - chop_title($show->{title}, $title_length), - $max_author_len, $show->{name}, $count_width, $show->{seasons}; + printf "%s. %s %s [%*s]\n", colored(sprintf('%2d', ++$i), 'bold'), + adj_width($show->{title}, $title_length), + adj_width($show->{name}, $max_author_len, 1), + $count_width, $show->{seasons}; } last; } @@ -2570,8 +2676,8 @@ } my $url = $results->{url}; - my $res = $results->{results} // {}; - my $comments = $res->{items} // []; + my $info = $results->{results} // {}; + my $comments = $info->{items} // []; my $i = 0; foreach my $comment (@{$comments}) { @@ -2600,6 +2706,7 @@ sub => __SUB__, url => $url, res => $comments, + info => $info, mode => 'comments', args => [$videoID], ) @@ -2927,16 +3034,17 @@ my @authors = map { $yv_utils->get_channel_title($_) } @{$playlists}; my @dates = map { $yv_utils->get_publication_date($_) } @{$playlists}; - my $author_width = List::Util::max(map { length($_) } @authors); - my $dates_width = List::Util::max(map { length($_) } @dates); + my $author_width = List::Util::min(List::Util::max(map { length($_) } @authors), int($term_width / 5)); + my $dates_width = List::Util::max(map { length($_) } @dates); my $title_length = $term_width - ($author_width + $dates_width + 2 + 3 + 1 + 2); print "\n"; foreach my $i (0 .. $#{$playlists}) { my $playlist = $playlists->[$i]; - printf "%s. %s %*s [%*s]\n", colored(sprintf('%2d', $i + 1), 'bold'), - chop_title($yv_utils->get_title($playlist), $title_length), - $author_width, $authors[$i], $dates_width, $dates[$i]; + printf "%s. %s %s [%*s]\n", colored(sprintf('%2d', $i + 1), 'bold'), + adj_width($yv_utils->get_title($playlist), $title_length), + adj_width($authors[$i], $author_width, 1), + $dates_width, $dates[$i]; } last; } @@ -2981,6 +3089,7 @@ sub => __SUB__, url => $url, res => $playlists, + info => $info, mode => 'playlists', ) ) { @@ -3320,11 +3429,16 @@ my $video_id = $yv_utils->get_video_id($video); - if (defined($opt{max_seconds})) { + # It may be downloaded, but that's OK... + if ($opt{highlight_watched}) { + $watched_videos{$video_id} = 1; + } + + if (defined($opt{max_seconds}) and $opt{max_seconds} >= 0) { next if $yv_utils->get_duration($video) > $opt{max_seconds}; } - if (defined($opt{min_seconds})) { + if (defined($opt{min_seconds}) and $opt{min_seconds} >= 0) { next if $yv_utils->get_duration($video) < $opt{min_seconds}; } @@ -3340,6 +3454,26 @@ next; } + # Dump metadata information + if (defined($opt{dump})) { + + my $file = $video_id . '.' . $opt{dump}; + open(my $fh, '>:utf8', $file) + or die "Can't open file `$file' for writing: $!"; + + local $video->{streaming} = $streaming; + + if ($opt{dump} eq 'json') { + print {$fh} JSON->new->pretty(1)->encode($video); + } + elsif ($opt{dump} eq 'perl') { + require Data::Dump; + print {$fh} Data::Dump::pp($video); + } + + close $fh; + } + if ($opt{download_video}) { print_video_info($video); if (not download_video($streaming, $video)) { @@ -3347,7 +3481,8 @@ } } elsif (length($opt{extract_info})) { - say $yv_utils->format_text($streaming, $video, $opt{extract_info}, $opt{escape_info}); + my $fh = $opt{extract_info_fh} // \*STDOUT; + say {$fh} $yv_utils->format_text($streaming, $video, $opt{extract_info}, $opt{escape_info}); } elsif ($opt{combine_multiple_videos}) { print_video_info($video); @@ -3368,9 +3503,12 @@ $yv_obj->proxy_system($command); # execute the video player if ($? and $? != 512) { + $opt{auto_next_page} = 0; return; } } + + press_enter_to_continue() if $opt{confirm}; } if ($opt{combine_multiple_videos} && @streaming_urls) { @@ -3438,8 +3576,11 @@ my $title = $yv_utils->get_title($video); my $title_length = length($title); + my $rep = ($term_width - $title_length) / 2 - 4; - print "\n$hr\n", q{ } x (($term_width - $title_length) / 2 - 4) => (_bold_color("=>> $title <<=") . "\n\n"), + $rep = 0 if $rep < 0; + + print "\n$hr\n", q{ } x $rep => (_bold_color("=>> $title <<=") . "\n\n"), map(sprintf(q{-> } . "%-*s: %s\n", $opt{_colors} ? 18 : 10, _bold_color($_->[0]), $_->[1]), ( ['Channel' => $yv_utils->get_channel_title($video)], @@ -3486,37 +3627,40 @@ $results->{has_extra_info} = 1; } + my @formatted; + foreach my $i (0 .. $#{$videos}) { my $video = $videos->[$i]; if ($opt{results_with_details}) { - printf( - "\n%s. %s\n" . " %s: %-16s %s: %-13s %s: %s\n" . " %s: %-12s %s: %-10s %s: %s\n%s\n", - colored(sprintf('%2d', $i + 1), 'bold') => colored($yv_utils->get_title($video), 'bold blue'), - colored('Views' => 'bold') => $yv_utils->set_thousands($yv_utils->get_views($video)), - colored('Likes' => 'bold') => $yv_utils->set_thousands($yv_utils->get_likes($video)), - colored('Dislikes' => 'bold') => $yv_utils->set_thousands($yv_utils->get_dislikes($video)), - colored('Published' => 'bold') => $yv_utils->get_publication_date($video), - colored('Duration' => 'bold') => $yv_utils->format_time($yv_utils->get_duration($video)), - colored('Author' => 'bold') => $yv_utils->get_channel_title($video), - wrap_text( - i_tab => q{ } x 4, - s_tab => q{ } x 4, - text => [$yv_utils->get_description($video) || 'No description available...'] - ), - ); + push @formatted, + ($i == 0 ? '' : "\n") + . sprintf( + "%s. %s\n" . " %s: %-16s %s: %-13s %s: %s\n" . " %s: %-12s %s: %-10s %s: %s\n%s\n", + colored(sprintf('%2d', $i + 1), 'bold') => colored($yv_utils->get_title($video), 'bold blue'), + colored('Views' => 'bold') => $yv_utils->set_thousands($yv_utils->get_views($video)), + colored('Likes' => 'bold') => $yv_utils->set_thousands($yv_utils->get_likes($video)), + colored('Dislikes' => 'bold') => $yv_utils->set_thousands($yv_utils->get_dislikes($video)), + colored('Published' => 'bold') => $yv_utils->get_publication_date($video), + colored('Duration' => 'bold') => $yv_utils->format_time($yv_utils->get_duration($video)), + colored('Author' => 'bold') => $yv_utils->get_channel_title($video), + wrap_text( + i_tab => q{ } x 4, + s_tab => q{ } x 4, + text => [$yv_utils->get_description($video) || 'No description available...'] + ), + ); } elsif ($opt{results_with_colors}) { - print "\n" if $i == 0; - my $definition = $yv_utils->get_definition($video); - printf( - "%s. %s (%s) [%s]\n", - colored(sprintf('%2d', $i + 1), 'bold'), - colored($yv_utils->get_title($video), 'bold green'), - colored("by " . $yv_utils->get_channel_title($video), 'bold yellow'), - colored($yv_utils->format_time($yv_utils->get_duration($video)), 'bold bright_blue'), - ); + push @formatted, + sprintf( + "%s. %s (%s) [%s]\n", + colored(sprintf('%2d', $i + 1), 'bold'), + colored($yv_utils->get_title($video), 'bold green'), + colored("by " . $yv_utils->get_channel_title($video), 'bold yellow'), + colored($yv_utils->format_time($yv_utils->get_duration($video)), 'bold bright_blue'), + ); } elsif ($opt{results_fixed_width}) { @@ -3525,30 +3669,45 @@ my @durations = map { $yv_utils->get_duration($_) } @{$videos}; my @authors = map { $yv_utils->get_channel_title($_) } @{$videos}; - my $author_width = List::Util::max(map { length($_) } @authors); + my $author_width = List::Util::min(List::Util::max(map { length($_) } @authors), int($term_width / 5)); my $time_width = List::Util::first(sub { $_ >= 3600 }, @durations) ? 8 : 6; my $title_length = $term_width - ($author_width + $time_width + 3 + 2 + 1); - print "\n"; foreach my $i (0 .. $#{$videos}) { my $video = $videos->[$i]; - printf "%s. %s %*s %*s\n", colored(sprintf('%2d', $i + 1), 'bold'), - chop_title($yv_utils->get_title($video), $title_length), - $author_width, $yv_utils->get_channel_title($video), $time_width, $yv_utils->format_time($durations[$i]); + push @formatted, + sprintf("%s. %s %s %*s\n", + colored(sprintf('%2d', $i + 1), 'bold'), + adj_width($yv_utils->get_title($video), $title_length), + adj_width($yv_utils->get_channel_title($video), $author_width, 1), + $time_width, + $yv_utils->format_time($durations[$i])); } last; } else { - print "\n" if $i == 0; + push @formatted, + sprintf( + "%s. %s (by %s) [%s]\n", + colored(sprintf('%2d', $i + 1), 'bold'), $yv_utils->get_title($video), + $yv_utils->get_channel_title($video), $yv_utils->format_time($yv_utils->get_duration($video)), + ); + } + } - printf( - "%s. %s (by %s) [%s]\n", - colored(sprintf('%2d', $i + 1), 'bold'), $yv_utils->get_title($video), - $yv_utils->get_channel_title($video), $yv_utils->format_time($yv_utils->get_duration($video)), - ); + if ($opt{highlight_watched}) { + foreach my $i (0 .. $#{$videos}) { + my $video = $videos->[$i]; + if (exists($watched_videos{$yv_utils->get_video_id($video)})) { + $formatted[$i] = colored(colorstrip($formatted[$i]), $opt{highlight_color}); + } } } + if (@formatted) { + print "\n" . join("", @formatted); + } + if ($opt{play_all} || $opt{play_backwards}) { if (@{$videos}) { if ( @@ -3761,6 +3920,7 @@ when (/^(?:play|P)${digit_or_equal_re}(.*)/) { if (my @nums = get_valid_numbers($#{$videos}, $1)) { local $opt{download_video} = 0; + local $opt{extract_info} = undef; play_videos([@{$videos}[@nums]]); } else { @@ -3817,7 +3977,12 @@ when (!$contains_keywords && (valid_num($_, $videos) || /$range_num_re/)) { my @for_play; if (/$range_num_re/) { - my @ids = get_valid_numbers($#{$videos}, "$1..$2"); + my $from = $1; + my $to = $2 // do { + $opt{auto_next_page} ? do { $from = 1 } : do { $opt{auto_next_page} = 1 }; + $#{$videos} + 1; + }; + my @ids = get_valid_numbers($#{$videos}, "$from..$to"); continue if not @ids; push @for_play, @ids; } diff -Nru youtube-viewer-3.2.0/Build.PL youtube-viewer-3.2.4/Build.PL --- youtube-viewer-3.2.0/Build.PL 2015-12-18 02:45:32.000000000 +0000 +++ youtube-viewer-3.2.4/Build.PL 2016-09-04 15:06:02.000000000 +0000 @@ -75,7 +75,8 @@ fixed_width_support => { description => "Print the results in a fixed-width format (--fixed-width, -W)", requires => { - 'Text::CharWidth' => 0, + 'Unicode::GCString' => 0, # this is recommended + #'Text::CharWidth' => 0, # this works as fallback }, }, diff -Nru youtube-viewer-3.2.0/debian/changelog youtube-viewer-3.2.4/debian/changelog --- youtube-viewer-3.2.0/debian/changelog 2016-05-30 20:12:51.000000000 +0000 +++ youtube-viewer-3.2.4/debian/changelog 2016-09-17 16:30:37.000000000 +0000 @@ -1,8 +1,29 @@ -youtube-viewer (3.2.0-1~ppa16.04+1) xenial; urgency=medium +youtube-viewer (3.2.4-1~ppa16.04+1) xenial; urgency=medium - * Merge from Webupd8 PPA. + * Merge new upstream release from Webupd8 PPA. - -- Nicolas Derive Mon, 30 May 2016 22:10:02 +0200 + -- Nicolas Derive Sat, 17 Sep 2016 18:29:10 +0200 + +youtube-viewer (3.2.4-1~webupd8~wily0) wily; urgency=medium + + * New upstream release + + -- Alin Andrei Mon, 05 Sep 2016 12:29:16 +0200 + +youtube-viewer (3.2.3-1~webupd8~xenial0) xenial; urgency=medium + + * New upstream release + + -- Alin Andrei Mon, 01 Aug 2016 12:43:19 +0200 + +youtube-viewer (3.2.2-1~webupd8~trusty1) trusty; urgency=medium + + * New upstream release + * Depend on libunicode-string-perl, libencode-perl, libterm-ui-perl + * Recommends: liblwp-useragent-chicaching-perl + * Bump Standards-Version to 3.9.7 + + -- Alin Andrei Wed, 20 Jul 2016 19:25:18 +0100 youtube-viewer (3.2.0-1~webupd8~xenial0) xenial; urgency=medium diff -Nru youtube-viewer-3.2.0/debian/control youtube-viewer-3.2.4/debian/control --- youtube-viewer-3.2.0/debian/control 2015-05-27 12:12:04.000000000 +0000 +++ youtube-viewer-3.2.4/debian/control 2016-07-20 16:42:30.000000000 +0000 @@ -3,7 +3,7 @@ Priority: optional Maintainer: Alin Andrei Build-Depends: debhelper (>= 9), libperl-dev, libmodule-build-perl -Standards-Version: 3.9.5 +Standards-Version: 3.9.7 Homepage: https://github.com/trizen/youtube-viewer Vcs-Git: git://github.com/trizen/youtube-viewer.git Vcs-Browser: https://github.com/trizen/youtube-viewer @@ -11,7 +11,8 @@ Package: youtube-viewer Architecture: all Depends: ${shlibs:Depends}, ${misc:Depends}, perl, libdata-dump-perl, libfile-sharedir-perl, libgtk2-perl, libwww-perl, libterm-readline-perl-perl, liburi-perl, youtube-dl (>= 2015.02.23), libjson-xs-perl, libjson-perl, libparse-http-useragent-perl -Suggests: gcap, liblwp-protocol-https-perl, libtext-charwidth-perl, libterm-readkey-perl, libterm-readline-gnu-perl, libterm-ui-perl, libterm-extendedcolor-perl, mplayer | mplayer2 | mpv | vlc, wget +Suggests: gcap, liblwp-protocol-https-perl, libtext-charwidth-perl, libterm-readkey-perl, libterm-readline-gnu-perl, libterm-ui-perl, libterm-extendedcolor-perl, libunicode-string-perl, libencode-perl, libterm-ui-perl, mplayer | mplayer2 | mpv | vlc, wget +Recommends: liblwp-useragent-chicaching-perl Description: YouTube Viewer A Gtk2 application (+Terminal utility) for searching and streaming videos from YouTube. diff -Nru youtube-viewer-3.2.0/lib/WWW/YoutubeViewer/Activities.pm youtube-viewer-3.2.4/lib/WWW/YoutubeViewer/Activities.pm --- youtube-viewer-3.2.0/lib/WWW/YoutubeViewer/Activities.pm 2015-12-18 02:45:32.000000000 +0000 +++ youtube-viewer-3.2.4/lib/WWW/YoutubeViewer/Activities.pm 2016-09-04 15:06:02.000000000 +0000 @@ -8,14 +8,6 @@ WWW::YoutubeViewer::Activities - ... -=head1 VERSION - -Version 0.01 - -=cut - -our $VERSION = '0.01'; - =head1 SYNOPSIS use WWW::YoutubeViewer::Activities; @@ -58,41 +50,10 @@ Copyright 2013-2015 Trizen. This program is free software; you can redistribute it and/or modify it -under the terms of the the Artistic License (2.0). You may obtain a -copy of the full license at: - -L - -Any use, modification, and distribution of the Standard or Modified -Versions is governed by this Artistic License. By using, modifying or -distributing the Package, you accept this license. Do not use, modify, -or distribute the Package, if you do not accept this license. - -If your Modified Version has been derived from a Modified Version made -by someone other than you, you are nevertheless required to ensure that -your Modified Version complies with the requirements of this license. - -This license does not grant you the right to use any trademark, service -mark, tradename, or logo of the Copyright Holder. - -This license includes the non-exclusive, worldwide, free-of-charge -patent license to make, have made, use, offer to sell, sell, import and -otherwise transfer the Package with respect to any patent claims -licensable by the Copyright Holder that are necessarily infringed by the -Package. If you institute patent litigation (including a cross-claim or -counterclaim) against any party alleging that the Package constitutes -direct or contributory patent infringement, then this Artistic License -to you shall terminate on the date that such litigation is filed. - -Disclaimer of Warranty: THE PACKAGE IS PROVIDED BY THE COPYRIGHT HOLDER -AND CONTRIBUTORS "AS IS' AND WITHOUT ANY EXPRESS OR IMPLIED WARRANTIES. -THE IMPLIED WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR -PURPOSE, OR NON-INFRINGEMENT ARE DISCLAIMED TO THE EXTENT PERMITTED BY -YOUR LOCAL LAW. UNLESS REQUIRED BY LAW, NO COPYRIGHT HOLDER OR -CONTRIBUTOR WILL BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, OR -CONSEQUENTIAL DAMAGES ARISING IN ANY WAY OUT OF THE USE OF THE PACKAGE, -EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. +under the terms of either: the GNU General Public License as published +by the Free Software Foundation; or the Artistic License. +See L for more information. =cut diff -Nru youtube-viewer-3.2.0/lib/WWW/YoutubeViewer/Authentication.pm youtube-viewer-3.2.4/lib/WWW/YoutubeViewer/Authentication.pm --- youtube-viewer-3.2.0/lib/WWW/YoutubeViewer/Authentication.pm 2015-12-18 02:45:32.000000000 +0000 +++ youtube-viewer-3.2.4/lib/WWW/YoutubeViewer/Authentication.pm 2016-09-04 15:06:02.000000000 +0000 @@ -8,14 +8,6 @@ WWW::YoutubeViewer::Authentication - OAuth login support. -=head1 VERSION - -Version 0.01 - -=cut - -our $VERSION = '0.01'; - =head1 SYNOPSIS use WWW::YoutubeViewer; @@ -66,7 +58,7 @@ response_type => 'code', client_id => $self->get_client_id() // return, redirect_uri => $self->get_redirect_uri() // return, - scope => 'https://www.googleapis.com/auth/youtube', + scope => 'https://www.googleapis.com/auth/youtube.force-ssl', access_type => 'offline', ); return $url; @@ -214,41 +206,10 @@ Copyright 2013-2015 Trizen. This program is free software; you can redistribute it and/or modify it -under the terms of the the Artistic License (2.0). You may obtain a -copy of the full license at: - -L - -Any use, modification, and distribution of the Standard or Modified -Versions is governed by this Artistic License. By using, modifying or -distributing the Package, you accept this license. Do not use, modify, -or distribute the Package, if you do not accept this license. - -If your Modified Version has been derived from a Modified Version made -by someone other than you, you are nevertheless required to ensure that -your Modified Version complies with the requirements of this license. - -This license does not grant you the right to use any trademark, service -mark, tradename, or logo of the Copyright Holder. - -This license includes the non-exclusive, worldwide, free-of-charge -patent license to make, have made, use, offer to sell, sell, import and -otherwise transfer the Package with respect to any patent claims -licensable by the Copyright Holder that are necessarily infringed by the -Package. If you institute patent litigation (including a cross-claim or -counterclaim) against any party alleging that the Package constitutes -direct or contributory patent infringement, then this Artistic License -to you shall terminate on the date that such litigation is filed. - -Disclaimer of Warranty: THE PACKAGE IS PROVIDED BY THE COPYRIGHT HOLDER -AND CONTRIBUTORS "AS IS' AND WITHOUT ANY EXPRESS OR IMPLIED WARRANTIES. -THE IMPLIED WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR -PURPOSE, OR NON-INFRINGEMENT ARE DISCLAIMED TO THE EXTENT PERMITTED BY -YOUR LOCAL LAW. UNLESS REQUIRED BY LAW, NO COPYRIGHT HOLDER OR -CONTRIBUTOR WILL BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, OR -CONSEQUENTIAL DAMAGES ARISING IN ANY WAY OUT OF THE USE OF THE PACKAGE, -EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. +under the terms of either: the GNU General Public License as published +by the Free Software Foundation; or the Artistic License. +See L for more information. =cut diff -Nru youtube-viewer-3.2.0/lib/WWW/YoutubeViewer/Channels.pm youtube-viewer-3.2.4/lib/WWW/YoutubeViewer/Channels.pm --- youtube-viewer-3.2.0/lib/WWW/YoutubeViewer/Channels.pm 2015-12-18 02:45:32.000000000 +0000 +++ youtube-viewer-3.2.4/lib/WWW/YoutubeViewer/Channels.pm 2016-09-04 15:06:02.000000000 +0000 @@ -8,14 +8,6 @@ WWW::YoutubeViewer::Channels - Channels interface. -=head1 VERSION - -Version 0.01 - -=cut - -our $VERSION = '0.01'; - =head1 SYNOPSIS use WWW::YoutubeViewer; @@ -119,7 +111,7 @@ =head2 channel_id_from_username($username) -Return the channel id for an username. +Return the channel ID for an username. =cut @@ -129,6 +121,24 @@ $channel->{results}{items}[0]{id} // return; } +=head2 channel_title_from_id($channel_id) + +Return the channel title for a given channel ID. + +=cut + +sub channel_title_from_id { + my ($self, $channel_id) = @_; + my $info = $self->channels_info($channel_id // return) // return; + + ( ref($info) eq 'HASH' + and ref($info->{results}) eq 'HASH' + and ref($info->{results}{items}) eq 'ARRAY' + and ref($info->{results}{items}[0]) eq 'HASH') + ? $info->{results}{items}[0]{snippet}{title} + : (); +} + =head2 channels_contentDetails($channelID) { @@ -207,41 +217,10 @@ Copyright 2013-2015 Trizen. This program is free software; you can redistribute it and/or modify it -under the terms of the the Artistic License (2.0). You may obtain a -copy of the full license at: - -L - -Any use, modification, and distribution of the Standard or Modified -Versions is governed by this Artistic License. By using, modifying or -distributing the Package, you accept this license. Do not use, modify, -or distribute the Package, if you do not accept this license. - -If your Modified Version has been derived from a Modified Version made -by someone other than you, you are nevertheless required to ensure that -your Modified Version complies with the requirements of this license. - -This license does not grant you the right to use any trademark, service -mark, tradename, or logo of the Copyright Holder. - -This license includes the non-exclusive, worldwide, free-of-charge -patent license to make, have made, use, offer to sell, sell, import and -otherwise transfer the Package with respect to any patent claims -licensable by the Copyright Holder that are necessarily infringed by the -Package. If you institute patent litigation (including a cross-claim or -counterclaim) against any party alleging that the Package constitutes -direct or contributory patent infringement, then this Artistic License -to you shall terminate on the date that such litigation is filed. - -Disclaimer of Warranty: THE PACKAGE IS PROVIDED BY THE COPYRIGHT HOLDER -AND CONTRIBUTORS "AS IS' AND WITHOUT ANY EXPRESS OR IMPLIED WARRANTIES. -THE IMPLIED WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR -PURPOSE, OR NON-INFRINGEMENT ARE DISCLAIMED TO THE EXTENT PERMITTED BY -YOUR LOCAL LAW. UNLESS REQUIRED BY LAW, NO COPYRIGHT HOLDER OR -CONTRIBUTOR WILL BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, OR -CONSEQUENTIAL DAMAGES ARISING IN ANY WAY OUT OF THE USE OF THE PACKAGE, -EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. +under the terms of either: the GNU General Public License as published +by the Free Software Foundation; or the Artistic License. +See L for more information. =cut diff -Nru youtube-viewer-3.2.0/lib/WWW/YoutubeViewer/CommentThreads.pm youtube-viewer-3.2.4/lib/WWW/YoutubeViewer/CommentThreads.pm --- youtube-viewer-3.2.0/lib/WWW/YoutubeViewer/CommentThreads.pm 2015-12-18 02:45:32.000000000 +0000 +++ youtube-viewer-3.2.4/lib/WWW/YoutubeViewer/CommentThreads.pm 2016-09-04 15:06:02.000000000 +0000 @@ -8,14 +8,6 @@ WWW::YoutubeViewer::CommentThreads - Retrieve comments threads. -=head1 VERSION - -Version 0.01 - -=cut - -our $VERSION = '0.01'; - =head1 SYNOPSIS use WWW::YoutubeViewer; @@ -67,25 +59,19 @@ my $url = $self->_simple_feeds_url('commentThreads', part => 'snippet'); - state $channel = $self->my_channel; - if (defined($channel) and defined $channel->{results}) { - ## ok - } - else { - return; - } - my $hash = { - "snippet" => { - "topLevelComment" => { - "snippet" => { - "textOriginal" => $comment, - "channelId" => $channel->{results}{items}[0]{id} - } - }, - "videoId" => $video_id, - } - }; + "snippet" => { + + "topLevelComment" => { + "snippet" => { + "textOriginal" => $comment, + } + }, + "videoId" => $video_id, + + #"channelId" => $channel_id, + }, + }; $self->post_as_json($url, $hash); } @@ -104,44 +90,13 @@ =head1 LICENSE AND COPYRIGHT -Copyright 2015 Trizen. +Copyright 2015-2016 Trizen. This program is free software; you can redistribute it and/or modify it -under the terms of the the Artistic License (2.0). You may obtain a -copy of the full license at: - -L - -Any use, modification, and distribution of the Standard or Modified -Versions is governed by this Artistic License. By using, modifying or -distributing the Package, you accept this license. Do not use, modify, -or distribute the Package, if you do not accept this license. - -If your Modified Version has been derived from a Modified Version made -by someone other than you, you are nevertheless required to ensure that -your Modified Version complies with the requirements of this license. - -This license does not grant you the right to use any trademark, service -mark, tradename, or logo of the Copyright Holder. - -This license includes the non-exclusive, worldwide, free-of-charge -patent license to make, have made, use, offer to sell, sell, import and -otherwise transfer the Package with respect to any patent claims -licensable by the Copyright Holder that are necessarily infringed by the -Package. If you institute patent litigation (including a cross-claim or -counterclaim) against any party alleging that the Package constitutes -direct or contributory patent infringement, then this Artistic License -to you shall terminate on the date that such litigation is filed. - -Disclaimer of Warranty: THE PACKAGE IS PROVIDED BY THE COPYRIGHT HOLDER -AND CONTRIBUTORS "AS IS' AND WITHOUT ANY EXPRESS OR IMPLIED WARRANTIES. -THE IMPLIED WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR -PURPOSE, OR NON-INFRINGEMENT ARE DISCLAIMED TO THE EXTENT PERMITTED BY -YOUR LOCAL LAW. UNLESS REQUIRED BY LAW, NO COPYRIGHT HOLDER OR -CONTRIBUTOR WILL BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, OR -CONSEQUENTIAL DAMAGES ARISING IN ANY WAY OUT OF THE USE OF THE PACKAGE, -EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. +under the terms of either: the GNU General Public License as published +by the Free Software Foundation; or the Artistic License. +See L for more information. =cut diff -Nru youtube-viewer-3.2.0/lib/WWW/YoutubeViewer/GetCaption.pm youtube-viewer-3.2.4/lib/WWW/YoutubeViewer/GetCaption.pm --- youtube-viewer-3.2.0/lib/WWW/YoutubeViewer/GetCaption.pm 2015-12-18 02:45:32.000000000 +0000 +++ youtube-viewer-3.2.4/lib/WWW/YoutubeViewer/GetCaption.pm 2016-09-04 15:06:02.000000000 +0000 @@ -8,14 +8,6 @@ WWW::YoutubeViewer::GetCaption - Save the YouTube closed captions as .srt files for a videoID. -=head1 VERSION - -Version 0.02 - -=cut - -our $VERSION = '0.02'; - =head1 SYNOPSIS use WWW::YoutubeViewer::GetCaption; @@ -249,41 +241,10 @@ Copyright 2012-2015 Trizen. This program is free software; you can redistribute it and/or modify it -under the terms of the the Artistic License (2.0). You may obtain a -copy of the full license at: - -L - -Any use, modification, and distribution of the Standard or Modified -Versions is governed by this Artistic License. By using, modifying or -distributing the Package, you accept this license. Do not use, modify, -or distribute the Package, if you do not accept this license. - -If your Modified Version has been derived from a Modified Version made -by someone other than you, you are nevertheless required to ensure that -your Modified Version complies with the requirements of this license. - -This license does not grant you the right to use any trademark, service -mark, tradename, or logo of the Copyright Holder. - -This license includes the non-exclusive, worldwide, free-of-charge -patent license to make, have made, use, offer to sell, sell, import and -otherwise transfer the Package with respect to any patent claims -licensable by the Copyright Holder that are necessarily infringed by the -Package. If you institute patent litigation (including a cross-claim or -counterclaim) against any party alleging that the Package constitutes -direct or contributory patent infringement, then this Artistic License -to you shall terminate on the date that such litigation is filed. - -Disclaimer of Warranty: THE PACKAGE IS PROVIDED BY THE COPYRIGHT HOLDER -AND CONTRIBUTORS "AS IS' AND WITHOUT ANY EXPRESS OR IMPLIED WARRANTIES. -THE IMPLIED WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR -PURPOSE, OR NON-INFRINGEMENT ARE DISCLAIMED TO THE EXTENT PERMITTED BY -YOUR LOCAL LAW. UNLESS REQUIRED BY LAW, NO COPYRIGHT HOLDER OR -CONTRIBUTOR WILL BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, OR -CONSEQUENTIAL DAMAGES ARISING IN ANY WAY OUT OF THE USE OF THE PACKAGE, -EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. +under the terms of either: the GNU General Public License as published +by the Free Software Foundation; or the Artistic License. +See L for more information. =cut diff -Nru youtube-viewer-3.2.0/lib/WWW/YoutubeViewer/GuideCategories.pm youtube-viewer-3.2.4/lib/WWW/YoutubeViewer/GuideCategories.pm --- youtube-viewer-3.2.0/lib/WWW/YoutubeViewer/GuideCategories.pm 2015-12-18 02:45:32.000000000 +0000 +++ youtube-viewer-3.2.4/lib/WWW/YoutubeViewer/GuideCategories.pm 2016-09-04 15:06:02.000000000 +0000 @@ -8,14 +8,6 @@ WWW::YoutubeViewer::GuideCategories - Categories interface. -=head1 VERSION - -Version 0.01 - -=cut - -our $VERSION = '0.01'; - =head1 SYNOPSIS use WWW::YoutubeViewer; @@ -106,41 +98,10 @@ Copyright 2013-2015 Trizen. This program is free software; you can redistribute it and/or modify it -under the terms of the the Artistic License (2.0). You may obtain a -copy of the full license at: - -L - -Any use, modification, and distribution of the Standard or Modified -Versions is governed by this Artistic License. By using, modifying or -distributing the Package, you accept this license. Do not use, modify, -or distribute the Package, if you do not accept this license. - -If your Modified Version has been derived from a Modified Version made -by someone other than you, you are nevertheless required to ensure that -your Modified Version complies with the requirements of this license. - -This license does not grant you the right to use any trademark, service -mark, tradename, or logo of the Copyright Holder. - -This license includes the non-exclusive, worldwide, free-of-charge -patent license to make, have made, use, offer to sell, sell, import and -otherwise transfer the Package with respect to any patent claims -licensable by the Copyright Holder that are necessarily infringed by the -Package. If you institute patent litigation (including a cross-claim or -counterclaim) against any party alleging that the Package constitutes -direct or contributory patent infringement, then this Artistic License -to you shall terminate on the date that such litigation is filed. - -Disclaimer of Warranty: THE PACKAGE IS PROVIDED BY THE COPYRIGHT HOLDER -AND CONTRIBUTORS "AS IS' AND WITHOUT ANY EXPRESS OR IMPLIED WARRANTIES. -THE IMPLIED WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR -PURPOSE, OR NON-INFRINGEMENT ARE DISCLAIMED TO THE EXTENT PERMITTED BY -YOUR LOCAL LAW. UNLESS REQUIRED BY LAW, NO COPYRIGHT HOLDER OR -CONTRIBUTOR WILL BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, OR -CONSEQUENTIAL DAMAGES ARISING IN ANY WAY OUT OF THE USE OF THE PACKAGE, -EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. +under the terms of either: the GNU General Public License as published +by the Free Software Foundation; or the Artistic License. +See L for more information. =cut diff -Nru youtube-viewer-3.2.0/lib/WWW/YoutubeViewer/Itags.pm youtube-viewer-3.2.4/lib/WWW/YoutubeViewer/Itags.pm --- youtube-viewer-3.2.0/lib/WWW/YoutubeViewer/Itags.pm 2015-12-18 02:45:32.000000000 +0000 +++ youtube-viewer-3.2.4/lib/WWW/YoutubeViewer/Itags.pm 2016-09-04 15:06:02.000000000 +0000 @@ -8,14 +8,6 @@ WWW::YoutubeViewer::Itags - Get the YouTube itags. -=head1 VERSION - -Version 0.04 - -=cut - -our $VERSION = '0.04'; - =head1 SYNOPSIS use WWW::YoutubeViewer::Itags; @@ -277,41 +269,10 @@ Copyright 2012-2015 Trizen. This program is free software; you can redistribute it and/or modify it -under the terms of the the Artistic License (2.0). You may obtain a -copy of the full license at: - -L - -Any use, modification, and distribution of the Standard or Modified -Versions is governed by this Artistic License. By using, modifying or -distributing the Package, you accept this license. Do not use, modify, -or distribute the Package, if you do not accept this license. - -If your Modified Version has been derived from a Modified Version made -by someone other than you, you are nevertheless required to ensure that -your Modified Version complies with the requirements of this license. - -This license does not grant you the right to use any trademark, service -mark, tradename, or logo of the Copyright Holder. - -This license includes the non-exclusive, worldwide, free-of-charge -patent license to make, have made, use, offer to sell, sell, import and -otherwise transfer the Package with respect to any patent claims -licensable by the Copyright Holder that are necessarily infringed by the -Package. If you institute patent litigation (including a cross-claim or -counterclaim) against any party alleging that the Package constitutes -direct or contributory patent infringement, then this Artistic License -to you shall terminate on the date that such litigation is filed. - -Disclaimer of Warranty: THE PACKAGE IS PROVIDED BY THE COPYRIGHT HOLDER -AND CONTRIBUTORS "AS IS' AND WITHOUT ANY EXPRESS OR IMPLIED WARRANTIES. -THE IMPLIED WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR -PURPOSE, OR NON-INFRINGEMENT ARE DISCLAIMED TO THE EXTENT PERMITTED BY -YOUR LOCAL LAW. UNLESS REQUIRED BY LAW, NO COPYRIGHT HOLDER OR -CONTRIBUTOR WILL BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, OR -CONSEQUENTIAL DAMAGES ARISING IN ANY WAY OUT OF THE USE OF THE PACKAGE, -EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. +under the terms of either: the GNU General Public License as published +by the Free Software Foundation; or the Artistic License. +See L for more information. =cut diff -Nru youtube-viewer-3.2.0/lib/WWW/YoutubeViewer/ParseJSON.pm youtube-viewer-3.2.4/lib/WWW/YoutubeViewer/ParseJSON.pm --- youtube-viewer-3.2.0/lib/WWW/YoutubeViewer/ParseJSON.pm 2015-12-18 02:45:32.000000000 +0000 +++ youtube-viewer-3.2.4/lib/WWW/YoutubeViewer/ParseJSON.pm 2016-09-04 15:06:02.000000000 +0000 @@ -8,14 +8,6 @@ WWW::YoutubeViewer::ParseJSON - Parse JSON content. -=head1 VERSION - -Version 0.01 - -=cut - -our $VERSION = '0.01'; - =head1 SYNOPSIS use WWW::YoutubeViewer::ParseJSON; @@ -73,41 +65,10 @@ Copyright 2013-2015 Trizen. This program is free software; you can redistribute it and/or modify it -under the terms of the the Artistic License (2.0). You may obtain a -copy of the full license at: - -L - -Any use, modification, and distribution of the Standard or Modified -Versions is governed by this Artistic License. By using, modifying or -distributing the Package, you accept this license. Do not use, modify, -or distribute the Package, if you do not accept this license. - -If your Modified Version has been derived from a Modified Version made -by someone other than you, you are nevertheless required to ensure that -your Modified Version complies with the requirements of this license. - -This license does not grant you the right to use any trademark, service -mark, tradename, or logo of the Copyright Holder. - -This license includes the non-exclusive, worldwide, free-of-charge -patent license to make, have made, use, offer to sell, sell, import and -otherwise transfer the Package with respect to any patent claims -licensable by the Copyright Holder that are necessarily infringed by the -Package. If you institute patent litigation (including a cross-claim or -counterclaim) against any party alleging that the Package constitutes -direct or contributory patent infringement, then this Artistic License -to you shall terminate on the date that such litigation is filed. - -Disclaimer of Warranty: THE PACKAGE IS PROVIDED BY THE COPYRIGHT HOLDER -AND CONTRIBUTORS "AS IS' AND WITHOUT ANY EXPRESS OR IMPLIED WARRANTIES. -THE IMPLIED WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR -PURPOSE, OR NON-INFRINGEMENT ARE DISCLAIMED TO THE EXTENT PERMITTED BY -YOUR LOCAL LAW. UNLESS REQUIRED BY LAW, NO COPYRIGHT HOLDER OR -CONTRIBUTOR WILL BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, OR -CONSEQUENTIAL DAMAGES ARISING IN ANY WAY OUT OF THE USE OF THE PACKAGE, -EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. +under the terms of either: the GNU General Public License as published +by the Free Software Foundation; or the Artistic License. +See L for more information. =cut diff -Nru youtube-viewer-3.2.0/lib/WWW/YoutubeViewer/ParseXML.pm youtube-viewer-3.2.4/lib/WWW/YoutubeViewer/ParseXML.pm --- youtube-viewer-3.2.0/lib/WWW/YoutubeViewer/ParseXML.pm 2015-12-18 02:45:32.000000000 +0000 +++ youtube-viewer-3.2.4/lib/WWW/YoutubeViewer/ParseXML.pm 2016-09-04 15:06:02.000000000 +0000 @@ -12,14 +12,6 @@ WWW::YoutubeViewer::ParseXML - Convert XML to a HASH ref structure. -=head1 VERSION - -Version 0.04 - -=cut - -our $VERSION = '0.04'; - =head1 SYNOPSIS Parse XML content and return an HASH ref structure. @@ -309,41 +301,10 @@ Copyright 2012-2015 Trizen. This program is free software; you can redistribute it and/or modify it -under the terms of the the Artistic License (2.0). You may obtain a -copy of the full license at: - -L - -Any use, modification, and distribution of the Standard or Modified -Versions is governed by this Artistic License. By using, modifying or -distributing the Package, you accept this license. Do not use, modify, -or distribute the Package, if you do not accept this license. - -If your Modified Version has been derived from a Modified Version made -by someone other than you, you are nevertheless required to ensure that -your Modified Version complies with the requirements of this license. - -This license does not grant you the right to use any trademark, service -mark, tradename, or logo of the Copyright Holder. - -This license includes the non-exclusive, worldwide, free-of-charge -patent license to make, have made, use, offer to sell, sell, import and -otherwise transfer the Package with respect to any patent claims -licensable by the Copyright Holder that are necessarily infringed by the -Package. If you institute patent litigation (including a cross-claim or -counterclaim) against any party alleging that the Package constitutes -direct or contributory patent infringement, then this Artistic License -to you shall terminate on the date that such litigation is filed. - -Disclaimer of Warranty: THE PACKAGE IS PROVIDED BY THE COPYRIGHT HOLDER -AND CONTRIBUTORS "AS IS' AND WITHOUT ANY EXPRESS OR IMPLIED WARRANTIES. -THE IMPLIED WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR -PURPOSE, OR NON-INFRINGEMENT ARE DISCLAIMED TO THE EXTENT PERMITTED BY -YOUR LOCAL LAW. UNLESS REQUIRED BY LAW, NO COPYRIGHT HOLDER OR -CONTRIBUTOR WILL BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, OR -CONSEQUENTIAL DAMAGES ARISING IN ANY WAY OUT OF THE USE OF THE PACKAGE, -EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. +under the terms of either: the GNU General Public License as published +by the Free Software Foundation; or the Artistic License. +See L for more information. =cut diff -Nru youtube-viewer-3.2.0/lib/WWW/YoutubeViewer/PlaylistItems.pm youtube-viewer-3.2.4/lib/WWW/YoutubeViewer/PlaylistItems.pm --- youtube-viewer-3.2.0/lib/WWW/YoutubeViewer/PlaylistItems.pm 2015-12-18 02:45:32.000000000 +0000 +++ youtube-viewer-3.2.4/lib/WWW/YoutubeViewer/PlaylistItems.pm 2016-09-04 15:06:02.000000000 +0000 @@ -6,15 +6,7 @@ =head1 NAME -WWW::YoutubeViewer::PlaylistItems - ... - -=head1 VERSION - -Version 0.01 - -=cut - -our $VERSION = '0.01'; +WWW::YoutubeViewer::PlaylistItems - Manage playlist entries. =head1 SYNOPSIS @@ -73,7 +65,7 @@ sub favorite_video { my ($self, $video_id) = @_; $video_id // return; - my $playlist_id = $self->get_playlist_id('favorites', mine => 'true'); + my $playlist_id = $self->get_playlist_id('favorites', mine => 'true') // return; $self->add_video_to_playlist($playlist_id, $video_id); } @@ -110,13 +102,19 @@ foreach my $name (qw(favorites uploads likes)) { *{__PACKAGE__ . '::' . $name . '_from_username'} = sub { my ($self, $username) = @_; - my $playlist_id = $self->get_playlist_id($name, $username ? (forUsername => $username) : (mine => 'true')); + my $playlist_id = $self->get_playlist_id($name, $username ? (forUsername => $username) : (mine => 'true')) + // return; $self->videos_from_playlist_id($playlist_id); }; *{__PACKAGE__ . '::' . $name} = sub { my ($self, $channel_id) = @_; - my $playlist_id = $self->get_playlist_id($name, $channel_id ? (id => $channel_id) : (mine => 'true')); + my $playlist_id = + $self->get_playlist_id( + $name, ($channel_id and $channel_id ne 'mine') + ? (id => $channel_id) + : (mine => 'true') + ) // return; $self->videos_from_playlist_id($playlist_id); }; } @@ -139,41 +137,10 @@ Copyright 2013-2015 Trizen. This program is free software; you can redistribute it and/or modify it -under the terms of the the Artistic License (2.0). You may obtain a -copy of the full license at: - -L - -Any use, modification, and distribution of the Standard or Modified -Versions is governed by this Artistic License. By using, modifying or -distributing the Package, you accept this license. Do not use, modify, -or distribute the Package, if you do not accept this license. - -If your Modified Version has been derived from a Modified Version made -by someone other than you, you are nevertheless required to ensure that -your Modified Version complies with the requirements of this license. - -This license does not grant you the right to use any trademark, service -mark, tradename, or logo of the Copyright Holder. - -This license includes the non-exclusive, worldwide, free-of-charge -patent license to make, have made, use, offer to sell, sell, import and -otherwise transfer the Package with respect to any patent claims -licensable by the Copyright Holder that are necessarily infringed by the -Package. If you institute patent litigation (including a cross-claim or -counterclaim) against any party alleging that the Package constitutes -direct or contributory patent infringement, then this Artistic License -to you shall terminate on the date that such litigation is filed. - -Disclaimer of Warranty: THE PACKAGE IS PROVIDED BY THE COPYRIGHT HOLDER -AND CONTRIBUTORS "AS IS' AND WITHOUT ANY EXPRESS OR IMPLIED WARRANTIES. -THE IMPLIED WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR -PURPOSE, OR NON-INFRINGEMENT ARE DISCLAIMED TO THE EXTENT PERMITTED BY -YOUR LOCAL LAW. UNLESS REQUIRED BY LAW, NO COPYRIGHT HOLDER OR -CONTRIBUTOR WILL BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, OR -CONSEQUENTIAL DAMAGES ARISING IN ANY WAY OUT OF THE USE OF THE PACKAGE, -EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. +under the terms of either: the GNU General Public License as published +by the Free Software Foundation; or the Artistic License. +See L for more information. =cut diff -Nru youtube-viewer-3.2.0/lib/WWW/YoutubeViewer/Playlists.pm youtube-viewer-3.2.4/lib/WWW/YoutubeViewer/Playlists.pm --- youtube-viewer-3.2.0/lib/WWW/YoutubeViewer/Playlists.pm 2015-12-18 02:45:32.000000000 +0000 +++ youtube-viewer-3.2.4/lib/WWW/YoutubeViewer/Playlists.pm 2016-09-04 15:06:02.000000000 +0000 @@ -8,14 +8,6 @@ WWW::YoutubeViewer::Playlists - Youtube playlists handle. -=head1 VERSION - -Version 0.01 - -=cut - -our $VERSION = '0.01'; - =head1 SYNOPSIS use WWW::YoutubeViewer; @@ -66,7 +58,7 @@ sub playlists { my ($self, $id) = @_; - $self->_get_results($self->_make_playlists_url(channelId => $id)); + $self->_get_results($self->_make_playlists_url(($id and $id ne 'mine') ? (channelId => $id) : (mine => 'true'))); } =head2 playlists_from_username($username) @@ -109,41 +101,10 @@ Copyright 2013-2015 Trizen. This program is free software; you can redistribute it and/or modify it -under the terms of the the Artistic License (2.0). You may obtain a -copy of the full license at: - -L - -Any use, modification, and distribution of the Standard or Modified -Versions is governed by this Artistic License. By using, modifying or -distributing the Package, you accept this license. Do not use, modify, -or distribute the Package, if you do not accept this license. - -If your Modified Version has been derived from a Modified Version made -by someone other than you, you are nevertheless required to ensure that -your Modified Version complies with the requirements of this license. - -This license does not grant you the right to use any trademark, service -mark, tradename, or logo of the Copyright Holder. - -This license includes the non-exclusive, worldwide, free-of-charge -patent license to make, have made, use, offer to sell, sell, import and -otherwise transfer the Package with respect to any patent claims -licensable by the Copyright Holder that are necessarily infringed by the -Package. If you institute patent litigation (including a cross-claim or -counterclaim) against any party alleging that the Package constitutes -direct or contributory patent infringement, then this Artistic License -to you shall terminate on the date that such litigation is filed. - -Disclaimer of Warranty: THE PACKAGE IS PROVIDED BY THE COPYRIGHT HOLDER -AND CONTRIBUTORS "AS IS' AND WITHOUT ANY EXPRESS OR IMPLIED WARRANTIES. -THE IMPLIED WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR -PURPOSE, OR NON-INFRINGEMENT ARE DISCLAIMED TO THE EXTENT PERMITTED BY -YOUR LOCAL LAW. UNLESS REQUIRED BY LAW, NO COPYRIGHT HOLDER OR -CONTRIBUTOR WILL BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, OR -CONSEQUENTIAL DAMAGES ARISING IN ANY WAY OUT OF THE USE OF THE PACKAGE, -EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. +under the terms of either: the GNU General Public License as published +by the Free Software Foundation; or the Artistic License. +See L for more information. =cut diff -Nru youtube-viewer-3.2.0/lib/WWW/YoutubeViewer/RegularExpressions.pm youtube-viewer-3.2.4/lib/WWW/YoutubeViewer/RegularExpressions.pm --- youtube-viewer-3.2.0/lib/WWW/YoutubeViewer/RegularExpressions.pm 2015-12-18 02:45:32.000000000 +0000 +++ youtube-viewer-3.2.4/lib/WWW/YoutubeViewer/RegularExpressions.pm 2016-09-04 15:06:02.000000000 +0000 @@ -11,14 +11,6 @@ WWW::YoutubeViewer::RegularExpressions - Various utils. -=head1 VERSION - -Version 0.01 - -=cut - -our $VERSION = '0.01'; - =head1 SYNOPSIS use WWW::YoutubeViewer::RegularExpressions; @@ -29,13 +21,13 @@ my $opt_begin_chars = q{:;=}; # stdin option valid begin chars # Options -our $range_num_re = qr{^([0-9]{1,2}+)(?>-|\.\.)([0-9]{1,2}+)\z}; +our $range_num_re = qr{^([0-9]{1,2}+)(?>-|\.\.)([0-9]{1,2}+)?\z}; our $digit_or_equal_re = qr{(?(?=[1-9])|=)}; our $non_digit_or_opt_re = qr{^(?!$range_num_re)(?>[0-9]{1,2}[^0-9]|[0-9]{3}|[^0-9$opt_begin_chars])}; # Generic name my $generic_name_re = qr{[a-zA-Z0-9_.\-]{11,34}}; -our $valid_username_re = qr{^(?:\w+(?:[-.]++\w++)*|$generic_name_re)\z}; +our $valid_channel_id_re = qr{^(?:\w+(?:[-.]++\w++)*|$generic_name_re)\z}; # Video ID my $video_id_re = qr{[0-9A-Za-z_\-]{11}}; @@ -57,7 +49,7 @@ $range_num_re $digit_or_equal_re $non_digit_or_opt_re - $valid_username_re + $valid_channel_id_re $valid_video_id_re $get_video_id_re $valid_course_id_re @@ -84,41 +76,10 @@ Copyright 2012-2013 Trizen. This program is free software; you can redistribute it and/or modify it -under the terms of the the Artistic License (2.0). You may obtain a -copy of the full license at: - -L - -Any use, modification, and distribution of the Standard or Modified -Versions is governed by this Artistic License. By using, modifying or -distributing the Package, you accept this license. Do not use, modify, -or distribute the Package, if you do not accept this license. - -If your Modified Version has been derived from a Modified Version made -by someone other than you, you are nevertheless required to ensure that -your Modified Version complies with the requirements of this license. - -This license does not grant you the right to use any trademark, service -mark, tradename, or logo of the Copyright Holder. - -This license includes the non-exclusive, worldwide, free-of-charge -patent license to make, have made, use, offer to sell, sell, import and -otherwise transfer the Package with respect to any patent claims -licensable by the Copyright Holder that are necessarily infringed by the -Package. If you institute patent litigation (including a cross-claim or -counterclaim) against any party alleging that the Package constitutes -direct or contributory patent infringement, then this Artistic License -to you shall terminate on the date that such litigation is filed. - -Disclaimer of Warranty: THE PACKAGE IS PROVIDED BY THE COPYRIGHT HOLDER -AND CONTRIBUTORS "AS IS' AND WITHOUT ANY EXPRESS OR IMPLIED WARRANTIES. -THE IMPLIED WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR -PURPOSE, OR NON-INFRINGEMENT ARE DISCLAIMED TO THE EXTENT PERMITTED BY -YOUR LOCAL LAW. UNLESS REQUIRED BY LAW, NO COPYRIGHT HOLDER OR -CONTRIBUTOR WILL BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, OR -CONSEQUENTIAL DAMAGES ARISING IN ANY WAY OUT OF THE USE OF THE PACKAGE, -EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. +under the terms of either: the GNU General Public License as published +by the Free Software Foundation; or the Artistic License. +See L for more information. =cut diff -Nru youtube-viewer-3.2.0/lib/WWW/YoutubeViewer/Search.pm youtube-viewer-3.2.4/lib/WWW/YoutubeViewer/Search.pm --- youtube-viewer-3.2.0/lib/WWW/YoutubeViewer/Search.pm 2015-12-18 02:45:32.000000000 +0000 +++ youtube-viewer-3.2.4/lib/WWW/YoutubeViewer/Search.pm 2016-09-04 15:06:02.000000000 +0000 @@ -8,14 +8,6 @@ WWW::YoutubeViewer::Search - Search functions for Youtube API v3 -=head1 VERSION - -Version 0.01 - -=cut - -our $VERSION = '0.01'; - =head1 SYNOPSIS use WWW::YoutubeViewer; @@ -173,41 +165,10 @@ Copyright 2013-2015 Trizen. This program is free software; you can redistribute it and/or modify it -under the terms of the the Artistic License (2.0). You may obtain a -copy of the full license at: - -L - -Any use, modification, and distribution of the Standard or Modified -Versions is governed by this Artistic License. By using, modifying or -distributing the Package, you accept this license. Do not use, modify, -or distribute the Package, if you do not accept this license. - -If your Modified Version has been derived from a Modified Version made -by someone other than you, you are nevertheless required to ensure that -your Modified Version complies with the requirements of this license. - -This license does not grant you the right to use any trademark, service -mark, tradename, or logo of the Copyright Holder. - -This license includes the non-exclusive, worldwide, free-of-charge -patent license to make, have made, use, offer to sell, sell, import and -otherwise transfer the Package with respect to any patent claims -licensable by the Copyright Holder that are necessarily infringed by the -Package. If you institute patent litigation (including a cross-claim or -counterclaim) against any party alleging that the Package constitutes -direct or contributory patent infringement, then this Artistic License -to you shall terminate on the date that such litigation is filed. - -Disclaimer of Warranty: THE PACKAGE IS PROVIDED BY THE COPYRIGHT HOLDER -AND CONTRIBUTORS "AS IS' AND WITHOUT ANY EXPRESS OR IMPLIED WARRANTIES. -THE IMPLIED WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR -PURPOSE, OR NON-INFRINGEMENT ARE DISCLAIMED TO THE EXTENT PERMITTED BY -YOUR LOCAL LAW. UNLESS REQUIRED BY LAW, NO COPYRIGHT HOLDER OR -CONTRIBUTOR WILL BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, OR -CONSEQUENTIAL DAMAGES ARISING IN ANY WAY OUT OF THE USE OF THE PACKAGE, -EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. +under the terms of either: the GNU General Public License as published +by the Free Software Foundation; or the Artistic License. +See L for more information. =cut diff -Nru youtube-viewer-3.2.0/lib/WWW/YoutubeViewer/Subscriptions.pm youtube-viewer-3.2.4/lib/WWW/YoutubeViewer/Subscriptions.pm --- youtube-viewer-3.2.0/lib/WWW/YoutubeViewer/Subscriptions.pm 2015-12-18 02:45:32.000000000 +0000 +++ youtube-viewer-3.2.4/lib/WWW/YoutubeViewer/Subscriptions.pm 2016-09-04 15:06:02.000000000 +0000 @@ -8,14 +8,6 @@ WWW::YoutubeViewer::Subscriptions - Subscriptions handler. -=head1 VERSION - -Version 0.01 - -=cut - -our $VERSION = '0.01'; - =head1 SYNOPSIS use WWW::YoutubeViewer; @@ -216,41 +208,10 @@ Copyright 2013-2015 Trizen. This program is free software; you can redistribute it and/or modify it -under the terms of the the Artistic License (2.0). You may obtain a -copy of the full license at: - -L - -Any use, modification, and distribution of the Standard or Modified -Versions is governed by this Artistic License. By using, modifying or -distributing the Package, you accept this license. Do not use, modify, -or distribute the Package, if you do not accept this license. - -If your Modified Version has been derived from a Modified Version made -by someone other than you, you are nevertheless required to ensure that -your Modified Version complies with the requirements of this license. - -This license does not grant you the right to use any trademark, service -mark, tradename, or logo of the Copyright Holder. - -This license includes the non-exclusive, worldwide, free-of-charge -patent license to make, have made, use, offer to sell, sell, import and -otherwise transfer the Package with respect to any patent claims -licensable by the Copyright Holder that are necessarily infringed by the -Package. If you institute patent litigation (including a cross-claim or -counterclaim) against any party alleging that the Package constitutes -direct or contributory patent infringement, then this Artistic License -to you shall terminate on the date that such litigation is filed. - -Disclaimer of Warranty: THE PACKAGE IS PROVIDED BY THE COPYRIGHT HOLDER -AND CONTRIBUTORS "AS IS' AND WITHOUT ANY EXPRESS OR IMPLIED WARRANTIES. -THE IMPLIED WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR -PURPOSE, OR NON-INFRINGEMENT ARE DISCLAIMED TO THE EXTENT PERMITTED BY -YOUR LOCAL LAW. UNLESS REQUIRED BY LAW, NO COPYRIGHT HOLDER OR -CONTRIBUTOR WILL BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, OR -CONSEQUENTIAL DAMAGES ARISING IN ANY WAY OUT OF THE USE OF THE PACKAGE, -EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. +under the terms of either: the GNU General Public License as published +by the Free Software Foundation; or the Artistic License. +See L for more information. =cut diff -Nru youtube-viewer-3.2.0/lib/WWW/YoutubeViewer/Utils.pm youtube-viewer-3.2.4/lib/WWW/YoutubeViewer/Utils.pm --- youtube-viewer-3.2.0/lib/WWW/YoutubeViewer/Utils.pm 2015-12-18 02:45:32.000000000 +0000 +++ youtube-viewer-3.2.4/lib/WWW/YoutubeViewer/Utils.pm 2016-09-04 15:06:02.000000000 +0000 @@ -10,14 +10,6 @@ WWW::YoutubeViewer::Utils - Various utils. -=head1 VERSION - -Version 0.02 - -=cut - -our $VERSION = '0.02'; - =head1 SYNOPSIS use WWW::YoutubeViewer::Utils; @@ -321,7 +313,8 @@ sub get_description { my ($self, $info) = @_; - $info->{snippet}{description} || 'No description available...'; + my $desc = $info->{snippet}{description}; + (defined($desc) and $desc =~ /\S/) ? $desc : 'No description available...'; } =head2 get_title($info) @@ -472,41 +465,10 @@ Copyright 2012-2015 Trizen. This program is free software; you can redistribute it and/or modify it -under the terms of the the Artistic License (2.0). You may obtain a -copy of the full license at: - -L - -Any use, modification, and distribution of the Standard or Modified -Versions is governed by this Artistic License. By using, modifying or -distributing the Package, you accept this license. Do not use, modify, -or distribute the Package, if you do not accept this license. - -If your Modified Version has been derived from a Modified Version made -by someone other than you, you are nevertheless required to ensure that -your Modified Version complies with the requirements of this license. - -This license does not grant you the right to use any trademark, service -mark, tradename, or logo of the Copyright Holder. - -This license includes the non-exclusive, worldwide, free-of-charge -patent license to make, have made, use, offer to sell, sell, import and -otherwise transfer the Package with respect to any patent claims -licensable by the Copyright Holder that are necessarily infringed by the -Package. If you institute patent litigation (including a cross-claim or -counterclaim) against any party alleging that the Package constitutes -direct or contributory patent infringement, then this Artistic License -to you shall terminate on the date that such litigation is filed. - -Disclaimer of Warranty: THE PACKAGE IS PROVIDED BY THE COPYRIGHT HOLDER -AND CONTRIBUTORS "AS IS' AND WITHOUT ANY EXPRESS OR IMPLIED WARRANTIES. -THE IMPLIED WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR -PURPOSE, OR NON-INFRINGEMENT ARE DISCLAIMED TO THE EXTENT PERMITTED BY -YOUR LOCAL LAW. UNLESS REQUIRED BY LAW, NO COPYRIGHT HOLDER OR -CONTRIBUTOR WILL BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, OR -CONSEQUENTIAL DAMAGES ARISING IN ANY WAY OUT OF THE USE OF THE PACKAGE, -EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. +under the terms of either: the GNU General Public License as published +by the Free Software Foundation; or the Artistic License. +See L for more information. =cut diff -Nru youtube-viewer-3.2.0/lib/WWW/YoutubeViewer/VideoCategories.pm youtube-viewer-3.2.4/lib/WWW/YoutubeViewer/VideoCategories.pm --- youtube-viewer-3.2.0/lib/WWW/YoutubeViewer/VideoCategories.pm 2015-12-18 02:45:32.000000000 +0000 +++ youtube-viewer-3.2.4/lib/WWW/YoutubeViewer/VideoCategories.pm 2016-09-04 15:06:02.000000000 +0000 @@ -8,14 +8,6 @@ WWW::YoutubeViewer::VideoCategories - videoCategory resource handler. -=head1 VERSION - -Version 0.01 - -=cut - -our $VERSION = '0.01'; - =head1 SYNOPSIS use WWW::YoutubeViewer; @@ -109,41 +101,10 @@ Copyright 2013-2015 Trizen. This program is free software; you can redistribute it and/or modify it -under the terms of the the Artistic License (2.0). You may obtain a -copy of the full license at: - -L - -Any use, modification, and distribution of the Standard or Modified -Versions is governed by this Artistic License. By using, modifying or -distributing the Package, you accept this license. Do not use, modify, -or distribute the Package, if you do not accept this license. - -If your Modified Version has been derived from a Modified Version made -by someone other than you, you are nevertheless required to ensure that -your Modified Version complies with the requirements of this license. - -This license does not grant you the right to use any trademark, service -mark, tradename, or logo of the Copyright Holder. - -This license includes the non-exclusive, worldwide, free-of-charge -patent license to make, have made, use, offer to sell, sell, import and -otherwise transfer the Package with respect to any patent claims -licensable by the Copyright Holder that are necessarily infringed by the -Package. If you institute patent litigation (including a cross-claim or -counterclaim) against any party alleging that the Package constitutes -direct or contributory patent infringement, then this Artistic License -to you shall terminate on the date that such litigation is filed. - -Disclaimer of Warranty: THE PACKAGE IS PROVIDED BY THE COPYRIGHT HOLDER -AND CONTRIBUTORS "AS IS' AND WITHOUT ANY EXPRESS OR IMPLIED WARRANTIES. -THE IMPLIED WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR -PURPOSE, OR NON-INFRINGEMENT ARE DISCLAIMED TO THE EXTENT PERMITTED BY -YOUR LOCAL LAW. UNLESS REQUIRED BY LAW, NO COPYRIGHT HOLDER OR -CONTRIBUTOR WILL BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, OR -CONSEQUENTIAL DAMAGES ARISING IN ANY WAY OUT OF THE USE OF THE PACKAGE, -EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. +under the terms of either: the GNU General Public License as published +by the Free Software Foundation; or the Artistic License. +See L for more information. =cut diff -Nru youtube-viewer-3.2.0/lib/WWW/YoutubeViewer/Videos.pm youtube-viewer-3.2.4/lib/WWW/YoutubeViewer/Videos.pm --- youtube-viewer-3.2.0/lib/WWW/YoutubeViewer/Videos.pm 2015-12-18 02:45:32.000000000 +0000 +++ youtube-viewer-3.2.4/lib/WWW/YoutubeViewer/Videos.pm 2016-09-04 15:06:02.000000000 +0000 @@ -4,7 +4,19 @@ use 5.014; use warnings; -our $VERSION = '0.01'; +=head1 NAME + +WWW::YoutubeViewer::Videos - videos handler. + +=head1 SYNOPSIS + + use WWW::YoutubeViewer; + my $obj = WWW::YoutubeViewer->new(%opts); + my $info = $obj->video_details($videoID); + +=head1 SUBROUTINES/METHODS + +=cut sub _make_videos_url { my ($self, %opts) = @_; @@ -253,41 +265,10 @@ Copyright 2013-2015 Trizen. This program is free software; you can redistribute it and/or modify it -under the terms of the the Artistic License (2.0). You may obtain a -copy of the full license at: - -L - -Any use, modification, and distribution of the Standard or Modified -Versions is governed by this Artistic License. By using, modifying or -distributing the Package, you accept this license. Do not use, modify, -or distribute the Package, if you do not accept this license. - -If your Modified Version has been derived from a Modified Version made -by someone other than you, you are nevertheless required to ensure that -your Modified Version complies with the requirements of this license. - -This license does not grant you the right to use any trademark, service -mark, tradename, or logo of the Copyright Holder. - -This license includes the non-exclusive, worldwide, free-of-charge -patent license to make, have made, use, offer to sell, sell, import and -otherwise transfer the Package with respect to any patent claims -licensable by the Copyright Holder that are necessarily infringed by the -Package. If you institute patent litigation (including a cross-claim or -counterclaim) against any party alleging that the Package constitutes -direct or contributory patent infringement, then this Artistic License -to you shall terminate on the date that such litigation is filed. - -Disclaimer of Warranty: THE PACKAGE IS PROVIDED BY THE COPYRIGHT HOLDER -AND CONTRIBUTORS "AS IS' AND WITHOUT ANY EXPRESS OR IMPLIED WARRANTIES. -THE IMPLIED WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR -PURPOSE, OR NON-INFRINGEMENT ARE DISCLAIMED TO THE EXTENT PERMITTED BY -YOUR LOCAL LAW. UNLESS REQUIRED BY LAW, NO COPYRIGHT HOLDER OR -CONTRIBUTOR WILL BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, OR -CONSEQUENTIAL DAMAGES ARISING IN ANY WAY OUT OF THE USE OF THE PACKAGE, -EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. +under the terms of either: the GNU General Public License as published +by the Free Software Foundation; or the Artistic License. +See L for more information. =cut diff -Nru youtube-viewer-3.2.0/lib/WWW/YoutubeViewer.pm youtube-viewer-3.2.4/lib/WWW/YoutubeViewer.pm --- youtube-viewer-3.2.0/lib/WWW/YoutubeViewer.pm 2015-12-18 02:45:32.000000000 +0000 +++ youtube-viewer-3.2.4/lib/WWW/YoutubeViewer.pm 2016-09-04 15:06:02.000000000 +0000 @@ -23,13 +23,9 @@ WWW::YoutubeViewer - A very easy interface to YouTube. -=head1 VERSION - -Version 3.2.0 - =cut -our $VERSION = '3.2.0'; +our $VERSION = '3.2.4'; =head1 SYNOPSIS @@ -182,7 +178,7 @@ } state $x = require MIME::Base64; - MIME::Base64::encode_base64(pack('C*', @f, 16, 0)) =~ tr/=//dr; + MIME::Base64::encode_base64(pack('C*', @f, 16, 0)) =~ tr/=\n//dr; } =head2 escape_string($string) @@ -306,6 +302,7 @@ sub lwp_get { my ($self, $url, $simple) = @_; + $url // return; $self->{lwp} // $self->set_lwp_useragent(); my %lwp_header = ($simple ? () : $self->_get_lwp_header); @@ -605,6 +602,11 @@ last; } } + elsif (exists $hash_ref->{hlsvp}) { + $hash_ref->{itag} = 38; + $hash_ref->{type} = 'video/ts'; + $hash_ref->{url} = $hash_ref->{hlsvp}; + } } return @array; @@ -695,7 +697,7 @@ my ($self, $url, $token) = @_; my $pt_url = ( - $url =~ s/[?&]pageToken=\K\w+/$token/ + $url =~ s/[?&]pageToken=\K[^&]+/$token/ ? $url : $self->_append_url_args($url, pageToken => $token) ); diff -Nru youtube-viewer-3.2.0/Makefile.PL youtube-viewer-3.2.4/Makefile.PL --- youtube-viewer-3.2.0/Makefile.PL 2015-12-18 02:45:32.000000000 +0000 +++ youtube-viewer-3.2.4/Makefile.PL 2016-09-04 15:06:02.000000000 +0000 @@ -1,4 +1,4 @@ -# Note: this file was auto-generated by Module::Build::Compat version 0.4214 +# Note: this file was auto-generated by Module::Build::Compat version 0.4220 use ExtUtils::MakeMaker; WriteMakefile ( diff -Nru youtube-viewer-3.2.0/META.json youtube-viewer-3.2.4/META.json --- youtube-viewer-3.2.0/META.json 2015-12-18 02:45:32.000000000 +0000 +++ youtube-viewer-3.2.4/META.json 2016-09-04 15:06:02.000000000 +0000 @@ -4,7 +4,7 @@ "Daniel \"Trizen\" Șuteu " ], "dynamic_config" : 1, - "generated_by" : "Module::Build version 0.4214", + "generated_by" : "Module::Build version 0.422", "license" : [ "perl_5" ], @@ -57,75 +57,58 @@ "provides" : { "WWW::YoutubeViewer" : { "file" : "lib/WWW/YoutubeViewer.pm", - "version" : "v3.2.0" + "version" : "v3.2.4" }, "WWW::YoutubeViewer::Activities" : { - "file" : "lib/WWW/YoutubeViewer/Activities.pm", - "version" : "0.01" + "file" : "lib/WWW/YoutubeViewer/Activities.pm" }, "WWW::YoutubeViewer::Authentication" : { - "file" : "lib/WWW/YoutubeViewer/Authentication.pm", - "version" : "0.01" + "file" : "lib/WWW/YoutubeViewer/Authentication.pm" }, "WWW::YoutubeViewer::Channels" : { - "file" : "lib/WWW/YoutubeViewer/Channels.pm", - "version" : "0.01" + "file" : "lib/WWW/YoutubeViewer/Channels.pm" }, "WWW::YoutubeViewer::CommentThreads" : { - "file" : "lib/WWW/YoutubeViewer/CommentThreads.pm", - "version" : "0.01" + "file" : "lib/WWW/YoutubeViewer/CommentThreads.pm" }, "WWW::YoutubeViewer::GetCaption" : { - "file" : "lib/WWW/YoutubeViewer/GetCaption.pm", - "version" : "0.02" + "file" : "lib/WWW/YoutubeViewer/GetCaption.pm" }, "WWW::YoutubeViewer::GuideCategories" : { - "file" : "lib/WWW/YoutubeViewer/GuideCategories.pm", - "version" : "0.01" + "file" : "lib/WWW/YoutubeViewer/GuideCategories.pm" }, "WWW::YoutubeViewer::Itags" : { - "file" : "lib/WWW/YoutubeViewer/Itags.pm", - "version" : "0.04" + "file" : "lib/WWW/YoutubeViewer/Itags.pm" }, "WWW::YoutubeViewer::ParseJSON" : { - "file" : "lib/WWW/YoutubeViewer/ParseJSON.pm", - "version" : "0.01" + "file" : "lib/WWW/YoutubeViewer/ParseJSON.pm" }, "WWW::YoutubeViewer::ParseXML" : { - "file" : "lib/WWW/YoutubeViewer/ParseXML.pm", - "version" : "0.04" + "file" : "lib/WWW/YoutubeViewer/ParseXML.pm" }, "WWW::YoutubeViewer::PlaylistItems" : { - "file" : "lib/WWW/YoutubeViewer/PlaylistItems.pm", - "version" : "0.01" + "file" : "lib/WWW/YoutubeViewer/PlaylistItems.pm" }, "WWW::YoutubeViewer::Playlists" : { - "file" : "lib/WWW/YoutubeViewer/Playlists.pm", - "version" : "0.01" + "file" : "lib/WWW/YoutubeViewer/Playlists.pm" }, "WWW::YoutubeViewer::RegularExpressions" : { - "file" : "lib/WWW/YoutubeViewer/RegularExpressions.pm", - "version" : "0.01" + "file" : "lib/WWW/YoutubeViewer/RegularExpressions.pm" }, "WWW::YoutubeViewer::Search" : { - "file" : "lib/WWW/YoutubeViewer/Search.pm", - "version" : "0.01" + "file" : "lib/WWW/YoutubeViewer/Search.pm" }, "WWW::YoutubeViewer::Subscriptions" : { - "file" : "lib/WWW/YoutubeViewer/Subscriptions.pm", - "version" : "0.01" + "file" : "lib/WWW/YoutubeViewer/Subscriptions.pm" }, "WWW::YoutubeViewer::Utils" : { - "file" : "lib/WWW/YoutubeViewer/Utils.pm", - "version" : "0.02" + "file" : "lib/WWW/YoutubeViewer/Utils.pm" }, "WWW::YoutubeViewer::VideoCategories" : { - "file" : "lib/WWW/YoutubeViewer/VideoCategories.pm", - "version" : "0.01" + "file" : "lib/WWW/YoutubeViewer/VideoCategories.pm" }, "WWW::YoutubeViewer::Videos" : { - "file" : "lib/WWW/YoutubeViewer/Videos.pm", - "version" : "0.01" + "file" : "lib/WWW/YoutubeViewer/Videos.pm" } }, "release_status" : "stable", @@ -134,6 +117,6 @@ "http://dev.perl.org/licenses/" ] }, - "version" : "v3.2.0", - "x_serialization_backend" : "JSON::PP version 2.27300" + "version" : "v3.2.4", + "x_serialization_backend" : "JSON::PP version 2.27400" } diff -Nru youtube-viewer-3.2.0/META.yml youtube-viewer-3.2.4/META.yml --- youtube-viewer-3.2.0/META.yml 2015-12-18 02:45:32.000000000 +0000 +++ youtube-viewer-3.2.4/META.yml 2016-09-04 15:06:02.000000000 +0000 @@ -7,7 +7,7 @@ configure_requires: Module::Build: '0' dynamic_config: 1 -generated_by: 'Module::Build version 0.4214, CPAN::Meta::Converter version 2.150005' +generated_by: 'Module::Build version 0.422, CPAN::Meta::Converter version 2.150010' license: perl meta-spec: url: http://module-build.sourceforge.net/META-spec-v1.4.html @@ -16,58 +16,41 @@ provides: WWW::YoutubeViewer: file: lib/WWW/YoutubeViewer.pm - version: v3.2.0 + version: v3.2.4 WWW::YoutubeViewer::Activities: file: lib/WWW/YoutubeViewer/Activities.pm - version: '0.01' WWW::YoutubeViewer::Authentication: file: lib/WWW/YoutubeViewer/Authentication.pm - version: '0.01' WWW::YoutubeViewer::Channels: file: lib/WWW/YoutubeViewer/Channels.pm - version: '0.01' WWW::YoutubeViewer::CommentThreads: file: lib/WWW/YoutubeViewer/CommentThreads.pm - version: '0.01' WWW::YoutubeViewer::GetCaption: file: lib/WWW/YoutubeViewer/GetCaption.pm - version: '0.02' WWW::YoutubeViewer::GuideCategories: file: lib/WWW/YoutubeViewer/GuideCategories.pm - version: '0.01' WWW::YoutubeViewer::Itags: file: lib/WWW/YoutubeViewer/Itags.pm - version: '0.04' WWW::YoutubeViewer::ParseJSON: file: lib/WWW/YoutubeViewer/ParseJSON.pm - version: '0.01' WWW::YoutubeViewer::ParseXML: file: lib/WWW/YoutubeViewer/ParseXML.pm - version: '0.04' WWW::YoutubeViewer::PlaylistItems: file: lib/WWW/YoutubeViewer/PlaylistItems.pm - version: '0.01' WWW::YoutubeViewer::Playlists: file: lib/WWW/YoutubeViewer/Playlists.pm - version: '0.01' WWW::YoutubeViewer::RegularExpressions: file: lib/WWW/YoutubeViewer/RegularExpressions.pm - version: '0.01' WWW::YoutubeViewer::Search: file: lib/WWW/YoutubeViewer/Search.pm - version: '0.01' WWW::YoutubeViewer::Subscriptions: file: lib/WWW/YoutubeViewer/Subscriptions.pm - version: '0.01' WWW::YoutubeViewer::Utils: file: lib/WWW/YoutubeViewer/Utils.pm - version: '0.02' WWW::YoutubeViewer::VideoCategories: file: lib/WWW/YoutubeViewer/VideoCategories.pm - version: '0.01' WWW::YoutubeViewer::Videos: file: lib/WWW/YoutubeViewer/Videos.pm - version: '0.01' recommends: JSON::XS: '0' LWP::UserAgent::Cached: '0' @@ -95,5 +78,5 @@ URI::Escape: '0' resources: license: http://dev.perl.org/licenses/ -version: v3.2.0 +version: v3.2.4 x_serialization_backend: 'CPAN::Meta::YAML version 0.018' diff -Nru youtube-viewer-3.2.0/share/gtk-youtube-viewer.glade youtube-viewer-3.2.4/share/gtk-youtube-viewer.glade --- youtube-viewer-3.2.0/share/gtk-youtube-viewer.glade 2015-12-18 02:45:32.000000000 +0000 +++ youtube-viewer-3.2.4/share/gtk-youtube-viewer.glade 2016-09-04 15:06:02.000000000 +0000 @@ -22,16 +22,6 @@ 1 10 - - True - False - emblem-downloads - - - True - False - emblem-downloads - True False @@ -47,41 +37,11 @@ False gtk-missing-image - - True - False - media-playback-start - - - True - False - go-up - - - True - False - go-down - - - True - False - emblem-favorite - True False emblem-documents - - True - False - emblem-downloads - - - True - False - media-skip-forward - True False @@ -92,7 +52,7 @@ False - User's videos + Videos True False image17 @@ -102,7 +62,7 @@ - User's playlists + Playlists True False image14 @@ -122,173 +82,6 @@ - - True - False - video-display - - - True - False - applications-internet - - - True - False - video-x-generic - - - True - False - mail-send - - - True - False - mail-send - - - True - False - mail-send - - - True - False - emblem-favorite - - - True - False - video-display - - - True - False - applications-internet - - - True - False - video-x-generic - - - True - False - - - True - False - application-exit - - - True - False - emblem-favorite - - - True - False - applications-internet - - - True - False - video-x-generic - - - True - False - emblem-favorite - - - True - False - video-display - - - True - False - list-add - - - True - False - video-display - - - True - False - - - True - False - emblem-default - - - True - False - face-smile-big - - - True - False - face-sad - - - True - False - video-x-generic - - - True - False - applications-internet - - - True - False - emblem-favorite - - - True - False - emblem-default - - - True - False - video-display - - - True - False - application-exit - - - True - False - application-exit - - - True - False - emblem-favorite - - - True - False - - - True - False - utilities-terminal - - - True - False - emblem-default - True False @@ -308,26 +101,6 @@ False go-down - - True - False - gtk-missing-image - - - True - False - video-display - - - True - False - edit-delete - - - True - False - emblem-favorite - True False @@ -338,206 +111,20 @@ False dialog-password - - True - False - - - True - False - emblem-favorite - - - True - False - emblem-default - - - True - False - video-display - - - True - False - application-exit - - - True - False - - - True - False - emblem-favorite - - - True - False - emblem-default - - - True - False - video-display - - - True - False - application-exit - - - True - False - applications-internet - - - True - False - emblem-documents - - - True - False - emblem-documents - - - True - False - emblem-documents - - - True - False - video-x-generic - - - True - False - emblem-favorite - True False emblem-important - - True - False - gtk-missing-image - - + True False - gtk-missing-image - 5 - - - True - False - window-new - - - True - False - list-add - - - True - False - - - Show video details - True - False - (CTRL+D) - image8 - False - - - - - - Comments / Ratings - True - False - image30 - False - - - - - - True - False - - - - - Add to playback queue - True - False - image9 - False - - - - - - Play the enqued videos - True - False - image10 - False - - - - - - Play all the video results - True - False - image16 - False - - - - - - True - False - - - - - Play this video in a terminal - True - False - image5 - False - - - - - - Download the selected video - True - False - image15 - False - - - - - - Open the YouTube video page - True - False - image7 - False - - - + applications-internet + + + True + False + mail-send @@ -571,9 +158,13 @@ - + + + + + - + @@ -604,7 +195,7 @@ True False - utilities-terminal + video-display True @@ -633,10 +224,10 @@ False - Users (CTRL+U) + Saved channels True False - Youtube usernames list + See your list of saved channels False @@ -727,10 +318,13 @@ - False @@ -1784,6 +1378,21 @@ + + Audio only + True + True + False + True + + + + True + True + 3 + + + Clear search list True @@ -1795,7 +1404,7 @@ True True - 3 + 4 @@ -2485,25 +2094,22 @@ normal __MAIN__ GTK Youtube Viewer - Copyright © 2010-2015 by Trizen - Written in Perl, Gtk2 and Glade under the GPLv3. + Copyright © 2010-2016 by Trizen + Written in Perl, Gtk2 and Glade. https://github.com/trizen/youtube-viewer https://github.com/trizen/youtube-viewer -Copyright (C) 2010-2015 Trizen <trizenx@gmail.com>. +Copyright (C) 2010-2016 Trizen <trizenx@gmail.com>. -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 free software; you can redistribute it and/or modify it +under the terms of either: the GNU General Public License as published +by the Free Software Foundation; or the Artistic License. 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. +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. -You should have received a copy of the GNU General Public License -along with this program. If not, see <http://www.gnu.org/licenses/>. +See <http://dev.perl.org/licenses/> for more information. [+] Developer/Maintainer: => Trizen (<trizenx@gmail.com>) @@ -2542,7 +2148,7 @@ False 2 - Video Details + Video details True center-on-parent __MAIN__ @@ -2954,11 +2560,12 @@ False - Feeds + YouTube comments True center-on-parent - 640 - 480 + 450 + 400 + True __MAIN__ @@ -2972,14 +2579,12 @@ True False Video feeds + True + fill True - - - - + end - @@ -3025,15 +2630,8 @@ - - - gtk-refresh - True - True - True - True - - + + @@ -3074,6 +2672,7 @@ True True + word True @@ -3094,40 +2693,13 @@ 0 - - - True - False - end - - - Send - True - True - True - image23 - - - - False - False - 0 - - - - - False - False - 1 - - True False - <b>Add a comment to this video:</b> + <b>Write your comment:</b> True @@ -3150,236 +2722,40 @@ True False - + True False - 0 - none + end - - True - False - 12 - - - True - False - start - - - Like - True - True - True - image11 - - - - False - False - 0 - - - - - Dislike - True - True - True - image12 - - - - False - False - 1 - - - - - - - - + + Send True - False - <b>Rate this video:</b> - True - True + True + True + image80 + + + False + False + 0 + - - - False - False - 0 - - - - - True - False - 0 - none - - True - False - 12 - - - True - False - True - - - True - False - - - Add video to favorites - True - True - True - image58 - - - - False - False - 0 - - - - - Subscribe to author's channel - True - True - True - image55 - - - - False - False - 1 - - - - - False - False - 0 - - - - - True - False - - - More videos from this author - True - True - True - image56 - - - - False - False - 0 - - - - - Show author's favorited videos - True - True - True - image74 - - - - False - False - 1 - - - - - False - False - 1 - - - - - True - False - - - Show related videos - True - True - True - image73 - - - - False - False - 0 - - - - - Show author's plalyists - True - True - True - image71 - - - - False - False - 1 - - - - - False - False - 2 - - - - - - - - + + gtk-refresh True - False - <b>Others:</b> - True - True + True + True + True + + + False + False + 1 + - - - False - False - 1 - 1 - - - - - True - False - end gtk-close @@ -3393,14 +2769,14 @@ False False - 0 + 2 False False - 2 + 0 @@ -3412,7 +2788,7 @@ False True - 3 + 1 @@ -3570,7 +2946,7 @@ True False - Connect to your Youtube account + Connect to your YouTube account @@ -3786,7 +3162,7 @@ False - Youtube Usernames + Saved channels center-on-parent 400 300 @@ -3817,19 +3193,49 @@ True False + + True + False + Channel name: + + + True + True + 0 + + + + + True + True + + False + False + True + True + + + + + True + True + 1 + + + True False - Add an username: + Channel ID: False False - 0 + 2 - + True True @@ -3839,27 +3245,27 @@ True True - + True True - 1 + 3 - + gtk-add True True True True - + False False - 2 + 5 @@ -3902,25 +3308,25 @@ True True liststore2 - + Icon - 1 + 3 - Username + Channel - 0 + 1 @@ -3954,7 +3360,7 @@ True True True - + True @@ -3987,11 +3393,6 @@ - - True - False - system-software-update - False 5