Add libvideosite.pm
[videosite.git] / videosite / DailyMotionGrabber.pm
1 # Grabber for dailymotion.com
2 #
3 # (c) 2007 by Ralf Ertzinger <ralf@camperquake.de>
4 # licensed under GNU GPL v2
5
6 package videosite::DailyMotionGrabber;
7
8 use videosite::GrabberBase;
9 @ISA = qw(videosite::GrabberBase);
10
11 use HTML::Parser;
12 use videosite::JSArrayParser;
13 use Data::Dumper;
14
15 use strict;
16
17 sub new {
18     my $class = shift;
19     my $self = $class->SUPER::new(
20         NAME => 'dailymotion',
21         PATTERNS => ['(http://(?:[-a-zA-Z0-9_.]+\.)*dailymotion.com/(?:[^/]+/)*video/([-a-zA-Z0-9_]+))'],
22         @_,
23     );
24
25     return bless($self, $class);
26 }
27
28 sub _parse {
29     my $self = shift;
30     my $url = shift;
31     my $pattern = shift;
32     my $content;
33     my $metadata = {};
34     my $p = HTML::Parser->new(api_version => 3);
35     my @accum;
36     my @text;
37     my $e;
38
39     $url =~ m|$pattern|;
40     $url = $1;
41
42     $metadata->{'URL'} = $url;
43     $metadata->{'ID'} = $2;
44     $metadata->{'TYPE'} = 'video';
45     $metadata->{'SOURCE'} = $self->{'NAME'};
46     $metadata->{'TITLE'} = undef;
47     $metadata->{'DLURL'} = undef;
48
49     unless(defined($content = $self->simple_get(sprintf('http://www.dailymotion.com/video/%s', $2)))) {
50         $self->error('Could not download %s', $url);
51         return undef;
52     }
53
54     $p->handler(start => \@accum, "tagname, attr");
55     $p->handler(text => \@text, "text");
56     $p->report_tags(qw(meta script));
57     $p->utf8_mode(1);
58     $p->parse($content);
59
60     # Look for the title in the meta tags
61     foreach $e (@accum) {
62         if ('meta' eq $e->[0]) {
63             if ('title' eq $e->[1]->{'name'}) {
64                 $metadata->{'TITLE'} = $e->[1]->{'content'};
65                 $metadata->{'TITLE'} =~ s/^Dailymotion\s+-\s+//;
66                 $metadata->{'TITLE'} =~ s/(?:\s+-\s+.*)?$//;
67             }
68         }
69     }
70
71     # Look for the download URL
72     foreach $e (@text) {
73         if ($e->[0] =~ m|\.addVariable\("sequence",\s*"([^\"]+)"|) {
74             my $sequence = $1;
75             my $jsp = videosite::JSArrayParser->new();
76             my $l;
77             my $s;
78
79             $sequence =~ s/%(..)/chr(hex($1))/ge;
80             $self->debug("Found sequence: %s", $sequence);
81
82             $self->debug("Using %s to parse", ref($jsp));
83             $sequence = $jsp->parse($sequence);
84             $self->debug(Dumper($sequence));
85
86             unless(defined($sequence)) {
87                 $self->error("Found sequence, but could not parse");
88                 return undef;
89             } else {
90                 $self->debug("Parsed sequence: %s", Dumper($sequence));
91
92                 $l = $self->_fetch_layer($sequence, "root/layerList", "background/sequenceList", "main/layerList", "video/param");
93                 unless(defined($l)) {
94                     $self->error("Could not find video layer");
95                     return undef;
96                 }
97
98                 # Found video section
99                 if (exists($l->{'videoPluginParameters'}->{'hdURL'})) {
100                     $metadata->{'DLURL'} = $l->{'videoPluginParameters'}->{'hdURL'};
101                 } elsif (exists($l->{'videoPluginParameters'}->{'hqURL'})) {
102                     $metadata->{'DLURL'} = $l->{'videoPluginParameters'}->{'hqURL'};
103                 } elsif (exists($l->{'videoPluginParameters'}->{'hqURL'})) {
104                     $metadata->{'DLURL'} = $l->{'videoPluginParameters'}->{'sdURL'};
105                 } else {
106                     $self->error("Video section found, but no URLs");
107                     return undef;
108                 }
109             }
110         }
111     }
112
113     unless(defined($metadata->{'DLURL'}) && defined($metadata->{'TITLE'})) {
114         $self->error('Could not determine download URL');
115         return undef;
116     }
117
118     return $metadata;
119 }
120
121 sub _fetch_layer {
122     my $self = shift;
123     my $sequence = shift;
124     my $point = shift;
125     my $next;
126     my @points = @_;
127     my $l;
128
129     $self->debug("Looking for %s in %s", $point, Dumper($sequence));
130
131     unless(defined($point)) {
132         $self->debug("Reached last point");
133         return $sequence;
134     }
135     ($point, $next) = split(/\//, $point, 2);
136
137     foreach (@{$sequence}) {
138         if (exists($_->{'name'}) and ($_->{'name'} eq $point)) {
139             if (exists($_->{$next})) {
140                 $self->debug("Using %s in %s", $next, $point);
141                 return $self->_fetch_layer($_->{$next}, @points);
142             } else {
143                 $self->debug("%s found, but no %s", $point, $next);
144                 return undef;
145             }
146
147         }
148     }
149
150     $self->debug("Could not find entry named %s", $point);
151     return undef;
152 }
153
154 1;