The Perl Toolchain Summit needs more sponsors. If your company depends on Perl, please support this very important event.
package Plagger::Plugin::CustomFeed::YouTube;
use strict;
use warnings;
use base qw( Plagger::Plugin );

use Plagger::Enclosure;
use Plagger::UserAgent;
use URI;
use Encode;

sub register {
    my($self, $context) = @_;
    $context->register_hook(
        $self,
        'subscription.load' => \&load,
    );
}

sub load {
    my($self, $context) = @_;
    my $feed = Plagger::Feed->new;
    $feed->aggregator(sub { $self->aggregate(@_) });
    $context->subscription->add($feed);
}

sub aggregate {
    my($self, $context, $args) = @_;

    my $url  = URI->new('http://youtube.com/results');
    my $file = $self->cache->path_to('youtube_search_result.html');
    my $query = $self->conf->{query};

    $query = encode('UTF-8', $query) unless $context->conf->{no_decode_utf8};

    $context->log( info => 'Getting YouTube search results for ' . $query );

    my $ua = Plagger::UserAgent->new;

    my $feed = Plagger::Feed->new;
    $feed->type('youtubesearch');
    $feed->title("YouTube Search - $query");

    my $page = $self->conf->{page} || 1;
    my $sort = $self->conf->{sort} || 'video_date_uploaded';

    for ( 1 .. $page ){
        $url->query_form(
            search_type     => 'search_videos',
            search_query    => $query,
            search_sort     => $sort,
            search_category => 0,
            page            => $_,
        );

        my $res = $ua->mirror( $url->as_string => $file );

        if($res->is_error){
            $context->log( error => $res->status );
            return;
        }

        open my $fh, "<:encoding(utf-8)", $file
            or return $context->log(error => "$file: $!");

        my (@videos, $data, $title_flag, $tag_flag);
        while (<$fh>) {
            # get title
            m!<div class="vtitle">!
                and $title_flag = 1;
            m!<a href="/watch\?v=([^"]+)"[^>]+>(.+)</a>!
                and do {
                    if($title_flag){
                        $data->{title} = $2;
                        $data->{id} = $1;
                        $title_flag = 0;
                    }
                };
            # get image url
            m!<img src="(http://[\w-]*static\d+(.[\w-]+)?\.youtube.com/[^">]+/[12].jpg)" border="0" class="vimg120" />!
                and $data->{image}->{url} = $1;
            # get description
            m!<div class="vdesc">!
                and do {
                    <$fh>;
                    $data->{description} = <$fh>;
                };
            # get tags
            m!<div class="vtagLabel">Tags:</div>!
                and $tag_flag = 1;
            m!(<a href="/results\?search_query=.*)!
                and do {
                    if($tag_flag){
                        $data->{tags} = $1;
                        $tag_flag = 0;
                    }
                };
            # get author
            m!From:</span> <a href="/user/[^>]+">([^<]+)</a>!
                and $data->{author} = $1;
            m/<!-- end vEntry -->/
                and do {
                    $context->log( info => 'Got ' . $data->{title});
                    my $entry = Plagger::Entry->new;
                    $entry->title($data->{title});
                    $entry->link('http://youtube.com/watch?v=' . $data->{id});
                    $entry->icon({
                        url    => $data->{image}->{url},
                        #width  => $data->{image}->{width},
                        #height => $data->{image}->{height},
                    });
                    $entry->summary($data->{description});
                    $entry->body($data->{description});
                    $entry->author($data->{author});

                    # tags
                    while( $data->{tags} =~ /<a href="\/results\?search_query=[^"]+" class="dg">([^<]+)<\/a>/gms){
                        $entry->add_tag($1);
                    }

                    # enclosure
                    my $video_url = $self->cache->get_callback(
                        "item-" . $entry->link, sub {
                            my $res = $ua->fetch($entry->link);
                            if ($res->is_error){
                                $context->log( error => $res->status );
                                return;
                            }
                            my $url;
                            if ($res->content =~ /&t=([^&]+)/gms){
                                $url = 'http://youtube.com/get_video?video_id=' . $data->{id} . "&t=$1";
                            }
                            return $url;
                        },
                        '24 hours',
                    );

                    if ($video_url) {
                        my $video_id = ( $video_url =~ /video_id=(\w+)/ )[0];
                        my $enclosure = Plagger::Enclosure->new;
                        $enclosure->url( URI->new($video_url) );
                        $enclosure->type('video/x-flv');
                        $enclosure->filename("$video_id.flv");
                        $entry->add_enclosure($enclosure);
                    }

                    $feed->add_entry($entry);
                    $data = {};
            };
        }
    }

    $context->update->add($feed);
}

1;
__END__

=head1 NAME

Plagger::Plugin::CustomFeed::YouTube - Get YouTube search result or rss

=head1 SYNOPSIS

  - module: CustomFeed::YouTube
    config:
      query: Twenty Four
      sort: video_date_uploaded
      page: 5

=head1 DESCRIPTION

This plugin fetches the result of YouTube search or the rss of a specified tag.

=head1 CONFIG

=over 4

=item query

Specify search query.

=item sort

Set sort condition. Available conditions are below. Default is video_date_uploaded.

  relevance
  video_date_uploaded
  video_view_count
  video_avg_rating

=item page

Number of pages of search result you get. Default is 1.

=back

=head1 AUTHOR

Gosuke Miyashita

=head1 SEE ALSO

L<Plagger>

=cut