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