106 lines
3.3 KiB
Perl
Executable File
106 lines
3.3 KiB
Perl
Executable File
#!/usr/bin/perl
|
|
use strict;
|
|
use warnings;
|
|
use DBI;
|
|
use Digest::SHA qw(sha256_hex);
|
|
use JSON;
|
|
use String::ShellQuote qw/shell_quote/;
|
|
|
|
my $db_host = $ENV{'DB_HOST'} || 'mariadb';
|
|
my $db_name = $ENV{'DB_NAME'} || 'videodetect';
|
|
my $db_user = $ENV{'DB_USER'} || 'videodetect';
|
|
my $db_pass = $ENV{'DB_PASSWORD'} || 'videodetect';
|
|
|
|
$SIG{INT} = sub { die "Interrupted\n"; };
|
|
|
|
my $dbh = DBI->connect(
|
|
"DBI:mysql:database=$db_name;host=$db_host;mysql_enable_utf8mb4=1",
|
|
$db_user,
|
|
$db_pass,
|
|
{ mysql_auto_reconnect => 1 }
|
|
);
|
|
|
|
|
|
my $sth = $dbh->prepare("SELECT id, file_path FROM videos ORDER BY id");
|
|
my $upd = $dbh->prepare("UPDATE videos SET file_size=?, file_hash=?, resolution_w=?, resolution_h=?, codec=?, duration=? WHERE id=?");
|
|
$sth->execute();
|
|
while (my($id,$path)=$sth->fetchrow_array()) {
|
|
print "$path\n";
|
|
my $info = get_video_info($path);
|
|
if ($info) {
|
|
$upd->execute(
|
|
-s $path,
|
|
$info->{file_hash},
|
|
$info->{resolution_w},
|
|
$info->{resolution_h},
|
|
$info->{codec},
|
|
$info->{duration},
|
|
$id
|
|
);
|
|
}
|
|
}
|
|
$sth->finish();
|
|
$upd->finish();
|
|
$dbh->disconnect();
|
|
|
|
sub get_video_info {
|
|
my ($file_path) = @_;
|
|
|
|
# --- Compute SHA-256 hash of the file ---
|
|
return undef unless -f $file_path && -r $file_path;
|
|
open(my $fh, '<:raw', $file_path) or do { warn "Cannot open $file_path: $!"; return undef; };
|
|
my $hash = Digest::SHA->new(256)->addfile($fh)->hexdigest;
|
|
close($fh);
|
|
|
|
|
|
|
|
# --- Run ffprobe to extract metadata ---
|
|
my $probe_cmd = 'ffprobe -v quiet -print_format json -show_format -show_streams ' . shell_quote($file_path);
|
|
my $output = `$probe_cmd`;
|
|
return undef unless defined $output && length($output);
|
|
|
|
my $json = JSON->new->utf8->canonical(1);
|
|
my $data = $json->decode($output);
|
|
|
|
# --- Extract codec from video stream (prefer first video stream found) ---
|
|
my $codec = undef;
|
|
if (exists $data->{streams} && ref($data->{streams}) eq 'ARRAY') {
|
|
for my $stream (@{$data->{streams}}) {
|
|
if ($stream->{codec_type} eq 'video') {
|
|
$codec = $stream->{codec_name};
|
|
last;
|
|
}
|
|
}
|
|
}
|
|
|
|
# --- Extract resolution and duration from format/streams ---
|
|
my ($resolution_w, $resolution_h, $duration);
|
|
|
|
# Duration from format first, then stream
|
|
if (exists $data->{format} && exists $data->{format}{duration}) {
|
|
$duration = $data->{format}{duration} + 0; # force numeric
|
|
} elsif (exists $data->{streams}[0] && exists $data->{streams}[0]{duration}) {
|
|
$duration = $data->{streams}[0]{duration} + 0;
|
|
}
|
|
|
|
# Resolution from video stream first, then format side data
|
|
if (exists $data->{streams} && ref($data->{streams}) eq 'ARRAY') {
|
|
for my $stream (@{$data->{streams}}) {
|
|
next unless $stream->{codec_type} eq 'video';
|
|
if ($stream->{width} && $stream->{height}) {
|
|
$resolution_w = $stream->{width};
|
|
$resolution_h = $stream->{height};
|
|
last;
|
|
}
|
|
}
|
|
}
|
|
|
|
return {
|
|
file_hash => $hash,
|
|
resolution_w => $resolution_w // 0,
|
|
resolution_h => $resolution_h // 0,
|
|
codec => $codec // 'unknown',
|
|
duration => $duration,
|
|
};
|
|
}
|