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 )