diff options
author | trizen <trizen@protonmail.com> | 2020-09-18 19:44:07 +0300 |
---|---|---|
committer | Jesús <heckyel@hyperbola.info> | 2020-09-28 22:17:04 -0500 |
commit | 27774c9579fad5b7595c3f936597307feadaef9d (patch) | |
tree | ccb6664bd6e32a258befeb84f35c1b347b892fff | |
parent | 8caf34c363ee1554787104f1b90a820075833655 (diff) | |
download | fair-viewer-27774c9579fad5b7595c3f936597307feadaef9d.tar.lz fair-viewer-27774c9579fad5b7595c3f936597307feadaef9d.tar.xz fair-viewer-27774c9579fad5b7595c3f936597307feadaef9d.zip |
- Implemented `sort_by` and `date` parameters for `/search`. (https://github.com/iv-org/invidious/wiki/API#get-apiv1search)
In the CLI version, we have:
--order=s # valid values: relevance rating upload_date view_count
--date=s # valid values: hour today week month year
In the GTK3 version, this is implemented in the "Order by" and "Published within" comboboxes.
Also implemented the `--hd`, `--captions` and `--region=s` options.
Signed-off-by: Jesús <heckyel@hyperbola.info>
-rwxr-xr-x | bin/fair-viewer | 289 | ||||
-rwxr-xr-x | bin/gtk-fair-viewer | 353 | ||||
-rw-r--r-- | lib/WWW/FairViewer.pm | 48 | ||||
-rw-r--r-- | lib/WWW/FairViewer/GuideCategories.pm | 4 | ||||
-rw-r--r-- | lib/WWW/FairViewer/Search.pm | 149 | ||||
-rw-r--r-- | lib/WWW/FairViewer/VideoCategories.pm | 4 | ||||
-rw-r--r-- | lib/WWW/FairViewer/Videos.pm | 5 | ||||
-rw-r--r-- | share/gtk-fair-viewer.glade | 41 |
8 files changed, 413 insertions, 480 deletions
diff --git a/bin/fair-viewer b/bin/fair-viewer index ab84393..ff70dea 100755 --- a/bin/fair-viewer +++ b/bin/fair-viewer @@ -36,8 +36,7 @@ See: fair-viewer --help =head1 LICENSE AND COPYRIGHT -Copyright 2013-2015 Trizen. - +Copyright 2010-2020 Trizen. Copyright 2020 Jesus E. This program is free software; you can redistribute it and/or modify it @@ -58,7 +57,7 @@ use 5.016; use warnings; no warnings 'once'; -my $DEVEL; # true in devel mode +my $DEVEL; # true in devel mode use if ($DEVEL = 0), lib => qw(../lib); # devel mode use WWW::FairViewer v1.0.4; @@ -175,7 +174,7 @@ my %CONFIG = ( video_player_selected => ( $constant{win32} ? 'vlc' - : undef # auto-defined + : undef # auto-defined ), # YouTube options @@ -191,16 +190,15 @@ my %CONFIG = ( safeSearch => undef, videoCaption => undef, videoDuration => undef, - videoSyndicated => undef, - publishedBefore => undef, - publishedAfter => undef, - order => undef, - comments_order => 'top', # valid values: top, new + order => undef, + date => undef, + + comments_order => 'top', # valid values: top, new subscriptions_order => 'relevance', # valid values: alphabetical, relevance, unread - hl => 'en_US', - regionCode => undef, + hl => 'en_US', + region => undef, # URI options youtube_video_url => 'https://www.youtube.com/watch?v=%s', @@ -248,13 +246,13 @@ my %CONFIG = ( highlight_watched => 1, highlight_color => 'bold', remove_played_file => 0, - history => undef, # auto-defined + history => undef, # auto-defined history_limit => 100_000, history_file => $history_file, convert_cmd => 'ffmpeg -i *IN* *OUT*', convert_to => undef, - custom_layout => undef, # auto-defined + custom_layout => undef, # auto-defined custom_layout_format => [{width => 3, align => "right", color => "bold", text => "*NO*.",}, {width => "55%", align => "left", color => "bold blue", text => "*TITLE*",}, {width => "15%", align => "left", color => "yellow", text => "*AUTHOR*",}, @@ -536,12 +534,12 @@ sub load_config { dump_configuration($config_file) if $update_config; -foreach my $path($CONFIG{cache_dir}) { - next if -d $path; - require File::Path; - File::Path::make_path($path) - or warn "[!] Can't create path <<$path>>: $!"; -} + foreach my $path ($CONFIG{cache_dir}) { + next if -d $path; + require File::Path; + File::Path::make_path($path) + or warn "[!] Can't create path <<$path>>: $!"; + } @opt{keys %CONFIG} = values(%CONFIG); } @@ -572,7 +570,7 @@ if ($opt{history}) { if (not -d $dir) { require File::Path; File::Path::make_path($dir) - or warn "[!] Can't create path <<$dir>>: $!"; + or warn "[!] Can't create path <<$dir>>: $!"; } open my $fh, '>', $opt{history_file} @@ -602,15 +600,15 @@ if ($opt{history}) { } my $yv_obj = WWW::FairViewer->new( - escape_utf8 => 1, - config_dir => $config_dir, - cache_dir => $opt{cache_dir}, - env_proxy => $opt{env_proxy}, - cookie_file => $opt{cookie_file}, - http_proxy => $opt{http_proxy}, - user_agent => $opt{user_agent}, - timeout => $opt{timeout}, - ); + escape_utf8 => 1, + config_dir => $config_dir, + cache_dir => $opt{cache_dir}, + env_proxy => $opt{env_proxy}, + cookie_file => $opt{cookie_file}, + http_proxy => $opt{http_proxy}, + user_agent => $opt{user_agent}, + timeout => $opt{timeout}, + ); require WWW::FairViewer::Utils; my $yv_utils = WWW::FairViewer::Utils->new(youtube_url_format => $opt{youtube_video_url}, @@ -668,7 +666,6 @@ usage: $execname [options] ([url] | [keywords]) * Trending --trending:s : show trending videos in a given category ID or name - use the `--within=s` option to restrict the results * Channels -sc --channels : search for YouTube channels @@ -681,16 +678,15 @@ usage: $execname [options] ([url] | [keywords]) * Filtering --author=s : search in videos uploaded by a specific user --duration=s : filter search results based on video length - valid values are: short medium long - --caption=s : only videos with/without closed captions - valid values are: any closedCaption none + valid values: short long + --captions! : only videos with or without closed captions --category=s : search only for videos in a specific category name/ID --safe-search=s : YouTube will skip restricted videos for your location valid values are: none moderate strict --order=s : order the results using a specific sorting method - valid values: date rating viewCount title videoCount - --within=s : show only videos uploaded within the specified time - valid values are: Nd, Nw, Nm, Ny, where N is a number + valid values: relevance rating upload_date view_count + --date=s : short videos published in a time period + valid values: hour today week month year --hd! : search only for videos available in at least 720p --vd=s : set the video definition (any, high or standard) --page=i : get results starting with a specific page number @@ -973,22 +969,13 @@ Results: show video comments for a specific video URL or videoID. Command: $execname --results=5 -up=khanacademy -D Results: the most recent 5 videos by a specific author (-up), printed with extra details (-D). -Command: $execname --author=MIT atom -Results: search only in videos by a specific author. - -Command: $execname --author=MIT atom --within=2y -Results: search only in videos by a specific author, published in the last 2 years. - -Command: $execname --popular=MIT --within=6m -Results: show the most popular videos by a specific user, published in the last 6 months. - Command: $execname -S=vsauce Results: get the subscriptions for a username. Command: $execname --page=2 -u=Google Results: show latest videos uploaded by Google, starting with the page number 2. -Command: $execname cats --order=viewCount --duration=short +Command: $execname cats --order=view_count --duration=short Results: search for 'cats' videos, ordered by ViewCount and short duration. Command: $execname --channels math lessons @@ -1094,13 +1081,11 @@ sub apply_configuration { foreach my $option_name ( qw( api_host - videoCaption maxResults order - videoDefinition videoCategoryId + videoCaption + videoDefinition videoDimension videoDuration - videoEmbeddable videoLicense - videoSyndicated channelId - publishedAfter publishedBefore - safeSearch regionCode debug hl + date order + channelId region debug hl http_proxy page comments_order subscriptions_order user_agent cookie_file timeout @@ -1169,18 +1154,6 @@ sub apply_configuration { } } - if (defined $opt->{within}) { - my $value = delete $opt->{within}; - - if ($value =~ /^\s*(\d+(?:\.\d+)?)([dwmy])/i) { - my $date = $yv_utils->period_to_date($1, $2); - $yv_obj->set_publishedAfter($date); - } - else { - warn "\n[!] Invalid value <$value> for option `--within`!\n"; - } - } - if (defined $opt->{more_results}) { $yv_obj->set_maxResults(delete($opt->{more_results}) ? 50 : $CONFIG{maxResults}); } @@ -1488,7 +1461,7 @@ sub parse_arguments { '720p|7' => sub { $opt{resolution} = 720 }, '1080p|1' => sub { $opt{resolution} = 1080 }, - 'hfr!' => \$opt{hfr}, + 'hfr!' => \$opt{hfr}, 'res|resolution=s' => \$opt{resolution}, 'comments=s' => \$opt{get_comments}, @@ -1530,11 +1503,12 @@ sub parse_arguments { 'catlang|cl|hl=s' => \$opt{hl}, 'category|cat-id|cat=s' => \$opt{category_id}, - 'r|region|region-code=s' => \$opt{regionCode}, + 'r|region|region-code=s' => \$opt{region}, + + 'order|order-by|sort|sort-by=s' => \$opt{order}, + 'date=s' => \$opt{date}, - 'orderby|order|order-by=s' => \$opt{order}, - 'duration=s' => \$opt{videoDuration}, - 'within=s' => \$opt{within}, + 'duration=s' => \$opt{videoDuration}, 'max-seconds|max_seconds=i' => \$opt{max_seconds}, 'min-seconds|min_seconds=i' => \$opt{min_seconds}, @@ -1588,7 +1562,7 @@ sub parse_arguments { 'colorful|colourful|C!' => \$opt{results_with_colors}, 'details|D!' => \$opt{results_with_details}, 'fixed-width|W|fw!' => \$opt{results_fixed_width}, - 'caption=s' => \$opt{videoCaption}, + 'captions!' => \$opt{videoCaption}, 'fullscreen|fs|f!' => \$opt{fullscreen}, 'dash!' => \$opt{dash_support}, 'confirm!' => \$opt{confirm}, @@ -1936,14 +1910,18 @@ sub get_user_input { } my $input = unpack( - 'A*', defined($opt{std_input}) - ? delete($opt{std_input}) - : (do { - my @lines = split(/\R/, $text); - say for @lines[0..$#lines-1]; - $term->readline($lines[-1]); - } // return ':return') - ) =~ s/^\s+//r; + 'A*', + defined($opt{std_input}) + ? delete($opt{std_input}) + : ( + do { + my @lines = split(/\R/, $text); + say for @lines[0 .. $#lines - 1]; + $term->readline($lines[-1]); + } + // return ':return' + ) + ) =~ s/^\s+//r; return q{:next} if $input eq q{}; # <ENTER> for the next page @@ -2116,9 +2094,9 @@ sub get_and_play_video_ids { ## OK } else { - $info->{title} = "unknwon"; + $info->{title} = "unknwon"; $info->{lengthSeconds} = 0; - $info->{videoId} = $id; + $info->{videoId} = $id; warn_cant_do('get info for', $id); } @@ -2262,12 +2240,12 @@ sub general_options { my $results = $args{res}; my $info = $args{info}; - my $token = undef; + my $token = undef; my $has_token = 0; if (ref($info->{results}) eq 'HASH' and exists $info->{results}{continuation}) { $has_token = 1; - $token = $info->{results}{continuation}; + $token = $info->{results}{continuation}; } if (not defined($option)) { @@ -2524,7 +2502,7 @@ sub print_channels { } my $url = $results->{url}; - my $channels = $results->{results} // []; + my $channels = $results->{results} // []; foreach my $i (0 .. $#{$channels}) { my $channel = $channels->[$i]; @@ -2546,7 +2524,7 @@ sub print_channels { print "\n" if $i == 0; printf("%s. %s (%s)\n", colored(sprintf('%2d', $i + 1), 'bold'), - colored($yv_utils->get_channel_title($channel), 'blue'), + colored($yv_utils->get_channel_title($channel), 'blue'), colored($yv_utils->get_publication_date($channel), 'magenta'), ); } @@ -2641,7 +2619,7 @@ sub print_comments { my $i = 0; foreach my $comment (@{$comments}) { - my $comment_id = $yv_utils->get_comment_id($comment); + my $comment_id = $yv_utils->get_comment_id($comment); my $comment_age = $yv_utils->get_publication_age_approx($comment); printf( @@ -2660,23 +2638,23 @@ sub print_comments { ); #~ if (exists $comment->{replies}) { - #~ foreach my $reply (reverse @{$comment->{replies}{comments}}) { - #~ my $reply_age = $yv_utils->date_to_age($reply->{snippet}{publishedAt}); - #~ printf( - #~ "\n %s (%s) replied:\n%s\n", - #~ colored($reply->{snippet}{authorDisplayName}, 'bold'), - #~ ( - #~ $reply_age =~ /sec|min|hour|day/ - #~ ? "$reply_age ago" - #~ : $yv_utils->format_date($reply->{snippet}{publishedAt}) - #~ ), - #~ wrap_text( - #~ i_tab => q{ } x 6, - #~ s_tab => q{ } x 6, - #~ text => [$reply->{snippet}{textDisplay} // 'Empty comment...'] - #~ ), - #~ ); - #~ } + #~ foreach my $reply (reverse @{$comment->{replies}{comments}}) { + #~ my $reply_age = $yv_utils->date_to_age($reply->{snippet}{publishedAt}); + #~ printf( + #~ "\n %s (%s) replied:\n%s\n", + #~ colored($reply->{snippet}{authorDisplayName}, 'bold'), + #~ ( + #~ $reply_age =~ /sec|min|hour|day/ + #~ ? "$reply_age ago" + #~ : $yv_utils->format_date($reply->{snippet}{publishedAt}) + #~ ), + #~ wrap_text( + #~ i_tab => q{ } x 6, + #~ s_tab => q{ } x 6, + #~ text => [$reply->{snippet}{textDisplay} // 'Empty comment...'] + #~ ), + #~ ); + #~ } #~ } } @@ -3047,12 +3025,12 @@ sub get_streaming_url { if (ref($captions) eq 'ARRAY' and @$captions and $opt{get_captions} and not $opt{novideo}) { require WWW::FairViewer::GetCaption; my $yv_cap = WWW::FairViewer::GetCaption->new( - auto_captions => $opt{auto_captions}, - captions_dir => $opt{cache_dir}, - captions => $captions, - languages => $CONFIG{srt_languages}, - yv_obj => $yv_obj, - ); + auto_captions => $opt{auto_captions}, + captions_dir => $opt{cache_dir}, + captions => $captions, + languages => $CONFIG{srt_languages}, + yv_obj => $yv_obj, + ); $srt_file = $yv_cap->save_caption($video_id); } @@ -3076,7 +3054,7 @@ sub get_streaming_url { resolution => ($opt{novideo} ? 'audio' : $opt{resolution}), hfr => $opt{hfr}, dash => $dash, - dash_mp4_audio => ($opt{novideo} ? 1 : $opt{dash_mp4_audio}), + dash_mp4_audio => ($opt{novideo} ? 1 : $opt{dash_mp4_audio}), dash_segmented => ($opt{download_video} ? 0 : $opt{dash_segmented}), ); @@ -3568,23 +3546,26 @@ sub print_video_info { $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]) } - grep { defined($_->[1]) and $_->[1] !~ /^(0|unknown)\z/i } ( - ['Channel' => $yv_utils->get_channel_title($video)], - ['ChannelID' => $yv_utils->get_channel_id($video)], - ['VideoID' => $yv_utils->get_video_id($video)], - ['Category' => $yv_utils->get_category_name($video)], - ['Definition' => $yv_utils->get_definition($video)], - ['Duration' => $yv_utils->get_time($video)], - ['Likes' => $yv_utils->set_thousands($yv_utils->get_likes($video))], - ['Dislikes' => $yv_utils->set_thousands($yv_utils->get_dislikes($video))], - ['Views' => $yv_utils->set_thousands($yv_utils->get_views($video))], - ['Published' => $yv_utils->get_publication_date($video)], - ) - ), - "$hr\n"); + 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]) } + grep { defined($_->[1]) and $_->[1] !~ /^(0|unknown)\z/i } ( + ['Channel' => $yv_utils->get_channel_title($video)], + ['ChannelID' => $yv_utils->get_channel_id($video)], + ['VideoID' => $yv_utils->get_video_id($video)], + ['Category' => $yv_utils->get_category_name($video)], + ['Definition' => $yv_utils->get_definition($video)], + ['Duration' => $yv_utils->get_time($video)], + ['Likes' => $yv_utils->set_thousands($yv_utils->get_likes($video))], + ['Dislikes' => $yv_utils->set_thousands($yv_utils->get_dislikes($video))], + ['Views' => $yv_utils->set_thousands($yv_utils->get_views($video))], + ['Published' => $yv_utils->get_publication_date($video)], + ) + ), + "$hr\n" + ); return 1; } @@ -3620,24 +3601,24 @@ sub print_videos { #my $videos = $info->{items} // []; #~ foreach my $entry (@$videos) { - #~ if ($yv_utils->is_activity($entry)) { - #~ my $type = $entry->{snippet}{type}; - - #~ if ($type eq 'upload') { - #~ $entry->{kind} = 'youtube#video'; - #~ $entry->{id} = $entry->{contentDetails}{upload}{videoId}; - #~ } - - #~ if ($type eq 'playlistItem') { - #~ $entry->{kind} = 'youtube#video'; - #~ $entry->{id} = $entry->{contentDetails}{playlistItem}{resourceId}{videoId}; - #~ } - - #~ if ($type eq 'bulletin' and $entry->{contentDetails}{bulletin}{resourceId}{kind} eq 'youtube#video') { - #~ $entry->{kind} = 'youtube#video'; - #~ $entry->{id} = $entry->{contentDetails}{bulletin}{resourceId}{videoId}; - #~ } - #~ } + #~ if ($yv_utils->is_activity($entry)) { + #~ my $type = $entry->{snippet}{type}; + + #~ if ($type eq 'upload') { + #~ $entry->{kind} = 'youtube#video'; + #~ $entry->{id} = $entry->{contentDetails}{upload}{videoId}; + #~ } + + #~ if ($type eq 'playlistItem') { + #~ $entry->{kind} = 'youtube#video'; + #~ $entry->{id} = $entry->{contentDetails}{playlistItem}{resourceId}{videoId}; + #~ } + + #~ if ($type eq 'bulletin' and $entry->{contentDetails}{bulletin}{resourceId}{kind} eq 'youtube#video') { + #~ $entry->{kind} = 'youtube#video'; + #~ $entry->{id} = $entry->{contentDetails}{bulletin}{resourceId}{videoId}; + #~ } + #~ } #~ } #<<< @@ -3657,16 +3638,16 @@ sub print_videos { #~ if (@{$videos} and not $results->{has_extra_info}) { - #~ my @video_ids = grep { defined } map { $yv_utils->get_video_id($_) } @{$videos}; - #~ my $content_details = $yv_obj->video_details(join(',', @video_ids), VIDEO_PART); - #~ my $video_details = $content_details->{results}{items}; + #~ my @video_ids = grep { defined } map { $yv_utils->get_video_id($_) } @{$videos}; + #~ my $content_details = $yv_obj->video_details(join(',', @video_ids), VIDEO_PART); + #~ my $video_details = $content_details->{results}{items}; - #~ foreach my $i (0 .. $#{$videos}) { - #~ @{$videos->[$i]}{qw(id contentDetails statistics snippet)} = - #~ @{$video_details->[$i]}{qw(id contentDetails statistics snippet)}; - #~ } + #~ foreach my $i (0 .. $#{$videos}) { + #~ @{$videos->[$i]}{qw(id contentDetails statistics snippet)} = + #~ @{$video_details->[$i]}{qw(id contentDetails statistics snippet)}; + #~ } - #~ $results->{has_extra_info} = 1; + #~ $results->{has_extra_info} = 1; #~ } #<<< @@ -3795,7 +3776,7 @@ sub print_videos { 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->get_time($video), + $yv_utils->get_channel_title($video), $yv_utils->get_time($video), ); } } @@ -3824,7 +3805,7 @@ sub print_videos { ) { if ($opt{play_backwards}) { if (defined($url)) { - __SUB__->($yv_obj->previous_page($url), auto => 1); + __SUB__->($yv_obj->previous_page($url), auto => 1); } else { $opt{play_backwards} = 0; diff --git a/bin/gtk-fair-viewer b/bin/gtk-fair-viewer index f8f40d5..593e929 100755 --- a/bin/gtk-fair-viewer +++ b/bin/gtk-fair-viewer @@ -29,7 +29,7 @@ use 5.016; use warnings; no warnings 'once'; -my $DEVEL; # true in devel mode +my $DEVEL; # true in devel mode use if ($DEVEL = 0), lib => qw(../lib); # devel only use WWW::FairViewer v1.0.4; @@ -54,9 +54,9 @@ my $version = $WWW::FairViewer::VERSION; # Share directory my $share_dir = - ($DEVEL and -d "../share") - ? '../share' - : do { require File::ShareDir; File::ShareDir::dist_dir('WWW-FairViewer') }; + ($DEVEL and -d "../share") + ? '../share' + : do { require File::ShareDir; File::ShareDir::dist_dir('WWW-FairViewer') }; # Configuration dir/file my $home_dir; @@ -184,25 +184,21 @@ my %CONFIG = ( hpaned_position => 420, # Fair options - dash_support => 1, - dash_mp4_audio => 1, - dash_segmented => 1, # may load slow - prefer_mp4 => 0, - prefer_av1 => 0, - maxResults => 10, - hfr => 1, # true to prefer high frame rate (HFR) videos - resolution => 'best', - videoDimension => undef, - videoEmbeddable => undef, - videoLicense => undef, - videoSyndicated => undef, - publishedBefore => undef, - publishedAfter => undef, - hl => 'en_US', - regionCode => undef, + dash_support => 1, + dash_mp4_audio => 1, + dash_segmented => 1, # may load slow + prefer_mp4 => 0, + prefer_av1 => 0, + maxResults => 10, + hfr => 1, # true to prefer high frame rate (HFR) videos + resolution => 'best', + videoDimension => undef, + videoLicense => undef, + hl => 'en_US', + region => undef, comments_width => 80, # wrap comments longer than `n` characters - comments_order => 'top', # valid values: time, relevance + comments_order => 'top', # valid values: time, relevance # API api_host => "auto", @@ -231,7 +227,7 @@ my %CONFIG = ( audio_only => 0, tooltips => 1, - tooltip_max_len => 512, # max length of description in tooltips + tooltip_max_len => 512, # max length of description in tooltips thousand_separator => q{,}, downloads_dir => curdir(), @@ -356,7 +352,6 @@ my %objects = ( 'channels_checkbox' => \my $search_for_channels_checkbox, 'spinbutton1' => \my $spin_results, 'spinbutton2' => \my $spin_start_with_page, - 'spinbutton3' => \my $spin_published_within, 'thumbs_checkbutton' => \my $thumbs_checkbutton, 'fullscreen_checkbutton' => \my $fullscreen_checkbutton, 'clear_list_checkbutton' => \my $clear_list_checkbutton, @@ -467,7 +462,7 @@ if (not defined $CONFIG{cache_dir}) { $CONFIG{cache_dir} = catdir($cache_dir, 'fair-viewer'); } -foreach my $path($CONFIG{cache_dir}) { +foreach my $path ($CONFIG{cache_dir}) { next if -d $path; require File::Path; File::Path::make_path($path) @@ -808,15 +803,15 @@ my %ResultsHistory = ( $CONFIG{fair_viewer} //= which_command('fair-viewer') // 'fair-viewer'; my $yv_obj = WWW::FairViewer->new( - escape_utf8 => 1, - config_dir => $config_dir, - hl => $CONFIG{hl}, - env_proxy => $CONFIG{env_proxy}, - cache_dir => $CONFIG{cache_dir}, - cookie_file => $CONFIG{cookie_file}, - user_agent => $CONFIG{user_agent}, - timeout => $CONFIG{timeout}, - ); + escape_utf8 => 1, + config_dir => $config_dir, + hl => $CONFIG{hl}, + env_proxy => $CONFIG{env_proxy}, + cache_dir => $CONFIG{cache_dir}, + cookie_file => $CONFIG{cookie_file}, + user_agent => $CONFIG{user_agent}, + timeout => $CONFIG{timeout}, + ); #$yv_obj->load_authentication_tokens(); @@ -866,9 +861,8 @@ sub apply_configuration { api_host videoSyndicated comments_order maxResults videoDimension - videoEmbeddable videoLicense - publishedAfter publishedBefore - regionCode videoCategoryId + videoLicense + region videoCategoryId debug http_proxy user_agent timeout cookie_file ) @@ -1426,8 +1420,8 @@ $accel->connect(ord('g'), ['control-mask'], ['visible'], \&show_user_favorited_v $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); +$accel->connect(0xffff, ['lock-mask'], ['visible'], \&delete_selected_row); +$accel->connect(0xffc8, ['lock-mask'], ['visible'], \&maximize_unmaximize_mainw); $mainw->add_accel_group($accel); # Support for navigating back and forth using the side buttons of the mouse @@ -1456,7 +1450,7 @@ $accel->connect(0xff1b, ['lock-mask'], ['visible'], \&hide_feeds_window); $feeds_window->add_accel_group($accel); $accel = Gtk3::AccelGroup->new; -$accel->connect(0xff1b, ['lock-mask'], ['visible'], \&hide_preferences_window); +$accel->connect(0xff1b, ['lock-mask'], ['visible'], \&hide_preferences_window); $accel->connect(ord('s'), ['control-mask'], ['visible'], \&save_configuration); $prefernces_window->add_accel_group($accel); @@ -1700,25 +1694,10 @@ sub combobox_published_within_changed { my $period = $published_within_combobox->get_active_text; if ($period =~ /^any/) { - $spin_published_within->hide; + $yv_obj->set_date(undef); } else { - $spin_published_within->show; - } - - spin_published_within_changed(); -} - -sub spin_published_within_changed { - my $period = $published_within_combobox->get_active_text; - - if ($period =~ /^any/) { - $yv_obj->set_publishedAfter(undef); - } - else { - my $amount = $spin_published_within->get_value; - my $date = $yv_utils->period_to_date($amount, $period); - $yv_obj->set_publishedAfter($date); + $yv_obj->set_date($period); } } @@ -2030,8 +2009,8 @@ sub set_youtube_tops { } sub remove_selected_user { - my $selection = $users_treeview->get_selection // return; - my $iter = $selection->get_selected // return; + 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); @@ -2278,8 +2257,6 @@ sub search { append_to_history($keywords, 1); } - spin_published_within_changed(); - # Set the username my $username = $from_author_entry->get_text; @@ -2513,7 +2490,8 @@ sub get_pixbuf_thumbnail_from_entry { sub display_results { my ($results, $from_history) = @_; - my $url = $results->{url}; + my $url = $results->{url}; + #my $info = $results->{results} // {}; my $items = $results->{results} // []; @@ -2538,11 +2516,10 @@ sub display_results { my $current_instance = $yv_obj->get_api_host(); $yv_obj->pick_and_set_random_instance(); # set a random invidious instance - die - "Probably $current_instance is down.\n" - . "\nTry changing the `api_host` in configuration file:\n\n" - . qq{\tapi_host => "auto",\n} - . qq{\nSee also: https://libregit.org/heckyel/fair-viewer#invidious-instances\n}; + die "Probably $current_instance is down.\n" + . "\nTry changing the `api_host` in configuration file:\n\n" + . qq{\tapi_host => "auto",\n} + . qq{\nSee also: https://libregit.org/heckyel/fair-viewer#invidious-instances\n}; } if (not $yv_utils->has_entries($results)) { @@ -2555,68 +2532,68 @@ sub display_results { #~ if (not $from_history) { - #~ foreach my $entry (@$items) { - #~ if ($yv_utils->is_activity($entry)) { - #~ my $type = $entry->{snippet}{type}; - - #~ if ($type eq 'upload') { - #~ $entry->{kind} = 'youtube#video'; - #~ $entry->{id} = $entry->{contentDetails}{upload}{videoId}; - #~ } - - #~ if ($type eq 'playlistItem') { - #~ $entry->{kind} = 'youtube#video'; - #~ $entry->{id} = $entry->{contentDetails}{playlistItem}{resourceId}{videoId}; - #~ } - - #~ if ($type eq 'subscription') { - #~ $entry->{kind} = 'youtube#channel'; - #~ $entry->{snippet}{title} = $entry->{snippet}{channelTitle}; - #~ $entry->{snippet}{channelId} = $entry->{contentDetails}{subscription}{resourceId}{channelId}; - #~ } - - #~ if ($type eq 'bulletin' and $entry->{contentDetails}{bulletin}{resourceId}{kind} eq 'youtube#video') { - #~ $entry->{kind} = 'youtube#video'; - #~ $entry->{id} = $entry->{contentDetails}{bulletin}{resourceId}{videoId}; - #~ } - #~ } - #~ } + #~ foreach my $entry (@$items) { + #~ if ($yv_utils->is_activity($entry)) { + #~ my $type = $entry->{snippet}{type}; - #~ my @video_ids; - #~ my @playlist_ids; + #~ if ($type eq 'upload') { + #~ $entry->{kind} = 'youtube#video'; + #~ $entry->{id} = $entry->{contentDetails}{upload}{videoId}; + #~ } - #~ foreach my $i (0 .. $#{$items}) { - #~ my $item = $items->[$i]; + #~ if ($type eq 'playlistItem') { + #~ $entry->{kind} = 'youtube#video'; + #~ $entry->{id} = $entry->{contentDetails}{playlistItem}{resourceId}{videoId}; + #~ } - #~ if ($yv_utils->is_playlist($item)) { - #~ push @playlist_ids, $yv_utils->get_playlist_id($item); - #~ } - #~ elsif ($yv_utils->is_video($item)) { - #~ push @video_ids, $yv_utils->get_video_id($item); - #~ } - #~ } + #~ if ($type eq 'subscription') { + #~ $entry->{kind} = 'youtube#channel'; + #~ $entry->{snippet}{title} = $entry->{snippet}{channelTitle}; + #~ $entry->{snippet}{channelId} = $entry->{contentDetails}{subscription}{resourceId}{channelId}; + #~ } - #~ my %id_lookup; + #~ if ($type eq 'bulletin' and $entry->{contentDetails}{bulletin}{resourceId}{kind} eq 'youtube#video') { + #~ $entry->{kind} = 'youtube#video'; + #~ $entry->{id} = $entry->{contentDetails}{bulletin}{resourceId}{videoId}; + #~ } + #~ } + #~ } - #~ if (@video_ids) { - #~ my $content_details = $yv_obj->video_details(join(',', @video_ids), VIDEO_PART); - #~ my $video_details = $content_details->{results}{items}; + #~ my @video_ids; + #~ my @playlist_ids; - #~ foreach my $i (0 .. $#video_ids) { - #~ $id_lookup{$video_ids[$i]} = $video_details->[$i]; - #~ } - #~ } + #~ foreach my $i (0 .. $#{$items}) { + #~ my $item = $items->[$i]; - #~ if (@playlist_ids) { - #~ my $content_details = $yv_obj->playlist_from_id(join(',', @playlist_ids), 'contentDetails'); - #~ my $playlist_details = $content_details->{results}{items}; + #~ if ($yv_utils->is_playlist($item)) { + #~ push @playlist_ids, $yv_utils->get_playlist_id($item); + #~ } + #~ elsif ($yv_utils->is_video($item)) { + #~ push @video_ids, $yv_utils->get_video_id($item); + #~ } + #~ } - #~ foreach my $i (0 .. $#playlist_ids) { - #~ $id_lookup{$playlist_ids[$i]} = $playlist_details->[$i]; - #~ } - #~ } + #~ my %id_lookup; - #~ $info->{__extra_info__} = \%id_lookup; + #~ if (@video_ids) { + #~ my $content_details = $yv_obj->video_details(join(',', @video_ids), VIDEO_PART); + #~ my $video_details = $content_details->{results}{items}; + + #~ foreach my $i (0 .. $#video_ids) { + #~ $id_lookup{$video_ids[$i]} = $video_details->[$i]; + #~ } + #~ } + + #~ if (@playlist_ids) { + #~ my $content_details = $yv_obj->playlist_from_id(join(',', @playlist_ids), 'contentDetails'); + #~ my $playlist_details = $content_details->{results}{items}; + + #~ foreach my $i (0 .. $#playlist_ids) { + #~ $id_lookup{$playlist_ids[$i]} = $playlist_details->[$i]; + #~ } + #~ } + + #~ $info->{__extra_info__} = \%id_lookup; #~ } foreach my $i (0 .. $#{$items}) { @@ -2627,8 +2604,8 @@ sub display_results { #~ my $playlist_id = $yv_utils->get_playlist_id($item) || next; #~ if (exists($info->{__extra_info__}{$playlist_id})) { - #~ @{$item}{qw(contentDetails)} = - #~ @{$info->{__extra_info__}{$playlist_id}}{qw(contentDetails)}; + #~ @{$item}{qw(contentDetails)} = + #~ @{$info->{__extra_info__}{$playlist_id}}{qw(contentDetails)}; #~ } add_playlist_entry($item); @@ -2644,8 +2621,8 @@ sub display_results { #~ my $video_id = $yv_utils->get_video_id($item) || next; #~ if (exists($info->{__extra_info__}{$video_id})) { - #~ @{$item}{qw(id contentDetails statistics snippet)} = - #~ @{$info->{__extra_info__}{$video_id}}{qw(id contentDetails statistics snippet)}; + #~ @{$item}{qw(id contentDetails statistics snippet)} = + #~ @{$info->{__extra_info__}{$video_id}}{qw(id contentDetails statistics snippet)}; #~ } # Filter out private or deleted videos @@ -2668,7 +2645,7 @@ sub display_results { if (ref($results->{results}) eq 'HASH' and exists($results->{results}{continuation})) { if (defined $results->{results}{continuation}) { - append_next_page($url, $results->{results}{continuation}); + append_next_page($url, $results->{results}{continuation}); } } else { @@ -3017,12 +2994,12 @@ sub get_streaming_url { if (ref($captions) eq 'ARRAY' and @$captions and $CONFIG{get_captions}) { require WWW::FairViewer::GetCaption; my $yv_cap = WWW::FairViewer::GetCaption->new( - auto_captions => $CONFIG{auto_captions}, - captions_dir => $CONFIG{cache_dir}, - captions => $captions, - languages => $CONFIG{srt_languages}, - yv_obj => $yv_obj, - ); + auto_captions => $CONFIG{auto_captions}, + captions_dir => $CONFIG{cache_dir}, + captions => $captions, + languages => $CONFIG{srt_languages}, + yv_obj => $yv_obj, + ); $srt_file = $yv_cap->save_caption($video_id); } @@ -3205,10 +3182,10 @@ sub get_options_as_arguments { 'no-interactive' => q{}, 'resolution' => $CONFIG{resolution}, 'download-dir' => quotemeta(rel2abs($CONFIG{downloads_dir})), - 'fullscreen' => $CONFIG{fullscreen} ? q{} : undef, + 'fullscreen' => $CONFIG{fullscreen} ? q{} : undef, 'no-dash' => $CONFIG{dash_support} ? undef : q{}, - 'no-video' => $CONFIG{audio_only} ? q{} : undef, - 'resolution=audio' => $CONFIG{audio_only} ? q{} : undef, + 'no-video' => $CONFIG{audio_only} ? q{} : undef, + 'resolution=audio' => $CONFIG{audio_only} ? q{} : undef, ); while (my ($argv, $value) = each %options) { @@ -3312,7 +3289,7 @@ sub execute_cli_fair_viewer { $CONFIG{terminal_exec}, join(q{ }, $CONFIG{fair_viewer}, get_options_as_arguments(), - @arguments, @{$CONFIG{fair_viewer_args}}), + @arguments, @{$CONFIG{fair_viewer_args}}), ) ); my $code = execute_external_program($command); @@ -3411,9 +3388,9 @@ sub display_comments { return 1 if ref($results) ne 'HASH'; - my $url = $results->{url}; - my $video_id = $results->{results}{videoId}; - my $comments = $results->{results}{comments} // []; + my $url = $results->{url}; + my $video_id = $results->{results}{videoId}; + my $comments = $results->{results}{comments} // []; my $continuation = $results->{results}{continuation}; foreach my $comment (@{$comments}) { @@ -3422,7 +3399,7 @@ sub display_comments { #pp $comment; #my $comment_age = $yv_utils->date_to_age($snippet->{publishedAt}); - my $comment_id = $yv_utils->get_comment_id($comment); + my $comment_id = $yv_utils->get_comment_id($comment); my $comment_age = $yv_utils->get_publication_age_approx($comment); my $comment_text = reflow_text( @@ -3436,12 +3413,12 @@ sub display_comments { ) . ") commented:</big>\n" . encode_entities( - wrap_text( - i_tab => "\t", - s_tab => "\t", - text => [$yv_utils->get_comment_content($comment) // 'Empty comment...'], - ) - ) + wrap_text( + i_tab => "\t", + s_tab => "\t", + text => [$yv_utils->get_comment_content($comment) // 'Empty comment...'], + ) + ) ); my $iter = $feeds_liststore->append; @@ -3453,39 +3430,39 @@ sub display_comments { ); #~ if (exists $comment->{replies}) { - #~ foreach my $reply (reverse @{$comment->{replies}{comments}}) { - #~ my $reply_age = $yv_utils->date_to_age($reply->{snippet}{publishedAt}); - #~ my $reply_text = reflow_text( - #~ "\t<big><b>" - #~ . encode_entities($reply->{snippet}{authorDisplayName}) - #~ . "</b> (" - #~ . ( - #~ $reply_age =~ /sec|min|hour|day/ - #~ ? "$reply_age ago" - #~ : $yv_utils->format_date($reply->{snippet}{publishedAt}) - #~ ) - #~ . ") replied:</big>\n" - #~ . encode_entities( - #~ wrap_text( - #~ i_tab => "\t\t", - #~ s_tab => "\t\t", - #~ text => [$reply->{snippet}{textDisplay} // 'Empty comment...'] - #~ ) - #~ ) - #~ ); - - #~ my $iter = $feeds_liststore->append; - #~ $feeds_liststore->set( - #~ $iter, - #~ 0 => $reply_text, - #~ 3 => $reply->{snippet}{videoId}, - #~ 4 => $reply->{id}, - #~ ); - #~ } + #~ foreach my $reply (reverse @{$comment->{replies}{comments}}) { + #~ my $reply_age = $yv_utils->date_to_age($reply->{snippet}{publishedAt}); + #~ my $reply_text = reflow_text( + #~ "\t<big><b>" + #~ . encode_entities($reply->{snippet}{authorDisplayName}) + #~ . "</b> (" + #~ . ( + #~ $reply_age =~ /sec|min|hour|day/ + #~ ? "$reply_age ago" + #~ : $yv_utils->format_date($reply->{snippet}{publishedAt}) + #~ ) + #~ . ") replied:</big>\n" + #~ . encode_entities( + #~ wrap_text( + #~ i_tab => "\t\t", + #~ s_tab => "\t\t", + #~ text => [$reply->{snippet}{textDisplay} // 'Empty comment...'] + #~ ) + #~ ) + #~ ); + + #~ my $iter = $feeds_liststore->append; + #~ $feeds_liststore->set( + #~ $iter, + #~ 0 => $reply_text, + #~ 3 => $reply->{snippet}{videoId}, + #~ 4 => $reply->{id}, + #~ ); + #~ } #~ } } - if (defined $continuation) { + if (defined $continuation) { my $iter = $feeds_liststore->append; $feeds_liststore->set( $iter, @@ -3618,10 +3595,10 @@ sub set_entry_details { my $info = $yv_obj->parse_json_string($liststore->get($iter, 8)); my %thumbs = ( - start => 1, - middle => 2, - end => 3, - ); + start => 1, + middle => 2, + end => 3, + ); # Getting thumbs foreach my $type (keys %thumbs) { @@ -3634,18 +3611,18 @@ sub set_entry_details { my $url = $yv_utils->get_thumbnail_url($info, $type); - #~ my $thumbnail = $info->{snippet}{thumbnails}{medium}; - #~ my $url = $thumbnail->{url}; + #~ my $thumbnail = $info->{snippet}{thumbnails}{medium}; + #~ my $url = $thumbnail->{url}; - if ($url =~ /_live\.\w+\z/) { - ## no extra thumbnails available while video is LIVE - } - else { - $url =~ s{/\w+\.(\w+)\z}{/mq$thumbs{$type}.$1}; - } + if ($url =~ /_live\.\w+\z/) { + ## no extra thumbnails available while video is LIVE + } + else { + $url =~ s{/\w+\.(\w+)\z}{/mq$thumbs{$type}.$1}; + } - my $pixbuf = get_pixbuf_thumbnail_from_url($url, 160, 90); - $gui->get_object("image$thumbs{$type}")->set_from_pixbuf($pixbuf); + my $pixbuf = get_pixbuf_thumbnail_from_url($url, 160, 90); + $gui->get_object("image$thumbs{$type}")->set_from_pixbuf($pixbuf); return 0; }, diff --git a/lib/WWW/FairViewer.pm b/lib/WWW/FairViewer.pm index 4e3bed8..5657c4c 100644 --- a/lib/WWW/FairViewer.pm +++ b/lib/WWW/FairViewer.pm @@ -46,34 +46,33 @@ our $VERSION = '1.0.4'; my %valid_options = ( # Main options - v => {valid => q[], default => 3}, - page => {valid => qr/^(?!0+\z)\d+\z/, default => 1}, - http_proxy => {valid => qr/./, default => undef}, - hl => {valid => qr/^\w+(?:[\-_]\w+)?\z/, default => undef}, - maxResults => {valid => [1 .. 50], default => 10}, - topicId => {valid => qr/./, default => undef}, - order => {valid => [qw(relevance date rating viewCount title videoCount)], default => undef}, - publishedAfter => {valid => qr/^\d+/, default => undef}, - publishedBefore => {valid => qr/^\d+/, default => undef}, - channelId => {valid => qr/^[-\w]{2,}\z/, default => undef}, - channelType => {valid => [qw(any show)], default => undef}, + v => {valid => q[], default => 3}, + page => {valid => qr/^(?!0+\z)\d+\z/, default => 1}, + http_proxy => {valid => qr/./, default => undef}, + hl => {valid => qr/^\w+(?:[\-_]\w+)?\z/, default => undef}, + maxResults => {valid => [1 .. 50], default => 10}, + order => {valid => [qw(relevance rating upload_date view_count)], default => undef}, + date => {valid => [qw(hour today week month year)], default => undef}, + + channelId => {valid => qr/^[-\w]{2,}\z/, default => undef}, + channelType => {valid => [qw(any show)], default => undef}, # Video only options - videoCaption => {valid => [qw(any closedCaption none)], default => undef}, - videoDefinition => {valid => [qw(any high standard)], default => undef}, - videoCategoryId => {valid => qr/^\d+\z/, default => undef}, - videoDimension => {valid => [qw(any 2d 3d)], default => undef}, - videoDuration => {valid => [qw(any short medium long)], default => undef}, - videoEmbeddable => {valid => [qw(any true)], default => undef}, - videoLicense => {valid => [qw(any creativeCommon youtube)], default => undef}, - videoSyndicated => {valid => [qw(any true)], default => undef}, - eventType => {valid => [qw(completed live upcoming)], default => undef}, - chart => {valid => [qw(mostPopular)], default => 'mostPopular'}, - - regionCode => {valid => qr/^[A-Z]{2}\z/i, default => undef}, + videoCaption => {valid => [qw(1 true)], default => undef}, + videoDefinition => {valid => [qw(high standard)], default => undef}, + videoCategoryId => {valid => qr/^\d+\z/, default => undef}, + videoDimension => {valid => [qw(2d 3d)], default => undef}, + videoDuration => {valid => [qw(short long)], default => undef}, + videoEmbeddable => {valid => [qw(true)], default => undef}, + videoLicense => {valid => [qw(creative_commons)], default => undef}, + videoSyndicated => {valid => [qw(true)], default => undef}, + eventType => {valid => [qw(completed live upcoming)], default => undef}, + chart => {valid => [qw(mostPopular)], default => 'mostPopular'}, + + region => {valid => qr/^[A-Z]{2}\z/i, default => undef}, relevanceLanguage => {valid => qr/^[a-z]+(?:\-\w+)?\z/i, default => undef}, safeSearch => {valid => [qw(none moderate strict)], default => undef}, - videoType => {valid => [qw(any episode movie)], default => undef}, + videoType => {valid => [qw(episode movie)], default => undef}, comments_order => {valid => [qw(top new)], default => 'top'}, subscriptions_order => {valid => [qw(alphabetical relevance unread)], default => undef}, @@ -669,7 +668,6 @@ sub default_arguments { #part => 'snippet', #prettyPrint => 'false', #maxResults => $self->get_maxResults, - #regionCode => $self->get_regionCode, %args, ); diff --git a/lib/WWW/FairViewer/GuideCategories.pm b/lib/WWW/FairViewer/GuideCategories.pm index 34d0a1d..a348abb 100644 --- a/lib/WWW/FairViewer/GuideCategories.pm +++ b/lib/WWW/FairViewer/GuideCategories.pm @@ -22,7 +22,7 @@ sub _make_guideCategories_url { my ($self, %opts) = @_; if (not exists $opts{id}) { - $opts{regionCode} //= $self->get_regionCode; + $opts{region} //= $self->get_region; } $self->_make_feed_url('guideCategories', hl => $self->get_hl, %opts); @@ -47,7 +47,7 @@ Return info for a list of comma-separated category IDs. name => 'guide_categories_info', }, { - key => 'regionCode', + key => 'region', name => 'guide_categories', }, ) { diff --git a/lib/WWW/FairViewer/Search.pm b/lib/WWW/FairViewer/Search.pm index 8e8162c..af6005b 100644 --- a/lib/WWW/FairViewer/Search.pm +++ b/lib/WWW/FairViewer/Search.pm @@ -21,43 +21,46 @@ WWW::FairViewer::Search - Search functions for Fair API v3 sub _make_search_url { my ($self, %opts) = @_; + my @features; + + if (defined(my $vd = $self->get_videoDefinition)) { + if ($vd eq 'high') { + push @features, 'hd'; + } + } + + if (defined(my $vc = $self->get_videoCaption)) { + if ($vc eq 'true' or $vc eq '1') { + push @features, 'subtitles'; + } + } + + if (defined(my $vd = $self->get_videoDimension)) { + if ($vd eq '3d') { + push @features, '3d'; + } + } + + if (defined(my $license = $self->get_videoLicense)) { + if ($license eq 'creative_commons') { + push @features, 'creative_commons'; + } + } + return $self->_make_feed_url( 'search', - topicId => $self->get_topicId, - regionCode => $self->get_regionCode, - - maxResults => $self->get_maxResults, - order => $self->get_order, - publishedAfter => $self->get_publishedAfter, - publishedBefore => $self->get_publishedBefore, - regionCode => $self->get_regionCode, - relevanceLanguage => $self->get_relevanceLanguage, - safeSearch => $self->get_safeSearch, - channelId => $self->get_channelId, - channelType => $self->get_channelType, - pageToken => $self->page_token, - - ( - $opts{type} eq 'video' - ? ( - videoCaption => $self->get_videoCaption, - videoCategoryId => $self->get_videoCategoryId, - videoDefinition => $self->get_videoDefinition, - videoDimension => $self->get_videoDimension, - videoDuration => $self->get_videoDuration, - videoEmbeddable => $self->get_videoEmbeddable, - videoLicense => $self->get_videoLicense, - videoSyndicated => $self->get_videoSyndicated, - videoType => $self->get_videoType, - eventType => $self->get_eventType, - ) - : () - ), + region => $self->get_region, + sort_by => $self->get_order, + date => $self->get_date, + channelId => $self->get_channelId, + pageToken => $self->page_token, + duration => $self->get_videoDuration, + + (@features ? (features => join(',', @features)) : ()), %opts, ); - } =head2 search_for($types,$keywords;\%args) @@ -146,19 +149,21 @@ be set to a YouTube video ID. sub related_to_videoID { my ($self, $videoID) = @_; - my %info = $self->_get_video_info($videoID); + my %info = $self->_get_video_info($videoID); my $watch_next_response = $self->parse_json_string($info{watch_next_response}); - my $related = eval { $watch_next_response->{contents}{twoColumnWatchNextResults}{secondaryResults}{secondaryResults}{results} } // return { results => []}; + my $related = + eval { $watch_next_response->{contents}{twoColumnWatchNextResults}{secondaryResults}{secondaryResults}{results} } + // return {results => []}; #use Data::Dump qw(pp); #pp $related; my @results; - foreach my $entry(@$related) { + foreach my $entry (@$related) { - my $info = $entry->{compactVideoRenderer} // next; - my $title = $info->{title}{simpleText} // next; + my $info = $entry->{compactVideoRenderer} // next; + my $title = $info->{title}{simpleText} // next; my $viewCount = 0; @@ -166,39 +171,39 @@ sub related_to_videoID { $viewCount = ($1 =~ tr/,//dr); } elsif ($info->{viewCountText}{simpleText} =~ /Recommended for you/i) { - next; # filter out recommended videos from related videos + next; # filter out recommended videos from related videos } my $lengthSeconds = 0; if ($info->{lengthText}{simpleText} =~ /([\d:]+)/) { - my $time = $1; + my $time = $1; my @fields = split(/:/, $time); my $seconds = pop(@fields) // 0; my $minutes = pop(@fields) // 0; - my $hours = pop(@fields) // 0; + my $hours = pop(@fields) // 0; - $lengthSeconds = 3600 * $hours + 60*$minutes + $seconds; + $lengthSeconds = 3600 * $hours + 60 * $minutes + $seconds; } my $published = 0; if (exists $info->{publishedTimeText} and $info->{publishedTimeText}{simpleText} =~ /(\d+)\s+(\w+)\s+ago/) { my $quantity = $1; - my $period = $2; + my $period = $2; - $period =~ s/s\z//; # make it singural + $period =~ s/s\z//; # make it singural my %table = ( - year => 31556952, # seconds in a year - month => 2629743.83, # seconds in a month - week => 604800, # seconds in a week - day => 86400, # seconds in a day - hour => 3600, # seconds in a hour - minute => 60, # seconds in a minute - second => 1, # seconds in a second - ); + year => 31556952, # seconds in a year + month => 2629743.83, # seconds in a month + week => 604800, # seconds in a week + day => 86400, # seconds in a day + hour => 3600, # seconds in a hour + minute => 60, # seconds in a minute + second => 1, # seconds in a second + ); if (exists $table{$period}) { $published = int(time - $quantity * $table{$period}); @@ -209,40 +214,42 @@ sub related_to_videoID { } push @results, { - type => "video", - title => $title, - videoId => $info->{videoId}, - author => $info->{longBylineText}{runs}[0]{text}, + type => "video", + title => $title, + videoId => $info->{videoId}, + author => $info->{longBylineText}{runs}[0]{text}, authorId => $info->{longBylineText}{runs}[0]{navigationEndpoint}{browseEndpoint}{browseId}, + #authorUrl => $info->{longBylineText}{runs}[0]{navigationEndpoint}{browseEndpoint}{browseId}, - description => $info->{accessibility}{accessibilityData}{label}, + description => $info->{accessibility}{accessibilityData}{label}, descriptionHtml => undef, - viewCount => $viewCount, - published => $published, - publishedText => $info->{publishedTimeText}{simpleText}, - lengthSeconds => $lengthSeconds, - liveNow => ($lengthSeconds == 0), # maybe it's live if lengthSeconds == 0? - paid => 0, - premium => 0, + viewCount => $viewCount, + published => $published, + publishedText => $info->{publishedTimeText}{simpleText}, + lengthSeconds => $lengthSeconds, + liveNow => ($lengthSeconds == 0), # maybe it's live if lengthSeconds == 0? + paid => 0, + premium => 0, videoThumbnails => [ map { scalar { - quality => 'medium', - url => $_->{url}, - width => $_->{width}, - height => $_->{height}, - } + quality => 'medium', + url => $_->{url}, + width => $_->{width}, + height => $_->{height}, + } } @{$info->{thumbnail}{thumbnails}} ], }; } - return scalar { - url => undef, - results => \@results, - }; + return + scalar { + url => undef, + results => \@results, + }; } =head1 AUTHOR diff --git a/lib/WWW/FairViewer/VideoCategories.pm b/lib/WWW/FairViewer/VideoCategories.pm index ecca0c2..85045fd 100644 --- a/lib/WWW/FairViewer/VideoCategories.pm +++ b/lib/WWW/FairViewer/VideoCategories.pm @@ -39,8 +39,8 @@ sub video_categories { require File::Spec; - my $region = $self->get_regionCode() // 'US'; - my $url = $self->_make_videoCategories_url(regionCode => $region); + my $region = $self->get_region() // 'US'; + my $url = $self->_make_videoCategories_url(region => $region); my $file = File::Spec->catfile($self->get_config_dir, "categories-$region-" . $self->get_hl() . ".json"); my $json; diff --git a/lib/WWW/FairViewer/Videos.pm b/lib/WWW/FairViewer/Videos.pm index da6af0b..a0f5e1b 100644 --- a/lib/WWW/FairViewer/Videos.pm +++ b/lib/WWW/FairViewer/Videos.pm @@ -74,12 +74,7 @@ sub trending_videos_from_category { my ($self, $cat_id) = @_; my $results = do { - local $self->{publishedAfter} = do { - state $yv_utils = WWW::FairViewer::Utils->new; - $yv_utils->period_to_date(1, 'w'); - } if !defined($self->get_publishedAfter); local $self->{videoCategoryId} = $cat_id; - local $self->{regionCode} = "US" if !defined($self->get_regionCode); $self->search_videos(""); }; diff --git a/share/gtk-fair-viewer.glade b/share/gtk-fair-viewer.glade index 9b9edc0..48b3a05 100644 --- a/share/gtk-fair-viewer.glade +++ b/share/gtk-fair-viewer.glade @@ -986,11 +986,9 @@ Author: Jesus E. https://framagit.org/heckyel <property name="active">0</property> <items> <item translatable="yes">relevance</item> - <item translatable="yes">title</item> <item translatable="yes">rating</item> - <item translatable="yes">date</item> - <item translatable="yes">videoCount</item> - <item translatable="yes">viewCount</item> + <item translatable="yes">upload_date</item> + <item translatable="yes">view_count</item> </items> <signal name="changed" handler="combobox_order_changed" swapped="no"/> </object> @@ -1041,7 +1039,6 @@ long – longer than 20 minutes</property> <items> <item translatable="yes">any</item> <item translatable="yes">short</item> - <item translatable="yes">medium</item> <item translatable="yes">long</item> </items> <signal name="changed" handler="combobox_duration_changed" swapped="no"/> @@ -1082,8 +1079,7 @@ long – longer than 20 minutes</property> <property name="active">0</property> <items> <item translatable="yes">any</item> - <item translatable="yes">closedCaption</item> - <item translatable="yes">none</item> + <item translatable="yes">true</item> </items> <signal name="changed" handler="combobox_caption_changed" swapped="no"/> </object> @@ -1124,7 +1120,6 @@ long – longer than 20 minutes</property> <items> <item translatable="yes">any</item> <item translatable="yes">high</item> - <item translatable="yes">standard</item> </items> <signal name="changed" handler="combobox_definition_changed" swapped="no"/> </object> @@ -1305,36 +1300,16 @@ Recommended: 10</property> <property name="visible">True</property> <property name="can_focus">False</property> <child> - <object class="GtkSpinButton" id="spinbutton3"> - <property name="visible">True</property> - <property name="can_focus">True</property> - <property name="invisible_char">•</property> - <property name="caps_lock_warning">False</property> - <property name="primary_icon_activatable">False</property> - <property name="secondary_icon_activatable">False</property> - <property name="adjustment">adjustment3</property> - <property name="climb_rate">1</property> - <property name="numeric">True</property> - <property name="update_policy">if-valid</property> - <signal name="activate" handler="search" swapped="no"/> - <signal name="value-changed" handler="spin_published_within_changed" swapped="no"/> - </object> - <packing> - <property name="expand">True</property> - <property name="fill">True</property> - <property name="position">0</property> - </packing> - </child> - <child> <object class="GtkComboBoxText" id="comboboxtext1"> <property name="visible">True</property> <property name="can_focus">False</property> <items> <item translatable="yes">anytime</item> - <item translatable="yes">days</item> - <item translatable="yes">weeks</item> - <item translatable="yes">months</item> - <item translatable="yes">years</item> + <item translatable="yes">hour</item> + <item translatable="yes">today</item> + <item translatable="yes">week</item> + <item translatable="yes">month</item> + <item translatable="yes">year</item> </items> <signal name="changed" handler="combobox_published_within_changed" swapped="no"/> </object> |