new youtubedown

This commit is contained in:
John Doty 2018-02-23 15:59:31 -08:00
parent 1dd8283355
commit b0173f6ab4

View file

@ -67,7 +67,7 @@ use HTML::Entities;
my $progname0 = $0; my $progname0 = $0;
my $progname = $0; $progname =~ s@.*/@@g; my $progname = $0; $progname =~ s@.*/@@g;
my ($version) = ('$Revision: 1.983 $' =~ m/\s(\d[.\d]+)\s/s); my ($version) = ('$Revision: 1.1044 $' =~ m/\s(\d[.\d]+)\s/s);
# Without this, [:alnum:] doesn't work on non-ASCII. # Without this, [:alnum:] doesn't work on non-ASCII.
use locale; use locale;
@ -1717,6 +1717,56 @@ my %ciphers = (
'player-vflGRNpAk/en_US/base' => '17436 s1 w50 r s3', # 02 Oct 2017 'player-vflGRNpAk/en_US/base' => '17436 s1 w50 r s3', # 02 Oct 2017
'player-vfl1RKjMF/en_US/base' => '17442 s2 r s2', # 04 Oct 2017 'player-vfl1RKjMF/en_US/base' => '17442 s2 r s2', # 04 Oct 2017
'player-vflOdyxa4/en_US/base' => '17444 s2 r w24 s2 w48 s3 r', # 05 Oct 2017 'player-vflOdyxa4/en_US/base' => '17444 s2 r w24 s2 w48 s3 r', # 05 Oct 2017
'player-vflgfcuiz/en_US/base' => '17444 s2 r w24 s2 w48 s3 r', # 09 Oct 2017
'player-vflgH8YLq/en_US/base' => '17448 r w49 s3 w34 s3 w6 s3', # 10 Oct 2017
'player-vflwcUIMe/en_US/base' => '17449 w31 r w13 w14 r s1 r w45 r',# 11 Oct 2017
'player-vflD3dhYB/en_US/base' => '17452 w41 r w37 w19', # 17 Oct 2017
'player-vflHvONov/en_US/base' => '17455 s2 r s2 w20 r s3', # 17 Oct 2017
'player-vflcNAJUd/en_US/base' => '17456 w16 s3 w6 r w40 s3 r w49',# 18 Oct 2017
'player-vflN-B5oM/en_US/base' => '17463 r w69 w9 s1', # 24 Oct 2017
'player-vflC8Yy7I/en_US/base' => '17462 w70 s3 w59 r w46', # 25 Oct 2017
'player-vflhIZIgy/en_US/base' => '17462 w70 s3 w59 r w46', # 26 Oct 2017
'player-vflSjPnAo/en_US/base' => '17465 r w28 w62 r s1 r s1', # 30 Oct 2017
'player-vfl1ElKmp/en_US/base' => '17469 s2 r w62 s2 w5', # 31 Oct 2017
'player-vflhqxyp7/en_US/base' => '17469 s2 r w62 s2 w5', # 01 Nov 2017
'player-vflg6eF8s/en_US/base' => '17471 w13 w48 r s3 w6', # 02 Nov 2017
'player-vflv6AMZr/en_US/base' => '17473 w1 r s2 w16', # 06 Nov 2017
'player-vflvYne1z/en_US/base' => '17473 w1 r s2 w16', # 07 Nov 2017
'player-vfl8XKJyP/en_US/base' => '17478 s1 r w69 s2 w45 s3 r w64 s2',# 08 Nov 2017
'player-vfl97imvj/en_US/base' => '17478 s1 r w69 s2 w45 s3 r w64 s2',# 09 Nov 2017
'player-vflXHVFyU/en_US/base' => '17483 r w55 s3 w5 r w36 r w66',# 13 Nov 2017
'player-vflg_prv_/en_US/base' => '17486 w58 s3 r s2 w2 s3', # 16 Nov 2017
'player-vflPDkkkL/en_US/base' => '17486 w58 s3 r s2 w2 s3', # 16 Nov 2017
'player-vflM013co/en_US/base' => '17486 w58 s3 r s2 w2 s3', # 16 Nov 2017
'player-vflYXLM5n/en_US/base' => '17488 r s2 w13 s3 w62 r w14', # 20 Nov 2017
'player-vflsCMP_E/en_US/base' => '17490 w31 s1 r s3', # 21 Nov 2017
'player-vflJtN5rw/en_US/base' => '17494 w45 w69 w2 r s1 r s1 r',# 24 Nov 2017
'player-vflnNEucX/en_US/base' => '17492 w61 r s2 r', # 27 Nov 2017
'player-vfl8BSHQD/en_US/base' => '17492 w61 r s2 r', # 29 Nov 2017
'player-vfl32FIDY/en_US/base' => '17501 w48 r w24 r', # 04 Dec 2017
'player-vfl_6lezG/en_US/base' => '17501 w48 r w24 r', # 05 Dec 2017
'player-vflvODUt0/en_US/base' => '17501 w48 r w24 r', # 06 Dec 2017
'player-vfl4OEYh9/en_US/base' => '17501 w48 r w24 r', # 07 Dec 2017
'player-vflebAXY2/en_US/base' => '17508 s2 w60 w51 s3 w52 r w22',# 11 Dec 2017
'player-vflu-7yX5/en_US/base' => '17511 r s2 r s2 w69', # 12 Dec 2017
'player-vflOQ79Pl/en_US/base' => '17512 w28 w47 r s1 r w6', # 13 Dec 2017
'player-vflyoGrhd/en_US/base' => '17512 w28 w47 r s1 r w6', # 14 Dec 2017
'player-vflalc4VN/en_US/base' => '17515 w52 w9 s3 r w19 r w44 r',# 18 Dec 2017
'player-vflQ3Cu6g/en_US/base' => '17533 w56 s3 w35 r s2 w57 s2',# 03 Jan 2018
'player-vflIfz8pB/en_US/base' => '17533 w56 s3 w35 r s2 w57 s2',# 04 Jan 2018
'player-vfluepRD8/en_US/base' => '17536 w30 w30 w10 s3', # 08 Jan 2018
'player-vflmAXHDE/en_US/base' => '17539 w20 r w35 r s1 w60 r s2',# 09 Jan 2018
'player-vflAhnAPk/en_US/base' => '17539 w20 r w35 r s1 w60 r s2',# 10 Jan 2018
'player-vflLCGcm0/en_US/base' => '17541 s2 r s3 w27 s2', # 11 Jan 2018
'player-vflsh1Hwx/en_US/base' => '17544 r s1 r w52 r s1 r s2', # 16 Jan 2018
'player-vflNX6xa_/en_US/base' => '17547 r w14 s1 w66 s1 w9 w65 r',# 17 Jan 2018
'player-vfljg_2Dr/en_US/base' => '17549 w52 r s1 w56 s2 r', # 22 Jan 2018
'player-vfleux_zG/en_US/base' => '17555 w15 w70 r w10 r w66 s3 w33 w24',# 24 Jan 2018
'player-vflX4ueE4/en_US/base' => '17555 w15 w70 r w10 r w66 s3 w33 w24',# 25 Jan 2018
'player-vflAZc3qd/en_US/base' => '17555 w15 w70 r w10 r w66 s3 w33 w24',# 29 Jan 2018
'player-vflVZNDz1/en_US/base' => '17555 w15 w70 r w10 r w66 s3 w33 w24',# 30 Jan 2018
'player-vflxuxnEY/en_US/base' => '17561 s3 r w49', # 31 Jan 2018
'player-vflBjp0_H/en_US/base' => '17564 w1 s3 r', # 06 Feb 2018
); );
@ -2400,22 +2450,27 @@ sub load_youtube_formats($$$) {
errorI ("$cipher: no sts") unless $sts; errorI ("$cipher: no sts") unless $sts;
} }
my $info_url = ("https://www.youtube.com/get_video_info?video_id=$id" . my $info_url_1 = ("https://www.youtube.com/get_video_info?video_id=$id" .
# Avoid the "playback restricted" error. This is a referer. # Avoid the "playback restricted" error. This is a referer.
'&eurl=' . url_quote ($url) . '&eurl=' . url_quote ($url) .
($sts ? '&sts=' . $sts : '') . ($sts ? '&sts=' . $sts : ''));
# Jul 2017: need this to avoid "blocked it from display
# on this website or application". # Sometimes this arg is needed to avoid "blocked it from display
'&el=info' # on this website or application". But sometimes, including it *causes*
); # "sign in to confirm your age". So try both with and without.
#
my $info_url_2 = $info_url_1 . '&el=info';
my ($title, $kind, $kind2, $urlmap, $urlmap2, $body, $rental, $realtime, my ($title, $kind, $kind2, $urlmap, $urlmap2, $body, $rental, $realtime,
$rtmpe_p, $embed_p, $dashmpd); $rtmpe_p, $embed_p, $dashmpd);
my $retries = 5; my $retries = 8;
my $err = undef; my $err = undef;
while (--$retries) { # Sometimes the $info_url fails; try a few times. while (--$retries) { # Sometimes the $info_url fails; try a few times.
my $info_url = ($retries & 1 ? $info_url_1 : $info_url_2);
my ($http, $head); my ($http, $head);
($http, $head, $body) = get_url ($info_url); ($http, $head, $body) = get_url ($info_url);
$err = (check_http_status ($id, $url, $http, 0) ? undef : $http); $err = (check_http_status ($id, $url, $http, 0) ? undef : $http);
@ -2487,15 +2542,26 @@ sub load_youtube_formats($$$) {
$err = undef; $err = undef;
} }
$err = "can't download rental videos" if (!$err && !$urlmap && $rental) {
if (!$err && !$urlmap && $rental); $err = "can't download rental videos";
# With --quiet, just silently ignore livestream failures,
# for "youtubefeed".
exit (0) if ($verbose <= 0);
}
$err = "can't download RTMPE DRM videos" if (!$err && $rtmpe_p) {
if (!$err && $rtmpe_p); $err = "can't download RTMPE DRM videos";
# With --quiet, just silently ignore livestream failures,
# for "youtubefeed".
exit (0) if ($verbose <= 0);
}
if (!$err && !$urlmap && $realtime) { if (!$err && !$urlmap && $realtime) {
$err = "can't download livestream videos"; $err = "can't download livestream videos";
return undef if ($size_p); return undef if ($size_p);
# With --quiet, just silently ignore livestream failures,
# for "youtubefeed".
exit (0) if ($verbose <= 0);
} }
if ($err && $verbose <= 0) { if ($err && $verbose <= 0) {
@ -2528,7 +2594,7 @@ sub load_youtube_formats($$$) {
} }
($title) = ($body =~ m@&title=([^&]+)@si) unless $title; ($title) = ($body =~ m@&title=([^&]+)@si) unless $title;
errorI ("$id: no title in $info_url") if (!$title && $urlmap); errorI ("$id: no title in $info_url_1") if (!$title && $urlmap);
$title = url_unquote($title) if $title; $title = url_unquote($title) if $title;
my $fmts = undef; my $fmts = undef;
@ -3014,6 +3080,11 @@ sub load_twitter_formats($$) {
if ($src =~ m@\.m3u[^/]+$@s) { if ($src =~ m@\.m3u[^/]+$@s) {
# ($http, $head, $body) = get_url ($src); # ($http, $head, $body) = get_url ($src);
#### ... #### ...
# With --quiet, just silently ignore livestream failures,
# for "youtubefeed".
exit (0) if ($verbose <= 0);
error ("Twitter is a piece of shit, we can't handle .m3u8u video"); error ("Twitter is a piece of shit, we can't handle .m3u8u video");
} }
} }
@ -4270,7 +4341,7 @@ sub mux_downloaded_files($$$$$$) {
error ("$id: mismunged filename $muxed_file") error ("$id: mismunged filename $muxed_file")
if ($muxed_file eq $audio_file || $muxed_file eq $video_file); if ($muxed_file eq $audio_file || $muxed_file eq $video_file);
error ("$id: exists: $muxed_file") if (-f $muxed_file); error ("$id: exists: $muxed_file (1)") if (-f $muxed_file);
my @cmd = ('ffmpeg', my @cmd = ('ffmpeg',
# "-hide_banner", # not present in 0.6.5 # "-hide_banner", # not present in 0.6.5
@ -4437,28 +4508,44 @@ sub download_video_url($$$$$$$$$$) {
} }
# Though Tumblr and Twitter can host their own videos, much of the time
# there is just an embedded Youtube video instead.
#
if ($site eq 'tumblr' || $site eq 'twitter') {
my ($http, $head, $body) = get_url ($url);
check_http_status ($id, $url, $http, 1);
if ($body =~ m@ \b ( https?:// (?: [a-z]+\. )?
youtube\.com/
[^\"\'<>]*? (?: embed | \?v= )
[^\"\'<>]+ )@six) {
($url, $id, $site) = canonical_url (html_unquote ($1));
}
}
my $suf = (" [" . $id . my $suf = (" [" . $id .
($force_fmt && $force_fmt ne 'mux' ? " $force_fmt" : "") . ($force_fmt && $force_fmt ne 'mux' ? " $force_fmt" : "") .
"]"); "]");
if (! ($size_p || $list_p)) { if (! ($size_p || $list_p)) {
# If we're writing with --suffix, we can check for an existing file before # If we're writing with --suffix, we can check for an existing
# knowing the title of the video. Check for a file with "[this-ID]" in it. # file before knowing the title of the video. Check for a file
# (The quoting rules of perl's "glob" function are ridiculous and # with "[this-ID]" in it. (The quoting rules of perl's "glob"
# confusing, so let's do it the hard way instead.) # function are ridiculous and confusing, so let's do it the hard
# way instead.)
# #
opendir (my $dir, '.') || error ("readdir: $!"); opendir (my $dir, '.') || error ("readdir: $!");
foreach my $f (readdir ($dir)) { foreach my $f (readdir ($dir)) {
if ($f =~ m/\Q$suf\E/s) { if ($f =~ m/\Q$suf\E/s) {
exit (1) if ($verbose <= 0); # Skip silently if --quiet. exit (1) if ($verbose <= 0); # Skip silently if --quiet.
error ("$id: exists: $f"); error ("$id: exists: $f (2)");
} }
} }
closedir $dir; closedir $dir;
if (defined($outfile)) { if (defined($outfile)) {
error ("$id: exists: $outfile") if (-f $outfile); error ("$id: exists: $outfile (3)") if (-f $outfile);
} elsif (defined($title)) { } elsif (defined($title)) {
# If we already have a --title, we can check for the existence of the # If we already have a --title, we can check for the existence of the
@ -4472,27 +4559,12 @@ sub download_video_url($$$$$$$$$$) {
file_exists_with_suffix ("$title$suf")); file_exists_with_suffix ("$title$suf"));
if ($o) { if ($o) {
exit (1) if ($verbose <= 0); # Skip silently if --quiet. exit (1) if ($verbose <= 0); # Skip silently if --quiet.
error ("$id: exists: $o"); error ("$id: exists: $o (4)");
} }
} }
} }
# Though Tumblr can host its own videos, much of the time there is
# just an embedded Youtube video instead.
#
if ($site eq 'tumblr') {
my ($http, $head, $body) = get_url ($url);
check_http_status ($id, $url, $http, 1);
if ($body =~ m@ \b ( https?:// (?: [a-z]+\. )?
youtube\.com/
[^\"\'<>]*? embed
[^\"\'<>]+ )@six) {
($url, $id, $site) = canonical_url (html_unquote ($1));
}
}
# Videos can come in multiple resolutions, and sometimes with audio and # Videos can come in multiple resolutions, and sometimes with audio and
# video in separate URLs. Get the list of all possible downloadable video # video in separate URLs. Get the list of all possible downloadable video
# formats. # formats.
@ -4535,7 +4607,7 @@ sub download_video_url($$$$$$$$$$) {
file_exists_with_suffix ("$title$suf")); file_exists_with_suffix ("$title$suf"));
if ($o) { if ($o) {
exit (1) if ($verbose <= 0); # Skip silently if --quiet. exit (1) if ($verbose <= 0); # Skip silently if --quiet.
error ("$id: exists: $o"); error ("$id: exists: $o (5)");
} }
} }
} }
@ -4612,6 +4684,12 @@ sub download_video_url($$$$$$$$$$) {
my $file = ($prefix ? "$prefix $title" : $title) . $suf; my $file = ($prefix ? "$prefix $title" : $title) . $suf;
$file .= '.' . content_type_ext($ct); $file .= '.' . content_type_ext($ct);
# If the de-muxed audio or video files are somehow still around
# when we exit, just delete them. We never resume those on the
# next run, so they're useless.
#
push @rm_f, $file if (@pair);
my $ftitle = $file; my $ftitle = $file;
$file = (@pair $file = (@pair
@ -4627,8 +4705,13 @@ sub download_video_url($$$$$$$$$$) {
} }
if (-f $file) { if (-f $file) {
if (($force_fmt || '') eq 'mux') {
# Allow the temporary files used in muxing to be overwritten.
} else {
exit (1) if ($verbose <= 0); # Skip silently if --quiet. exit (1) if ($verbose <= 0); # Skip silently if --quiet.
error ("$id: exists: $file"); error ("$id: exists: $file (6)");
}
} }
print STDERR "$progname: reading \"$ftitle\"\n" if ($verbose > 0); print STDERR "$progname: reading \"$ftitle\"\n" if ($verbose > 0);
@ -4757,6 +4840,7 @@ sub download_youtube_playlist($$$$$$$$$$) {
my ($t2, $u2) = @$P; my ($t2, $u2) = @$P;
eval { eval {
$noerror = 1; $noerror = 1;
utf8::encode ($t2) if defined($t2);
download_video_url ($u2, $t2, $prefix, undef, $size_p, $list_p, download_video_url ($u2, $t2, $prefix, undef, $size_p, $list_p,
$bwlimit, $progress_p, $bwlimit, $progress_p,
$cgi_p, $force_fmt); $cgi_p, $force_fmt);
@ -4819,6 +4903,12 @@ sub do_cgi($$) {
$ct = 'video/mpeg' unless $ct; $ct = 'video/mpeg' unless $ct;
my $ct2 = $1 if ($ct =~ s/\|(.*)$//s); my $ct2 = $1 if ($ct =~ s/\|(.*)$//s);
my $filename_arg = "filename=\"$title\"";
if ($title =~ m/[^\001-\276]/s) { # Contains non-ASCII
# RFC 5987 bad craziness: not supported by some browsers.
$filename_arg .= "; filename*=utf-8''" . url_quote($title);
}
if ($redir) { if ($redir) {
my ($audio) = ($redir =~ s@\|(.*)$@@s); my ($audio) = ($redir =~ s@\|(.*)$@@s);
error ("can't redir URLs that require muxing") if ($audio); error ("can't redir URLs that require muxing") if ($audio);
@ -4827,7 +4917,7 @@ sub do_cgi($$) {
binmode (STDOUT, ':raw'); binmode (STDOUT, ':raw');
print STDOUT ("Content-Type: text/html\n" . print STDOUT ("Content-Type: text/html\n" .
"Location: $redir\n" . "Location: $redir\n" .
"Content-Disposition: attachment; filename=\"$title\"\n" . "Content-Disposition: attachment; $filename_arg\n" .
"\n" . "\n" .
"<A HREF=\"$redir\">$title</A>\n" . "<A HREF=\"$redir\">$title</A>\n" .
"\n"); "\n");
@ -4887,7 +4977,7 @@ sub do_cgi($$) {
print STDOUT ("Content-Type: $ct\n" . print STDOUT ("Content-Type: $ct\n" .
"Content-Length: $size\n" . "Content-Length: $size\n" .
"Content-Disposition: attachment; filename=\"$title\"\n". "Content-Disposition: attachment; $filename_arg\n" .
"\n"); "\n");
binmode (STDOUT, ':raw'); binmode (STDOUT, ':raw');
@ -4899,7 +4989,7 @@ sub do_cgi($$) {
} else { } else {
# Otherwise we can just stream it without involving the disk. # Otherwise we can just stream it without involving the disk.
print STDOUT "Content-Disposition: attachment; filename=\"$title\"\n"; print STDOUT "Content-Disposition: attachment; $filename_arg\n";
binmode (STDOUT, ':raw'); binmode (STDOUT, ':raw');
get_url ($proxy, undef, '-', $bwlimit); get_url ($proxy, undef, '-', $bwlimit);
} }