From a3013078e082d86669bd557c602e63ced28be0e0 Mon Sep 17 00:00:00 2001 From: Deon George Date: Mon, 2 Sep 2024 22:51:19 +1000 Subject: [PATCH] Photo scan and move implemented, and remove redundant files --- app/Console/Commands/CatalogAutoDelete.php | 73 ---------- app/Console/Commands/CatalogMove.php | 45 ++----- app/Console/Commands/CatalogScan.php | 8 +- app/Console/Commands/VideoImport.php | 149 --------------------- app/Console/Commands/VideoMove.php | 102 -------------- app/Jobs/CatalogMove.php | 76 +++++++++++ app/Jobs/CatalogScan.php | 10 +- app/Jobs/PhotoMove.php | 39 ------ app/Jobs/VideoMove.php | 39 ------ app/Models/Abstracted/Catalog.php | 23 ++-- app/Models/Photo.php | 24 +++- app/Providers/AppServiceProvider.php | 21 +-- config/filesystems.php | 1 + 13 files changed, 131 insertions(+), 479 deletions(-) delete mode 100644 app/Console/Commands/CatalogAutoDelete.php delete mode 100644 app/Console/Commands/VideoImport.php delete mode 100644 app/Console/Commands/VideoMove.php create mode 100644 app/Jobs/CatalogMove.php delete mode 100644 app/Jobs/PhotoMove.php delete mode 100644 app/Jobs/VideoMove.php diff --git a/app/Console/Commands/CatalogAutoDelete.php b/app/Console/Commands/CatalogAutoDelete.php deleted file mode 100644 index 7c6b099..0000000 --- a/app/Console/Commands/CatalogAutoDelete.php +++ /dev/null @@ -1,73 +0,0 @@ -getModelType($this->argument('type')); - - $class::where('remove',1)->each(function($o) { - foreach ($o->myduplicates()->get() as $oo) { - if (! $oo->signature OR ! $oo->file_signature) - continue; - - if ($oo->signature == $o->signature AND $oo->file_signature == $o->file_signature) { - $this->info(sprintf('Removing: %s (%s)',$o->id,$o->filename)); - - // Dispatch Job to move file. - switch (strtolower($this->argument('type'))) { - case 'photo': - $this->dispatch((new PhotoDelete($o))->onQueue('delete')); - break; - - case 'video': - $this->dispatch((new VideoDelete($o))->onQueue('delete')); - break; - - default: - $this->error('Dont know how to handle: ',$this->argument('type')); - } - } - } - }); - } -} \ No newline at end of file diff --git a/app/Console/Commands/CatalogMove.php b/app/Console/Commands/CatalogMove.php index 0683436..33f6f3c 100644 --- a/app/Console/Commands/CatalogMove.php +++ b/app/Console/Commands/CatalogMove.php @@ -3,27 +3,29 @@ namespace App\Console\Commands; use Illuminate\Console\Command; -use Illuminate\Foundation\Bus\DispatchesJobs; -use App\Jobs\{PhotoMove,VideoMove}; +use App\Jobs\CatalogMove as Job; +use App\Traits\Type; class CatalogMove extends Command { - use DispatchesJobs; + use Type; /** * The name and signature of the console command. * * @var string */ - protected $signature = 'catalog:move {type : Photo | Video }'; + protected $signature = 'catalog:move' + .' {type : Photo | Video }' + .' {id : Photo ID}'; /** * The console command description. * * @var string */ - protected $description = 'Trigger Moves'; + protected $description = 'Move Photo/Video based on their meta data'; /** * Execute the console command. @@ -32,35 +34,10 @@ class CatalogMove extends Command */ public function handle() { - $class = 'App\Models\\'.$this->argument('type'); + $class = $this->getModelType($this->argument('type')); - if (! class_exists($class)) - abort(500,sprintf('No class [%s]',$this->argument('type'))); + $o = $class::findOrFail($this->argument('id')); - foreach ($class::where('filename','LIKE','%INCOMING%')->get() as $o) { - // Catch any files that are already there. - if ($o->moveable() === 1) { - $o->duplicate = TRUE; - $o->save(); - continue; - } - - $x = NULL; - if (! $o->scanned OR $o->duplicate OR $o->remove OR ($x=$o->moveable()) !== TRUE) { - $this->warn(sprintf('Ignoring (%s)[%s]... [%s]',$o->id,$o->file_path(),$x)); - continue; - } - - switch (strtolower($this->argument('type'))) { - case 'photo': - $this->dispatch((new PhotoMove($o))->onQueue('move')); - break; - case 'video': - $this->dispatch((new VideoMove($o))->onQueue('move')); - break; - default: - $this->error('Dont know how to handle: ',$this->argument('type')); - } - } + return Job::dispatchSync($o); } -} +} \ No newline at end of file diff --git a/app/Console/Commands/CatalogScan.php b/app/Console/Commands/CatalogScan.php index 6137257..6f85d79 100644 --- a/app/Console/Commands/CatalogScan.php +++ b/app/Console/Commands/CatalogScan.php @@ -16,10 +16,10 @@ class CatalogScan extends Command * * @var string */ - protected $signature = 'catalog:scan'. - ' {type : Photo | Video }'. - ' {id : Photo ID}'. - ' {--dirty : Show Dirty}'; + protected $signature = 'catalog:scan' + .' {type : Photo | Video }' + .' {id : Photo ID}' + .' {--dirty : Show Dirty}'; /** * The console command description. diff --git a/app/Console/Commands/VideoImport.php b/app/Console/Commands/VideoImport.php deleted file mode 100644 index 39ab822..0000000 --- a/app/Console/Commands/VideoImport.php +++ /dev/null @@ -1,149 +0,0 @@ -getFiles([ - 'dir'=>$this->option('dir'), - 'file'=>$this->option('file') - ],'video'); - - if (! count($files)) - exit; - - // Show a progress bar - $bar = $this->output->createProgressBar(count($files)); - $bar->setFormat("%current%/%max% [%bar%] %percent:3s%% (%memory%) (%remaining%) "); - - $tags = NULL; - $t = $p = array(); - - // Tags - if ($this->option('tags')) { - $tags = explode(',',$this->option('tags')); - $t = Tag::whereIn('tag',$tags)->pluck('id')->toArray(); - - if (! $t OR count($t) != count($tags)) { - $this->error(sprintf('Tag [%s] dont exist',join('|',$tags))); - abort(501); - } - } - - // People - if ($this->option('people')) { - $tags = explode(',',$this->option('people')); - $p = Person::whereIn('tag',$tags)->pluck('id')->toArray(); - - if (! $p OR count($p) != count($tags)) - { - $this->error(sprintf('People [%s] dont exist',join('|',$tags))); - abort(501); - } - } - - $c = 0; - foreach ($files as $file) { - $bar->advance(); - - if (preg_match('/@__thumb/',$file) OR preg_match('/\/._/',$file)) { - $this->warn(sprintf('Ignoring file [%s]',$file)); - continue; - } - - if (! in_array(strtolower(pathinfo($file,PATHINFO_EXTENSION)),config('video.import.accepted'))) { - $this->warn(sprintf('Ignoring [%s]',$file)); - continue; - } - - if ($this->option('verbose')) - $this->info(sprintf('Processing file [%s]',$file)); - - $c++; - - $o = Video::where('filename',$file)->first(); - - // The video doesnt exist - if (is_null($o)) { - $o = new Video; - $o->filename = $file; - } - - if ($o->exists) - $this->warn(sprintf('%s [%s] already in DB: %s',$o->objectType(),$file,$o->id)); - - // Make sure we can read the video. - if (! is_readable($o->file_path())) { - $this->warn(sprintf('Ignoring [%s], it is not readable',$o->file_path())); - continue; - } - - $o->save(); - - if ($o->wasRecentlyCreated) - $this->info(sprintf('%s [%s] stored in DB: %s',$o->objectType(),$file,$o->id)); - - // Record our people and tags - if ($p) - $o->People()->sync($p); - if ($t) - $o->Tags()->sync($t); - - $this->dispatch((new \App\Jobs\CatalogScan($o))->onQueue('scan')); - - if ($this->option('dumpid3')) - dd($o->properties()); - } - - $bar->finish(); - - return $this->info(sprintf('Videos processed: %s',$c)); - } -} \ No newline at end of file diff --git a/app/Console/Commands/VideoMove.php b/app/Console/Commands/VideoMove.php deleted file mode 100644 index dcba9cb..0000000 --- a/app/Console/Commands/VideoMove.php +++ /dev/null @@ -1,102 +0,0 @@ -option('file')) { - $vo = Video::notRemove()->notDuplicate()->where('filename',Video::path($this->option('file'))); - - } elseif ($this->option('id')) { - $vo = Video::notRemove()->notDuplicate()->where('id',$this->option('id')); - - } else { - $vo = Video::notRemove()->notDuplicate(); - } - - if (! $vo) - exit; - - // Show a progress bar - $bar = $this->output->createProgressBar($vo->count()); - $bar->setFormat("%current%/%max% [%bar%] %percent:3s%% (%memory%) (%remaining%) "); - $bar->setRedrawFrequency(100); - - $vo->chunk(1,function($video) use ($bar) { - while ($o = $video->shift()) { - if (($x = $o->moveable()) === TRUE) { - Log::info(sprintf('%s: Moving (%s)[%s]',__METHOD__,$o->id,$o->filename)); - - if ($this->makeParentDir(dirname($o->file_path(FALSE,TRUE))) AND rename($o->file_path(),$o->file_path(FALSE,TRUE))) { - // Convert the path to a relative one. - $o->filename = $o->file_path(TRUE,TRUE); - - // @todo If the DB update failed, move it back. - if (! $o->save()) # AND ! rename($path,$o->file_path())) - { - $this->error(sprintf('Save after rename failed for (%s)',$o->id)); - continue; - } - - } else { - $this->error(sprintf('Rename failed for (%s)',$o->id)); - continue; - } - - chmod($o->file_path(),0444); - - } else { - if ($x > 0) { - $this->warn(sprintf('Unable to move (%s) [%s] to [%s], movable returned (%s)',$o->id,$o->file_path(),$o->file_path(FALSE,TRUE),$x)); - - if ($x == 1 AND $v = Video::where('filename',$o->file_path(TRUE,TRUE))->first()) - $this->warn(sprintf('File is id (%s) [%s]',$v->file_path(),$v->id)); - } - } - } - - $bar->advance(); - }); - } -} \ No newline at end of file diff --git a/app/Jobs/CatalogMove.php b/app/Jobs/CatalogMove.php new file mode 100644 index 0000000..38c72c0 --- /dev/null +++ b/app/Jobs/CatalogMove.php @@ -0,0 +1,76 @@ +o = $o->withoutRelations(); + } + + public function middleware(): array + { + return [new WithoutOverlapping($this->o->id)]; + } + + /** + * Execute the job. + * + * @return void + * @throws \Exception + */ + public function handle() + { + $from = $this->o->file_name_rel(TRUE); + $to = $this->o->file_name_rel(FALSE); + + Log::info(sprintf('%s: Moving [%s|%s] from [%s] to [%s]', + __METHOD__, + $this->o->objecttype(), + $this->o->id, + $from, + $to, + )); + + // If the move is successful, commit the transaction + if ($this->o->isMoveable()) { + // If our move fails, we'll abort the update + DB::beginTransaction(); + $this->o->filename = $this->o->file_name(); + $this->o->save(); + + if (Storage::disk($this->o::fs)->move($from,$to)) + DB::commit(); + else + Log::error(sprintf('%s: Move failed for file [%s]',__METHOD__,$from)); + + } else + Log::alert(sprintf('%s: Unable to move file [%s] with reason [%s]', + __METHOD__, + $from, + $this->o->isMoveableReason(), + )); + } +} \ No newline at end of file diff --git a/app/Jobs/CatalogScan.php b/app/Jobs/CatalogScan.php index e7fd562..44c8f0e 100644 --- a/app/Jobs/CatalogScan.php +++ b/app/Jobs/CatalogScan.php @@ -30,11 +30,19 @@ class CatalogScan implements ShouldQueue, ShouldBeUnique $this->show_dirty = $show_dirty; } - public function xmiddleware(): array + public function middleware(): array { return [new WithoutOverlapping($this->o->id)]; } + /** + * Get the unique ID for the job. + */ + public function uniqueId(): string + { + return $this->o->id; + } + /** * Execute the job. * diff --git a/app/Jobs/PhotoMove.php b/app/Jobs/PhotoMove.php deleted file mode 100644 index ae60be1..0000000 --- a/app/Jobs/PhotoMove.php +++ /dev/null @@ -1,39 +0,0 @@ -photo = $o; - } - - /** - * Execute the job. - * - * @return void - */ - public function handle() - { - Log::info(sprintf('%s: Moving [%s]',__METHOD__,$this->photo->id)); - Artisan::call('photo:move',['--id' => $this->photo->id]); - } -} diff --git a/app/Jobs/VideoMove.php b/app/Jobs/VideoMove.php deleted file mode 100644 index 76e94fa..0000000 --- a/app/Jobs/VideoMove.php +++ /dev/null @@ -1,39 +0,0 @@ -video = $o; - } - - /** - * Execute the job. - * - * @return void - */ - public function handle() - { - Log::info(sprintf('%s: Moving [%s]',__METHOD__,$this->video->id)); - Artisan::call('video:move',['--id' => $this->video->id]); - } -} diff --git a/app/Models/Abstracted/Catalog.php b/app/Models/Abstracted/Catalog.php index c795f74..b5ea920 100644 --- a/app/Models/Abstracted/Catalog.php +++ b/app/Models/Abstracted/Catalog.php @@ -22,7 +22,7 @@ abstract class Catalog extends Model 'thumbnail' => PostgresBytea::class, ]; - protected const fs = 'nas'; + public const fs = 'nas'; private ?string $move_reason; @@ -271,7 +271,12 @@ abstract class Catalog extends Model } else return Storage::disk(self::fs) - ->path(config(static::config.'.dir').DIRECTORY_SEPARATOR.$this->filename); + ->path($this->file_name_rel()); + } + + public function file_name_rel(bool $source=TRUE): string + { + return config(static::config.'.dir').DIRECTORY_SEPARATOR.($source ? $this->filename : $this->file_name()); } /** @@ -285,7 +290,7 @@ abstract class Catalog extends Model if ($new) $file = $this->file_name(TRUE); - return (($short OR preg_match('/^\//',$file)) ? '' : config($this->type.'.dir').DIRECTORY_SEPARATOR).$file; + return (($short OR preg_match('/^\//',$file)) ? '' : config(static::config.'.dir').DIRECTORY_SEPARATOR).$file; } /** @@ -507,18 +512,6 @@ abstract class Catalog extends Model return is_readable($this->file_name(FALSE)); } - /** - * Determine if a file is moveable - * - * useID boolean Determine if the path is based on the the ID or date - * @todo Change to boolean and rename isMoveable() Log any FALSE reason. - */ - public function moveable() - { - Log::alert(__METHOD__.' deprecated'); - return $this->isMoveable(); - } - /** * Get the id of the next record */ diff --git a/app/Models/Photo.php b/app/Models/Photo.php index 6e67aec..3c5c00c 100644 --- a/app/Models/Photo.php +++ b/app/Models/Photo.php @@ -4,9 +4,12 @@ namespace App\Models; use Carbon\Carbon; use Illuminate\Support\Facades\Log; +use Illuminate\Support\Facades\Route; use Illuminate\Support\Traits\ForwardsCalls; use Imagick; +use App\Jobs\CatalogMove; + class Photo extends Abstracted\Catalog { use ForwardsCalls; @@ -28,11 +31,26 @@ class Photo extends Abstracted\Catalog // How should the image be rotated, based on the value of orientation private array $_rotate = [ - 3=>180, - 6=>90, - 8=>-90, + 3 => 180, + 6 => 90, + 8 => -90, ]; + public static function boot() + { + parent::boot(); + + // Any photo saved, queue it to be moved. + self::saved(function($item) { + if ($item->scanned && (! $item->duplicate) && (! $item->remove) && ($x=$item->shouldMove()) === TRUE) { + Log::info(sprintf('%s: Need to Move [%s]','Photo',$item->id.'|'.serialize($x))); + + CatalogMove::dispatch($item) + ->onQueue('move'); + } + }); + } + /** * Calculate the GPS coordinates */ diff --git a/app/Providers/AppServiceProvider.php b/app/Providers/AppServiceProvider.php index fbb34d8..3b8efa2 100644 --- a/app/Providers/AppServiceProvider.php +++ b/app/Providers/AppServiceProvider.php @@ -2,13 +2,11 @@ namespace App\Providers; -use Illuminate\Support\Facades\Log; use Illuminate\Support\Facades\Route; use Illuminate\Support\ServiceProvider; use Illuminate\Foundation\Bus\DispatchesJobs; use App\Models\{Photo,Video}; -use App\Jobs\{PhotoMove,VideoMove}; class AppServiceProvider extends ServiceProvider { @@ -32,23 +30,6 @@ class AppServiceProvider extends ServiceProvider public function boot(): void { Route::model('po',Photo::class); - - // Any photo saved, queue it to be moved. - Photo::saved(function($photo) { - if ($photo->scanned && (! $photo->duplicate) && (! $photo->remove) && ($x=$photo->moveable()) === TRUE) { - Log::info(sprintf('%s: Need to Move [%s]',__METHOD__,$photo->id.'|'.serialize($x))); - - PhotoMove::dispatch($photo)->onQueue('move'); - } - }); - - // Any video saved, queue it to be moved. - Video::saved(function($video) { - if ($video->scanned AND ! $video->duplicate AND ! $video->remove AND ($x=$video->moveable()) === TRUE) { - Log::info(sprintf('%s: Need to Move [%s]',__METHOD__,$video->id.'|'.serialize($x))); - - $this->dispatch((new VideoMove($video))->onQueue('move')); - } - }); + Route::model('vo',Video::class); } } \ No newline at end of file diff --git a/config/filesystems.php b/config/filesystems.php index 48a9033..ef86f79 100644 --- a/config/filesystems.php +++ b/config/filesystems.php @@ -40,6 +40,7 @@ return [ 'driver' => 'local', 'root' => storage_path('nas'), 'throw' => false, + 'visibility' => 'public', ], 'public' => [