YouTube: Correctly parse url_encoded_fmt_stream_map from the web scape, too
[videosite.git] / videosite / BlipTVGrabber.pm
1 # (c) 2007 by Ralf Ertzinger <ralf@camperquake.de>
2 # licensed under GNU GPL v2
3 #
4 # Grabber for blip.tv
5
6 package videosite::BlipTVGrabber;
7
8 use videosite::GrabberBase;
9 @ISA = qw(videosite::GrabberBase);
10
11 use LWP::Simple qw(!get);
12 use LWP::UserAgent;
13 use URI;
14 use URI::QueryParam;
15 use HTML::Parser;
16 use XML::Simple;
17 use Data::Dumper;
18
19 use strict;
20
21 sub new {
22     my $class = shift;
23     my $self = $class->SUPER::new();
24
25     $self->{'NAME'} = 'bliptv';
26     $self->{'PATTERNS'} = ['(http://(?:[-a-zA-Z0-9_.]+\.)*blip.tv/file/(\d+)(?:\?\S+)?)',
27                            '(http://blip\.tv/play/(\w+)$)'];
28
29     bless($self, $class);
30     $self->_prepare_parameters();
31
32     return $self;
33 }
34
35 sub _parse {
36     my $self = shift;
37     my $url = shift;
38     my $pattern = shift;
39     my $content;
40     my $metadata = {};
41     my $p = HTML::Parser->new(api_version => 3);
42     my @accum;
43     my @text;
44     my $e;
45     my $xml = undef;
46     my $ua;
47
48     $url =~ m|$pattern|;
49     $url = $1;
50
51     $metadata->{'URL'} = $url;
52     $metadata->{'ID'} = $2;
53     $metadata->{'TYPE'} = 'video';
54     $metadata->{'SOURCE'} = $self->{"NAME"};
55     $metadata->{'TITLE'} = undef;
56     $metadata->{'DLURL'} = undef;
57
58     if ($pattern eq $self->{'PATTERNS'}->[0]) {
59         # blip.tv/file pattern
60         unless(defined($content = LWP::Simple::get(sprintf('http://blip.tv/file/%s', $2)))) {
61             $self->error('Could not download page');
62             return undef;
63         }
64
65         $p->handler(start => \@accum, "tagname, attr");
66         $p->handler(text => \@text, "text");
67         $p->report_tags(qw(script));
68         $p->utf8_mode(1);
69         $p->parse($content);
70
71         # Look for the post id in the javascript code
72         foreach $e (@text) {
73             if ($e->[0] =~ m|player.setPostsId\((\d+)\)|s) {
74                 $xml = $1;
75             }
76         }
77     } elsif ($pattern eq $self->{'PATTERNS'}->[1]) {
78         my $r;
79         my $u;
80
81         $ua = LWP::UserAgent->new(max_redirect => 0);
82         $r = $ua->get(sprintf('http://blip.tv/play/%s', $2));
83
84         unless(defined($r)) {
85             $self->error('Could not download page');
86             return undef;
87         }
88         unless($r->is_redirect()) {
89             $self->error('Expected redirect, but got none');
90             return undef;
91         }
92         $u = URI->new($r->header('Location'));
93         $u = $u->query_param("file");
94
95         unless(defined($u)) {
96             $self->error('Did not find file parameter in URL');
97             return undef;
98         }
99         $u =~ m|^http://blip.tv/rss/flash/(\d+)$|;
100         $xml = $1;
101
102     } else {
103         $self->error("Don't know how to handle that pattern yet");
104         return undef;
105     }
106
107     unless(defined($xml)) { 
108         $self->error("Could not find post id");
109         return undef;
110     }
111
112     # Download the XML file containing the stream information
113     unless(defined($content = LWP::Simple::get(sprintf('http://blip.tv/rss/flash/%s', $xml)))) {
114         $self->error('Could not download XML metadata');
115         return undef;
116     }
117
118     $xml = XML::Simple::XMLin($content, KeepRoot => 1);
119     $metadata->{'DLURL'} = $xml->{'rss'}->{'channel'}->{'item'}->{'enclosure'}->{'url'};
120     $metadata->{'TITLE'} = $xml->{'rss'}->{'channel'}->{'item'}->{'media:title'};
121
122     unless(defined($metadata->{'DLURL'}) && defined($metadata->{'TITLE'})) {
123         $self->error('Could not determine download URL');
124         return undef;
125     }
126
127     return $metadata;
128 }
129
130 1;