Skip to content

Instantly share code, notes, and snippets.

@skaji
Created March 22, 2014 16:35
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save skaji/9710019 to your computer and use it in GitHub Desktop.
Save skaji/9710019 to your computer and use it in GitHub Desktop.
#!/usr/bin/env perl
use strict;
use warnings;
use utf8;
use Encode qw{ encode decode };
use WWW::YouTube::Download;
use Term::ReadKey ();
use List::Util qw(first);
use File::Temp ();
use File::Spec ();
use IO::Handle;
use constant {
WIN => $^O eq 'MSWin32',
MAC => $^O eq 'darwin',
};
die 'Only for MSWin32 or Mac.' if !WIN && !MAC;
STDOUT->autoflush;
my @AAC_FMT_LIST = qw{37 22 35 34 18};
my ($TERMINAL_WIDTH) = Term::ReadKey::GetTerminalSize();
print "Input a video URL:\n";
chomp(my $video_url = <STDIN>);
my $client = WWW::YouTube::Download->new;
my $meta = $client->prepare_download($video_url);
my ($title, $fmt, $suffix) = get_title_fmt_suffix($meta);
my $dir = File::Temp->newdir(CLEANUP => 1);
my $filename = File::Spec->catfile($dir, $title);
print "Dir: $dir\n";
# ビデオダウンロード
open my $fh, '>:raw', $filename or die "Cannot open $filename: $!";
print "Downloading: $title (suffix=$suffix, fmt=$fmt)\n";
eval {
$client->download($video_url, {fmt => $fmt, cb => \&callback});
};
die "Error: Can't complete downloading: $@" if $@;
close $fh;
print "Successfully finished downloading.\n";
# ffmpeg
my $null = WIN ? 'nul' : '/dev/null';
system qq|ffmpeg -i "$filename" -vn |
.qq|-acodec copy -y "$filename.m4a" 1> $null 2>&1|;
# iTunes
if (WIN) {
system qq|start iTunes "$filename.m4a"|;
}
elsif (MAC) {
system qw{open -a /Applications/iTunes.app}, "$filename.m4a";
}
print "Waiting 20 seconds to start iTunes.....\n";
sleep 30;
exit;
sub callback {
my ($chunk, $res, $proto) = @_;
print {$fh} $chunk;
my $size = tell $fh;
my $total = $res->header('Content-Length');
my $width = $TERMINAL_WIDTH - 26;
my $progress = int($size / $total * $width);
printf "Total:%5.1fMB (%5.1f%%)", (
$total / 1024 / 1024, $size / $total * 100
);
print '[';
print '=' x $progress;
print ' ' x ($width - $progress);
print "]\r";
print "\n" if $total == $size;
}
sub get_title_fmt_suffix {
my $meta = shift;
my $title = filename_normalize(
decode('utf8', $meta->{title})
);
if (WIN) {
$title = encode('cp932', $title);
}
elsif (MAC) {
$title = encode('utf8', $title);
}
my $fmt = _get_aac_fmt( $meta->{fmt_list} );
my $suffix = $meta->{video_url_map}{$fmt}{suffix};
return ($title, $fmt, $suffix);
}
sub _get_aac_fmt {
my %get_fmt_list = map { $_ => 1 } @{shift()};
first { exists $get_fmt_list{$_} } @AAC_FMT_LIST;
}
# 以下は youtube-download からの丸写し
sub filename_normalize {
my $filename = shift;
$filename =~ s#[[:cntrl:]]##smg; # remove all control characters
$filename =~ s#^\s+|\s+$##g; # trim spaces
$filename =~ s#^\.+##; # remove multiple leading dots
$filename =~ tr#"/\\:*?<>|#'\-\-\-_____#; # NTFS and FAT unsupported characters
return $filename;
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment