From faaacb2741009b8df6e855d74f38ef72197d6889 Mon Sep 17 00:00:00 2001 From: Ralf Ertzinger Date: Wed, 3 Aug 2011 23:11:30 +0200 Subject: [PATCH] Youtube: Add support for url_encoded_fmt_stream_map and use decode_hexurl() --- videosite/YouTubeGrabber.pm | 56 ++++++++++++++++++++++++++++++++++----------- 1 file changed, 43 insertions(+), 13 deletions(-) diff --git a/videosite/YouTubeGrabber.pm b/videosite/YouTubeGrabber.pm index be1add1..56bf65c 100644 --- a/videosite/YouTubeGrabber.pm +++ b/videosite/YouTubeGrabber.pm @@ -134,21 +134,27 @@ sub _parse_by_video_info { return undef; } - unless(exists($content->{'fmt_url_map'}) and exists($content->{'title'})) { - $self->debug("No fmt_url_map or no title found"); + if (exists($content->{'fmt_url_map'})) { + # Decode fmt_url_map + $urls = $self->decode_hexurl($content->{'fmt_url_map'}); + $urls = { split /[\|,]/, $urls }; + } elsif (exists($content->{'url_encoded_fmt_stream_map'})) { + $urls = $self->_decode_url_encoded_fmt_stream_map($content->{'url_encoded_fmt_stream_map'}); + } else { + $self->debug("No URL data found"); return undef; } - # Decode fmt_url_map - $urls = $content->{'fmt_url_map'}; - $urls =~ s/%(..)/chr(hex($1))/ge; - $urls = { split /[\|,]/, $urls }; + unless(exists($content->{'title'})) { + $self->debug("No title found"); + return undef; + } $self->__pick_url($urls, $preflist, $metadata); $metadata->{'TITLE'} = $content->{'title'}; $metadata->{'TITLE'} =~ s/\+/ /g; - $metadata->{'TITLE'} =~ s/%(..)/chr(hex($1))/ge; + $metadata->{'TITLE'} = $self->decode_hexurl($metadata->{'TITLE'}); $metadata->{'TITLE'} = decode("utf8", $metadata->{'TITLE'}); $self->debug('Title found: %s', $metadata->{'TITLE'}); @@ -244,7 +250,7 @@ sub _parse_by_scrape { $self->debug("Video has fmt_url_map: %s", $urls); - $urls =~ s/%([[:xdigit:]]{2})/chr(hex($1))/ge; + $urls = $self->decode_hexurl($urls); %urls = split(/[\|,]/, $urls); $self->debug("Pagetype: old (SWF_ARGS), fmt_url_map"); @@ -256,7 +262,7 @@ sub _parse_by_scrape { my @fmt; $self->debug('Video has fmt_map'); - $fmt =~ s/%([[:xdigit:]]{2})/chr(hex($1))/ge; + $fmt = $self->decode_hexurl($fmt); @fmt = split(/,/, $fmt); foreach (@fmt) { @_=split(/\//); @@ -281,7 +287,7 @@ sub _parse_by_scrape { my $urls = $1; $self->debug("Video has fmt_url_map: %s", $urls); - $urls =~ s/%([[:xdigit:]]{2})/chr(hex($1))/ge; + $urls = $self->decode_hexurl($urls); %urls = split(/[\|,]/, $urls); $self->debug("Pagetype: 2010 (swfHTML), fmt_url_map"); } elsif ($e =~ m|\x27PLAYER_CONFIG\x27:\s+(.+)\}\);|) { @@ -309,9 +315,7 @@ sub _parse_by_scrape { %urls = split(/[\|,]/, $urls); foreach (keys(%urls)) { - my $u = $urls{$_}; - $u =~ s/%([[:xdigit:]]{2})/chr(hex($1))/ge; - $urls{$_} = $u; + $urls{$_} = $self->decode_hexurl($urls{$_}); } $self->debug("Pagetype: 2011 (PLAYER_CONFIG), fmt_url_map"); } else { @@ -451,6 +455,31 @@ sub __login { return ($ua->get($videourl), $cookie); } +# Take an encoded url_encoded_fmt_stream_map and return a hash +# matching video IDs to download URLs +sub _decode_url_encoded_fmt_stream_map { + my $self = shift; + my $data = $self->decode_hexurl(shift); + my @data; + + # This will + # - Split the decoded string into segments (along ,) + # - Interpret each segment as a concatenated key-value list (key and value separated by =, pairs separated by & + # - URL-decode each key and value _again_ + # + # @data will be an array of hash references + + @data = map { { map { $self->decode_hexurl($_) } split /[=&]/ } } split /,/, $data; + $self->debug("_decode_url_encoded_fmt_stream_map() decoded %s", Dumper(\@data)); + + # From each array entry, pick the itag and the url values and return that + # as a hash reference + + return { map { $_->{'itag'}, $_->{'url'} } @data }; +} + + + sub __pick_url { my $self = shift; my $urls = shift; @@ -477,3 +506,4 @@ sub __pick_url { } 1; + -- 1.8.3.1