Move to new db setup

This commit is contained in:
Ryan
2026-09-08 20:31:06 -04:00
parent 78358e0d7b
commit ea46d418bd
18 changed files with 468 additions and 2043 deletions
+153
View File
@@ -0,0 +1,153 @@
#!/usr/bin/perl
use strict;
use warnings;
use DBI;
use Digest::SHA qw(sha256_hex);
use JSON;
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'} || 'videodetect123';
my $dbh = DBI->connect("DBI:mysql:database=$db_name;host=$db_host", $db_user, $db_pass);
my @video_extensions = qw(mp4 mkv avi mov flv wmv mpg mpeg webm);
my @dir_queue = ('/data');
# Get NOW() from the database
my $sth = $dbh->prepare("SELECT NOW() AS now");
$sth->execute();
my $row = $sth->fetchrow_hashref();
my $now = $row->{now};
$sth->finish();
while(my $dir = shift @dir_queue) {
opendir(my $dh, $dir) or die "Cannot open directory $dir: $!";
while (my $file = readdir($dh)) {
next if ($file eq '.' || $file eq '..');
my $full_path = "$dir/$file";
if (-d $full_path) {
unshift @dir_queue, $full_path;
} elsif (-f $full_path) {
process_file($full_path);
}
}
closedir($dh);
}
# Any entry where last_scan_time < $now is considered deleted or moved, so we can mark them as such
my $sth_delete = $dbh->prepare("DELETE FROM videos WHERE last_scan_time < ? OR last_scan_time IS NULL");
$sth_delete->execute($now);
sub process_file {
my ($file_path) = @_;
# Determine if the file is a video based on mime info or extension. For simplicity, let's check the extension.
if (my ($ext)=$file_path =~ /^.+\.(\S+?)$/) {
unless (grep { lc($ext) eq $_ } @video_extensions) {
return; # Not a video file
}
}
my $sth = $dbh->prepare("SELECT id,file_size FROM videos WHERE file_path=?");
$sth->execute($file_path);
if(my $row = $sth->fetchrow_hashref()) {
my $file_size = -s $file_path;
if ($file_size != $row->{file_size}) {
warn "File size mismatch for $file_path. Updating record.";
my $update_sth = $dbh->prepare("UPDATE videos SET file_size=?, last_scan_time=NOW() WHERE id=?");
$update_sth->execute($file_size, $row->{id});
$update_sth->finish();
create_review_task($row->{id});
}
return; # Already exists and size matches
}
my $info = get_video_info($file_path);
unless ($info) {
warn "Failed to get video info for $file_path. Skipping.";
return;
}
$sth = $dbh->prepare("INSERT INTO videos (file_path, file_size, file_hash, resolution_w, resolution_h, codec, duration, last_scan_time) VALUES (?, ?, ?, ?, ?, ?, ?, NOW())");
$sth->execute(
$file_path,
-s $file_path,
$info->{file_hash},
$info->{resolution_w},
$info->{resolution_h},
$info->{codec},
$info->{duration}
);
$sth->finish();
my $video_id = $dbh->last_insert_id(undef, undef, 'videos', undef);
create_review_task($video_id);
}
sub create_review_task {
my ($video_id) = @_;
$dbh->do("DELETE FROM tasks WHERE video_id=$video_id AND task_type='REVIEW'");
my $sth = $dbh->prepare("INSERT INTO tasks (video_id, task_type, status) VALUES (?, 'REVIEW', 'PENDING')");
$sth->execute($video_id);
$sth->finish();
}
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 = sha256_hex($fh);
close($fh);
# --- Run ffprobe to extract metadata ---
my $probe_cmd = qq{ffprobe -v quiet -print_format json -show_format -show_streams '$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,
};
}