diff options
Diffstat (limited to 'lib/WWW/FairViewer/Subscriptions.pm')
-rw-r--r-- | lib/WWW/FairViewer/Subscriptions.pm | 272 |
1 files changed, 272 insertions, 0 deletions
diff --git a/lib/WWW/FairViewer/Subscriptions.pm b/lib/WWW/FairViewer/Subscriptions.pm new file mode 100644 index 0000000..eb8add9 --- /dev/null +++ b/lib/WWW/FairViewer/Subscriptions.pm @@ -0,0 +1,272 @@ +package WWW::FairViewer::Subscriptions; + +use utf8; +use 5.014; +use warnings; + +=head1 NAME + +WWW::FairViewer::Subscriptions - Subscriptions handler. + +=head1 SYNOPSIS + + use WWW::FairViewer; + my $obj = WWW::FairViewer->new(%opts); + my $videos = $obj->subscriptions_from_channelID($channel_id); + +=head1 SUBROUTINES/METHODS + +=cut + +sub _make_subscriptions_url { + my ($self, %opts) = @_; + return $self->_make_feed_url('subscriptions', %opts); +} + +=head2 subscribe_channel($channel_id) + +Subscribe to an YouTube channel. + +=cut + +sub subscribe_channel { + my ($self, $channel_id) = @_; + + my $resource = { + snippet => { + resourceId => { + kind => 'youtube#channel', + channelId => $channel_id, + } + } + }; + + my $url = $self->_simple_feeds_url('subscriptions', part => 'snippet'); + return $self->post_as_json($url, $resource); +} + +=head2 subscribe_channel_from_username($username) + +Subscribe to an YouTube channel via username. + +=cut + +sub subscribe_channel_from_username { + my ($self, $username) = @_; + $self->subscribe_channel($self->channel_id_from_username($username) // $username); +} + +=head2 subscriptions(;$channel_id) + +Retrieve the subscriptions for a channel ID or for the authenticated user. + +=cut + +sub subscriptions { + my ($self, $channel_id) = @_; + $self->_get_results( + $self->_make_subscriptions_url( + order => $self->get_subscriptions_order, + part => 'snippet', + ( + ($channel_id and $channel_id ne 'mine') + ? (channelId => $channel_id) + : do { $self->get_access_token() // return; (mine => 'true') } + ), + ) + ); +} + +=head2 subscriptions_from_username($username) + +Retrieve subscriptions for a given YouTube username. + +=cut + +sub subscriptions_from_username { + my ($self, $username) = @_; + $self->subscriptions($self->channel_id_from_username($username) // $username); +} + +=head2 subscription_videos(;$channel_id) + +Retrieve the video subscriptions for a channel ID or for the current authenticated user. + +=cut + +sub subscription_videos { + my ($self, $channel_id, $order) = @_; + + my $max_results = $self->get_maxResults(); + + my @subscription_items; + my $next_page_token; + + while (1) { + + my $url = $self->_make_subscriptions_url( + order => $self->get_subscriptions_order, + maxResults => 50, + part => 'snippet,contentDetails', + ($channel_id and $channel_id ne 'mine') + ? (channelId => $channel_id) + : do { $self->get_access_token() // return; (mine => 'true') }, + defined($next_page_token) ? (pageToken => $next_page_token) : (), + ); + + my $subscriptions = $self->_get_results($url)->{results}; + + if ( ref($subscriptions) eq 'HASH' + and ref($subscriptions->{items}) eq 'ARRAY') { + push @subscription_items, @{$subscriptions->{items}}; + } + + $next_page_token = $subscriptions->{nextPageToken} || last; + } + + my (undef, undef, undef, $mday, $mon, $year) = localtime; + + $mon += 1; + $year += 1900; + + my @videos; + foreach my $channel (@subscription_items) { + + my $new_items = $channel->{contentDetails}{newItemCount}; + + # Ignore channels with zero new items + $new_items > 0 || next; + + # Set the number of results + $self->set_maxResults(1); # don't load more than 1 video from each channel + # maybe, this value should be configurable (?) + + my $uploads = $self->uploads($channel->{snippet}{resourceId}{channelId}); + + (ref($uploads) eq 'HASH' and ref($uploads->{results}) eq 'HASH' and ref($uploads->{results}{items}) eq 'ARRAY') + || return; + + my $items = $uploads->{results}{items}; + + # Get and store the video uploads from each channel + foreach my $item (@$items) { + my $publishedAt = $item->{snippet}{publishedAt}; + my ($p_year, $p_mon, $p_mday) = $publishedAt =~ /^(\d{4})-(\d{2})-(\d{2})/; + + my $year_diff = $year - $p_year; + my $mon_diff = $mon - $p_mon; + my $mday_diff = $mday - $p_mday; + + my $days_diff = $year_diff * 365.2422 + $mon_diff * 30.436875 + $mday_diff; + + # Ignore old entries + if ($days_diff > 3) { + next; + } + + push @videos, $item; + } + + # Stop when the limit is reached + last if (@videos >= $max_results); + } + + # When there are no new videos, load one from each channel + if ($#videos == -1) { + foreach my $channel (@subscription_items) { + $self->set_maxResults(1); + push @videos, @{$self->uploads($channel->{snippet}{resourceId}{channelId})->{results}{items}}; + last if (@videos >= $max_results); + } + } + + $self->set_maxResults($max_results); + + state $parse_time_re = qr/^(\d{4})-(\d{2})-(\d{2})T(\d{2}):(\d{2}):(\d{2})/; + + @videos = + sort { + my ($y1, $M1, $d1, $h1, $m1, $s1) = $a->{snippet}{publishedAt} =~ $parse_time_re; + my ($y2, $M2, $d2, $h2, $m2, $s2) = $b->{snippet}{publishedAt} =~ $parse_time_re; + + ($y2 <=> $y1) || ($M2 <=> $M1) || ($d2 <=> $d1) || ($h2 <=> $h1) || ($m2 <=> $m1) || ($s2 <=> $s1) + } @videos; + + return {results => {pageInfo => {totalResults => $#videos + 1}, items => \@videos}}; +} + +=head2 subscription_videos_from_username($username) + +Retrieve the video subscriptions for a username. + +=cut + +sub subscription_videos_from_username { + my ($self, $username) = @_; + $self->subscription_videos($self->channel_id_from_username($username) // $username); +} + +=head2 subscriptions_from_channelID(%args) + +Get subscriptions for the specified channel ID. + +=head2 subscriptions_info($subscriptionID, %args) + +Get details for the comma-separated subscriptionID(s). + +=head3 HASH '%args' supports the following pairs: + + %args = ( + part => {contentDetails,id,snippet}, + forChannelId => $channelID, + maxResults => [0-50], + order => {alphabetical, relevance, unread}, + pageToken => {$nextPageToken, $prevPageToken}, + ); + +=cut + +{ + no strict 'refs'; + foreach my $method ( + { + key => 'id', + name => 'subscriptions_info', + }, + { + key => 'channelId', + name => 'subscriptions_from_channel_id', + } + ) { + *{__PACKAGE__ . '::' . $method->{name}} = sub { + my ($self, $id, %args) = @_; + return $self->_get_results($self->_make_subscriptions_url($method->{key} => $id, %args)); + }; + } +} + +=head1 AUTHOR + +Trizen, C<< <echo dHJpemVuQHByb3Rvbm1haWwuY29tCg== | base64 -d> >> + + +=head1 SUPPORT + +You can find documentation for this module with the perldoc command. + + perldoc WWW::FairViewer::Subscriptions + + +=head1 LICENSE AND COPYRIGHT + +Copyright 2013-2015 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 L<http://dev.perl.org/licenses/> for more information. + +=cut + +1; # End of WWW::FairViewer::Subscriptions |