App-YoutubeDlIf
view release on metacpan or search on metacpan
lib/App/YoutubeDlIf.pm view on Meta::CPAN
sub _search_id_in_log_file {
my ($id, $path) = @_;
state $cache = do {
my %mem;
open my($fh), "<", $path or die "Can't open log file '$path': $!";
while (my $line = <$fh>) {
chomp $line;
if (my $video_id = YouTube::Util::extract_youtube_video_id($line)) {
next if $mem{$video_id};
$mem{$video_id} = $line;
}
}
#use DD; dd \%mem;
\%mem;
};
$cache->{$id};
}
sub _dur2sec {
my $dur = shift;
return undef unless defined $dur;
if ($dur =~ /\A(?:(\d+):)?(?:(\d{1,2}):)(\d{1,2})$/) {
return ($1 // 0)*3600 + $2*60 + $3;
} else {
die "Can't parse duration '$dur'";
}
}
$SPEC{youtube_dl_if} = {
v => 1.1,
summary => 'Download videos using youtube-dl with extra selection/filtering',
description => <<'_',
This is a wrapper for **youtube-dl**.
_
args => {
%args_common,
%arg_if_not_yet,
},
args_rels => {
#dep_any => [log_file => ['if_not_yet']], # XXX currently will fail if if_not_yet not specified because of the log_file's default
},
deps => {
prog => 'youtube-dl',
},
};
sub youtube_dl_if {
my %args = @_;
my $re_video_id = $Regexp::Pattern::YouTube::RE{video_id}{pat} or die;
$re_video_id = qr/\A$re_video_id\z/;
#use DD; dd $re_video_id;
my @argv_for_youtube_dl;
ARG:
for my $arg (@{$args{urls_or_ids}}) {
FILTER: {
# looks like an option name
last FILTER if $arg =~ /\A--?\w+/ && $arg !~ $re_video_id;
my $video_id = YouTube::Util::extract_youtube_video_id($arg);
if ($video_id) {
log_trace "Argument %s has video ID %s", $arg, $video_id;
if ($args{if_not_yet}) {
if (my $filename = _search_id_in_log_file($video_id, $args{log_file})) {
log_info "Argument %s (video ID %s) has been downloaded (%s), skipped", $arg, $video_id, $filename;
next ARG;
} else {
log_trace "Argument %s (video ID %s) is not in downloaded list", $arg, $video_id;
}
}
}
if (defined $args{if_duration_not_shorter_than} || defined $args{if_duration_not_longer_than}) {
my $min_secs = _dur2sec($args{if_duration_not_shorter_than});
my $max_secs = _dur2sec($args{if_duration_not_longer_than});
my $video_dur = readpipe({log=>1, die=>1}, "youtube-dl --no-playlist --get-duration -- '$arg' 2>/dev/null");
my $video_secs = _dur2sec($video_dur);
if (defined $min_secs && $video_secs < $min_secs) {
log_info "Argument %s (video ID %s, duration %s) is too short (min %s), skipped", $arg, $video_id, $video_dur, $args{if_duration_not_shorter_than};
next ARG;
}
if (defined $max_secs && $video_secs > $max_secs) {
log_info "Argument %s (video ID %s, duration %s) is too long (min %s), skipped", $arg, $video_id, $video_dur, $args{if_duration_not_longer_than};
next ARG;
}
}
} # FILTER
push @argv_for_youtube_dl, $arg;
}
my $do_govern;
$do_govern = 1 if defined $args{restart_if_no_output_after};
if ($do_govern) {
my @opts_for_govern;
push @opts_for_govern, "--restart-if-no-output-after", $args{restart_if_no_output_after}
if defined $args{restart_if_no_output_after};
system({log=>1, die=>1}, "govproc", @opts_for_govern, "--", "youtube-dl", @argv_for_youtube_dl);
} else {
system({log=>1, die=>1}, "youtube-dl", @argv_for_youtube_dl);
}
[200];
}
$SPEC{youtube_dl_if_not_yet} = {
v => 1.1,
summary => 'Download videos using youtube-dl if not already downloaded',
description => <<'_',
This is a shortcut for:
% youtube-dl-if --if-not-yet ...
_
args => {
%args_common,
},
( run in 1.112 second using v1.01-cache-2.11-cpan-8f98c5d2c55 )