From e5d50fa5293ca55a5fea23be344c524c76e007ae Mon Sep 17 00:00:00 2001 From: dakkar Date: Sun, 16 Oct 2016 14:26:21 +0100 Subject: more rough pieces --- anidb-renamer | 9 ++--- lib/AniDB/Datastore.pm | 97 ++++++++++++++++++++++++++++++++++++++++++++++++++ lib/AniDB/Manager.pm | 64 +++++++++++++++++++++++++++++++++ 3 files changed, 166 insertions(+), 4 deletions(-) create mode 100644 lib/AniDB/Datastore.pm create mode 100644 lib/AniDB/Manager.pm diff --git a/anidb-renamer b/anidb-renamer index e9a3451..64d6fc9 100644 --- a/anidb-renamer +++ b/anidb-renamer @@ -7,6 +7,7 @@ use Log::Any::Adapter::Util; use Log::Any '$log'; use Path::Tiny; use Getopt::Long::Descriptive; +use AniDB::Manager; my ($opt, $usage) = describe_options( '%c %o ', @@ -29,7 +30,7 @@ Log::Any::Adapter->set( + $opt->verbose, ); -my $data = AniDB::Data->new($opt->database); +my $anidb = AniDB::Manager->new({database=>$opt->database}); my %new_name_for; for my $dir (@ARGV) { @@ -37,8 +38,8 @@ for my $dir (@ARGV) { while (my $path = $path_iter->()) { next unless $path->is_file; $log->info("looking at $path") - $data->update($path); - if (my $new_name = $data->maybe_new_name_for($path)) { + $anidb->update($path); + if (my $new_name = $anidb->maybe_new_name_for($path)) { $new_name_for{$path->stringify} = $new_name; } } @@ -46,6 +47,6 @@ for my $dir (@ARGV) { for my $current_name (sort keys %new_name_for) { $log->infof('renaming %s to %s',$current_name,$new_name_for{$current_name}); - $data->rename($current_name,$new_name_for{$current_name}); + $anidb->rename($current_name,$new_name_for{$current_name}); } diff --git a/lib/AniDB/Datastore.pm b/lib/AniDB/Datastore.pm new file mode 100644 index 0000000..8db4e16 --- /dev/null +++ b/lib/AniDB/Datastore.pm @@ -0,0 +1,97 @@ +package AniDB::Datastore; +use 5.024; +use experimental 'signatures'; +use Moo; +use Path::Tiny; +use AniDB::Hashing; +use namespace::clean; + +has database => ( is => 'ro', required => 1 ); +has dbh => ( is => 'ro', lazy => 1 ); + +sub _build_dbh($self) { + require DBI; + return DBI->connect( + 'dbi:SQLite:dbname='.$self->database, + '', '', + { + AutoCommit => 1, + RaiseError => 1, + PrintError => 0, + }, + ); +} + +sub update($self,$path) { + my $stat = $path->stat; + + return 0 unless $self->_has_changed($path,$stat); + my $hash = AniDB::Hashing::hash_fd($path->openr_raw); + $self->_update_path_info( + $path => { + size => $stat->size, + mtime => $stat->mtime, + hash => $hash, + }, + ); + return 1; +} + +sub _has_changed($self,$path,$stat) { + my $path_info = $self->path_info_for($path); + return ( + $path_info->{size} == $stat->size + && $path_info->{mtime} == $stat->mtime + ); +} + +sub rename($self,$path,$new_path) { + $self->dbh->do( + q{UPDATE path_info SET name=? WHERE name=?}, + $path->stringify,$new_path->stringify, + ); +} + +sub full_info_for($self,$path) { + my $path_info = $self->path_info_for($path); + my $episode_info = $self->episode_info_for( + $path_info, + ); + my $anime_info = $self->anime_info_for( + $episode_info, + ); + return { + path => $path_info, + episode => $episode_info, + anime => $anime_info, + }; +} + +sub path_info_for($self,$path) { + my $ret = $self->dbh->selectall_arrayref( + qr{SELECT * FROM path_info WHERE name=?}, + { Slice => {} }, + $path->stringify, + ); + return $ret->[0]; +} + +sub episode_info_for($self,$args) { + my $ret = $self->dbh->selectall_arrayref( + qr{SELECT * FROM episode_info WHERE hash=? AND size=?}, + { Slice => {} }, + @{$args}{qw(hash size)}, + ); + return $ret->[0]; +} + +sub anime_info_for($self,$args) { + my $ret = $self->dbh->selectall_arrayref( + qr{SELECT * FROM anime_info WHERE aid=?}, + { Slice => {} }, + @{$args}{qw(aid)}, + ); + return $ret->[0]; +} + +1; diff --git a/lib/AniDB/Manager.pm b/lib/AniDB/Manager.pm new file mode 100644 index 0000000..eeb724f --- /dev/null +++ b/lib/AniDB/Manager.pm @@ -0,0 +1,64 @@ +package AniDB::Manager; +use 5.024; +use experimental 'signatures'; +use Moo; +use Log::Any '$log'; +use Path::Tiny; +use namespace::clean; + +has datastore => ( + is => 'ro', + required => 1, + handles => [qw(update)], +); + +around BUILDARGS => sub($orig,$class,@args) { + my $args = $class->$orig(@args); + if (my $db_name = $args->{database}) { + require AniDB::Datastore; + $args->{datastore} = AniDB::Datastore->new({ + database => $db_name, + }); + } + return $args; +}; + +has renamer => ( + is => 'ro', + lazy => 1, +); + +sub _build_renamer { + require AniDB::Renamer; + return AniDB::Renamer->new(); +} + +sub new_name_for($self,$path) { + $path = path($path)->realpath; + my $full_info = $self->datastore->full_info_for($path); + return $self->renamer->new_name_for($path,$full_info); +} + +sub maybe_new_name_for($self,$path) { + my $new_name = $self->new_name_for($path); + return if $new_name eq $path; + return $new_name; +} + +sub rename($self,$path,$new_path) { + $path = path($path)->realpath; + $new_path ||= $self->new_name_for($path); + if ($path->move($new_path)) { + $self->datastore->rename($path,$new_path); + return 1; + } + else { + $log->errorf( + 'failed to rename %s to %s', + $path, $new_path, + ); + return; + } +} + +1; -- cgit v1.2.3