diff --git a/src/Commands/IslandoraInplaceMediaCommands.php b/src/Commands/IslandoraInplaceMediaCommands.php new file mode 100644 index 0000000..0a091c2 --- /dev/null +++ b/src/Commands/IslandoraInplaceMediaCommands.php @@ -0,0 +1,155 @@ +fileSystem = $fileSystem; + $this->fileRepository = $fileRepository; + $this->logger = $logger; + $this->state = $state; + $this->queueFactory = $queueFactory; + } + + /** + * Process media files (optionally queued and resumable). + * + * @command islandora:inplace-media + * @aliases iim + * + * @option source_dir + * @option destination_path + * @option media_type + * @option media_use + * @option file_type + * @option ownership + * @option queue + * Queue files instead of processing immediately. + * @option reset + * Reset saved progress. + */ + public function inplaceMedia(array $options = [ + 'source_dir' => NULL, + 'destination_path' => NULL, + 'media_type' => NULL, + 'media_use' => NULL, + 'file_type' => 'field_media_file', + 'ownership' => NULL, + 'queue' => FALSE, + 'reset' => FALSE, + ]): void { + + $files = array_diff(scandir($options['source_dir']), ['.', '..']); + + $job_id = hash('sha256', serialize($options)); + $state_key = "islandora_inplace_media.progress.$job_id"; + + if ($options['reset']) { + $this->state->delete($state_key); + $this->output()->writeln('Progress reset.'); + } + + $processed = $this->state->get($state_key, []); + $remaining = array_values(array_diff($files, $processed)); + + if (empty($remaining)) { + $this->output()->success('Nothing left to process.'); + return; + } + + if ($options['queue']) { + $this->enqueueFiles($remaining, $options); + $this->output()->success('Files queued for processing.'); + return; + } + + $progress = new ProgressBar($this->output(), count($remaining)); + $progress->start(); + + foreach ($remaining as $file_name) { + $this->processFile($file_name, $options); + $processed[] = $file_name; + $this->state->set($state_key, $processed); + $progress->advance(); + } + + $progress->finish(); + $this->output()->newLine(2); + $this->output()->success('Processing complete.'); + } + + /** + * Enqueue files for background processing. + */ + protected function enqueueFiles(array $files, array $options): void { + $queue = $this->queueFactory->get('islandora_inplace_media'); + + foreach ($files as $file) { + $queue->createItem([ + 'file' => $file, + 'options' => $options, + ]); + } + } + + /** + * Process a single file. + */ + protected function processFile(string $file_name, array $build_data): void { + $source = "{$build_data['source_dir']}/{$file_name}"; + $dest = "{$build_data['destination_path']}/{$file_name}"; + + if (!file_exists($source)) { + $this->logger->warning('Missing file @file', ['@file' => $source]); + return; + } + + $path = ($source === $dest) + ? $dest + : $this->fileSystem->copy($source, $dest, FileExists::Rename); + + $file = $this->fileRepository->loadByUri($path) + ?? File::create(['uri' => $path, 'status' => 1]); + + $file->save(); + + preg_match('/^(\d+)_/', $file_name, $m); + $nid = $m[1] ?? NULL; + + Media::create([ + 'bundle' => $build_data['media_type'], + 'name' => $file_name, + $build_data['file_type'] => ['target_id' => $file->id()], + 'field_media_use' => ['target_id' => $build_data['media_use']], + 'field_media_of' => $nid, + ])->save(); + } + +} diff --git a/src/Plugin/QueueWorker/InplaceMediaQueueWorker.php b/src/Plugin/QueueWorker/InplaceMediaQueueWorker.php new file mode 100644 index 0000000..8bd2106 --- /dev/null +++ b/src/Plugin/QueueWorker/InplaceMediaQueueWorker.php @@ -0,0 +1,20 @@ +processFile($data['file'], $data['options']); + } +}