Skip to content

Instantly share code, notes, and snippets.

@ispedals
Created May 20, 2013 21:05
Show Gist options
  • Save ispedals/5615556 to your computer and use it in GitHub Desktop.
Save ispedals/5615556 to your computer and use it in GitHub Desktop.
Mojolicious::Lite app that explores a youtube video by both displaying both the author's video and related videos recursively
#perl
use v5.16;
use warnings;
use XML::Smart;
use Mojolicious::Lite;
my %videos; #videos to be saved; structured <id:[title, author_url, id, duration, [thumbnails]]>
my %seen; #videos that have been seen and either saved or rejected; keys are video ids
my %authors; #authors whose uploads have been seen; keys are author urls
my @to_process = (
[
]
); #initialize with videos
$seen{$_->[2]} = 1 for @to_process;
sub get_videos_from_feed {
my $url = shift;
my $ret = [];
#actually 97% faster than Mojo::DOM
my $x = XML::Smart->new($url);
for ( @{ $x->{feed}->{entry} } ) {
my $title = $_->{title}->content;
my $author = $_->{author}->{uri}->content . '/uploads?v=2';
my $id = $_->{'media:group'}->{'yt:videoid'}->content;
my @thumbs =
map { $_->{url} }
@{ $_->{'media:group'}->{'media:thumbnail'} }[ -3 .. -1 ]; #last three thumbs are start, middle and end of video
my $duration = $_->{'media:group'}->{'yt:duration'}->{seconds};
next if $videos{$id} || $seen{$id};
push( @$ret, [ $title, $author, $id, $duration, \@thumbs ] );
}
if ( $x->{feed}->{link}( 'rel', 'eq', 'next' ) ) {
$url = $x->{feed}{link}( 'rel', 'eq', 'next' )->{href}->content;
my @next = get_videos_from_feed($url);
return @$ret, @next;
}
else {
return @$ret;
}
#use Mojo::UserAgent;
#state $ua = Mojo::UserAgent->new;
#my $dom = $ua->get($url)->res->dom;
#for ( $dom->find('media\:group')->each ) {
# my $title = $_->at('media\:title')->text;
# my $author = $_->at('yt\:uploaderId')->text;
# $author =
# sprintf 'http://gdata.youtube.com/feeds/api/users/%s/uploads?v=2',
# $author;
# my $id = $_->at('yt\:videoid')->text;
# my @thumbs =
# map { $_->{url} } ( $_->find('media\:thumbnail')->each )[ -3 .. -1 ];
# my $duration = $_->at('yt\:duration')->{seconds};
# next if $videos{$id} || $seen{$id};
# push( @$ret, [ $title, $author, $id, $duration, \@thumbs ] );
#}
#return @$ret unless ( $url = $dom->at('link[rel="next"]') );
#my @next = get_videos_from_feed( $url->{href} );
#return @$ret, @next;
}
sub process {
my $vid = shift @to_process;
my @ret;
my @related_videos =
get_videos_from_feed "http://gdata.youtube.com/feeds/api/videos/"
. $vid->[2]
. "/related?v=2";
my @author_uploads =
$authors{ $vid->[1] } ? () : get_videos_from_feed $vid->[1];
for ( ( @related_videos, @author_uploads ) ) {
next if $videos{ $_->[2] } || $seen{ $_->[2] } || $authors{ $_->[1] };
$seen{ $_->[2] } = 1;
push @ret, $_;
}
$authors{ $vid->[1] } = 1;
return @ret;
}
my @to_be_selected; #contains all the videos derived from a single video, filtered in post
get '/' => sub {
my $self = shift;
@to_be_selected = process;
my $picked = scalar keys %videos;
my $processed = scalar keys %seen;
my $out = "<!html><head><title>Picked $picked out of $processed</title></head><body><form method='post'>";
for (@to_be_selected) {
my ( $title, $id, $duration ) = @{$_}[ 0, 2, 3 ];
$out .=
"<div><p>$title ($duration seconds)</p><input type='checkbox' name='$id'>";
$out .= "<img src='$_'>" for @{ $_->[4] };
$out .= '</div>';
}
$out .= '<input type="submit" value="Submit">';
$self->render( text => $out );
};
post '/' => sub {
my $self = shift;
my %wanted = map { $_ => 1 } $self->param; #params contains the ids of the video that were selected to be saved
@to_be_selected = grep { $wanted{ $_->[2] } } @to_be_selected;
$videos{ $_->[2] } = $_ for @to_be_selected;
push @to_process, @to_be_selected;
@to_be_selected = ();
$self->redirect_to('/');
};
get '/view' => sub {
my $self = shift;
my $picked = scalar keys %videos;
my $processed = scalar keys %seen;
my $out = "<!html><head><title>Picked $picked out of $processed</title></head><body>";
for ( values %videos ) {
my ( $title, $id, $duration ) = @{$_}[ 0, 2, 3 ];
$out .= "<div><p><a href='https://www.youtube.com/watch?v=$id'>$title</a> ($duration seconds)</p>";
$out .= '<img src="' . $_ . '">' for @{ $_->[4] };
$out .= '</div>';
}
$out .= "http://www.youtube.com/watch?v=$_<br>" for keys %videos;
$out .= '<hr><h1>Seen</h1>';
$out .= "http://www.youtube.com/watch?v=$_<br>" for keys %seen;
$out .= '<hr><h1>Authors</h1>';
$out .= "$_<br>" for keys %authors;
$self->render( text => $out );
};
app->start;
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment