1
0

Improved LEGO bundles update

This commit is contained in:
Richard Dern 2024-05-12 14:47:44 +02:00
parent 82b76db6a5
commit e236e09998
6 changed files with 209 additions and 47 deletions

View File

@ -94,23 +94,36 @@ public function add(array $data): string
if (!empty($data['contents'])) { if (!empty($data['contents'])) {
// Adding from an image resource of which $data['contents'] is a // Adding from an image resource of which $data['contents'] is a
// representation // representation
$contents = $data['contents']; $contents = $data['contents'];
$checksum = md5($contents);
$existingRef = $this->findAttachmentByChecksum($checksum);
if (!empty($existingRef)) {
return $existingRef;
}
$data['checksum'] = $checksum;
unset($data['contents']); unset($data['contents']);
} elseif (!empty($data['url'])) { } elseif (!empty($data['original_url'])) {
$existingRef = $this->findAttachmentByOriginalUrl($data['url']); $existingRef = $this->findAttachmentByOriginalUrl($data['original_url']);
if (!empty($existingRef)) { if (!empty($existingRef)) {
return $existingRef; return $existingRef;
} }
// Adding from a URL which implies downloading the resource // Adding from a URL which implies downloading the resource
$contents = Http::throw()->get($data['url'])->body(); $contents = Http::throw()->get($data['original_url'])->body();
$checksum = md5($contents);
$existingRef = $this->findAttachmentByChecksum($checksum);
$data['filename'] = basename($data['url']); if (!empty($existingRef)) {
$data['original_url'] = $data['url']; return $existingRef;
}
unset($data['url']); $data['checksum'] = $checksum;
$data['filename'] = basename($data['original_url']);
} }
$filename = $this->getFormatedFilename($data['filename']); $filename = $this->getFormatedFilename($data['filename']);
@ -356,6 +369,20 @@ private function findAttachmentByOriginalUrl(string $url)
return null; return null;
} }
/**
* Find an attachment from file's checksum, if specified
*/
private function findAttachmentByChecksum(string $checksum)
{
foreach ($this->manager->get('files', []) as $ref => $data) {
if (array_key_exists('checksum', $data) && $data['checksum'] === $checksum) {
return $ref;
}
}
return null;
}
/** /**
* Generate new, random reference for a file * Generate new, random reference for a file
*/ */

View File

@ -0,0 +1,38 @@
<?php
namespace App\Console\Commands\Bundle\Traits;
use App\Classes\Bundle;
trait ReadsBundles
{
protected $bundles;
/**
* Collect a list of bundles to validate
*/
protected function selectBundles(): self
{
$path = $this->argument('path') ?? '/';
$comment = sprintf('Validating <info>%s</info>', $path);
if ($this->option('recursive')) {
$comment .= ' and <info>all sub-bundles</info>';
}
$this->line($comment);
$this->output->write('Collecting bundles... ');
if ($this->option('recursive')) {
$bundles = Bundle::findBundles($this->sourceDisk, $path, true);
} else {
$bundles = [new Bundle($path, $this->sourceDisk)];
}
$this->bundles = $bundles;
$this->info('OK');
return $this;
}
}

View File

@ -0,0 +1,30 @@
<?php
namespace App\Console\Commands\Bundle\Traits;
use Illuminate\Contracts\Filesystem\Filesystem;
use Illuminate\Support\Facades\Storage;
trait SelectsDisks
{
protected Filesystem $sourceDisk;
/**
* Select the disk we will be working on
*/
private function selectDisk(): self
{
$sourceDisk = $this->option('source-disk') ?? env('CONTENT_DISK');
$this->sourceDisk = Storage::disk($sourceDisk);
$this->line(
sprintf(
'Using <info>%s</info> as source disk',
$sourceDisk
)
);
return $this;
}
}

View File

@ -3,20 +3,19 @@
namespace App\Console\Commands\Bundle; namespace App\Console\Commands\Bundle;
use App\Classes\Bundle; use App\Classes\Bundle;
use App\Console\Commands\Bundle\Traits\ReadsBundles;
use App\Console\Commands\Bundle\Traits\SelectsDisks;
use App\Exceptions\BundleUpdaterCannotBeFound; use App\Exceptions\BundleUpdaterCannotBeFound;
use App\Exceptions\UnableToFindWikidataEntityId; use App\Exceptions\UnableToFindWikidataEntityId;
use App\Services\BundleUpdaters\Facades\BundleUpdater; use App\Services\BundleUpdaters\Facades\BundleUpdater;
use Illuminate\Console\Command; use Illuminate\Console\Command;
use Illuminate\Support\Facades\Storage;
use function Laravel\Prompts\progress;
class Update extends Command class Update extends Command
{ {
/** use ReadsBundles;
* The name and signature of the console command. use SelectsDisks;
*
* @var string
*/
protected $signature = 'bundle:update { path? : Path to a specific bundle to update }';
/** /**
* The console command description. * The console command description.
@ -25,48 +24,113 @@ class Update extends Command
*/ */
protected $description = 'Update bundles extended metadata'; protected $description = 'Update bundles extended metadata';
protected $notUpdatable = [];
protected $updatedCount = 0;
protected $notUpdatedCount = 0;
public function __construct()
{
$this->signature = 'bundle:update
{ --r|recursive : Also validate sub-bundles }
{ --source-disk= : Use specified content disk - Defaults to <info>' . env('CONTENT_DISK') . '</info> }
{ path? : Path to a specific bundle to validate - Default to <info>/</info> }
';
parent::__construct();
}
/** /**
* Execute the console command. * Execute the console command.
*/ */
public function handle() public function handle()
{ {
$path = $this->argument('path') ?? '/'; $this->selectDisk()
$bundles = Bundle::findBundles(Storage::disk(env('CONTENT_DISK')), $path, true); ->selectBundles()
->update()
->showReport();
}
foreach ($bundles as $bundle) { /**
$this->output->write(sprintf('Updating %s... ', $bundle->getPath())); * Updates specific bundle
*/
protected function handleBundle(Bundle $bundle, $progress)
{
$progress->hint(sprintf('Updated %s', $bundle->getPath()));
try { try {
$updater = BundleUpdater::getBundleUpdaterFor($bundle); $updater = BundleUpdater::getBundleUpdaterFor($bundle);
} catch (BundleUpdaterCannotBeFound $ex) { } catch (BundleUpdaterCannotBeFound $ex) {
$this->line('Not updatable'); return;
}
continue; try {
} while (!$updater->canUpdateBundle()) {
$specs = $updater->formSpecs();
try { foreach ($specs as $key => $func) {
while (!$updater->canUpdateBundle()) { $result = $func();
$specs = $updater->formSpecs(); $bundle->metadata()->set($key, $result);
$bundle->save();
foreach ($specs as $key => $func) {
$result = $func();
$bundle->metadata()->set($key, $result);
$bundle->save();
}
} }
} catch (UnableToFindWikidataEntityId $ex) {
$this->comment('Unable to find wikidata entity Id');
continue;
} }
} catch (UnableToFindWikidataEntityId $ex) {
$this->notUpdatable[$bundle->getPath()] = 'Missing Wikidata Entity Id';
$result = $updater->update(); return;
}
if ($result) { $result = $updater->update();
$this->info('OK');
} else { if ($result) {
$this->comment('Update not needed'); $this->updatedCount++;
} } else {
$this->notUpdatedCount++;
}
}
/**
* Performs update on selected bundles
*/
private function update(): self
{
progress('Updating bundles...', $this->bundles, function (Bundle $bundle, $progress) {
$this->handleBundle($bundle, $progress);
});
return $this;
}
/**
* Show a report of update procedure
*/
private function showReport()
{
$this->line(sprintf('Updated bundles: <info>%d</info>', $this->updatedCount));
$this->line(sprintf('Update not needed: <comment>%d</comment>', $this->notUpdatedCount));
$this->reportNonUpdatable();
}
/**
* Show report of non updatable bundles
*/
private function reportNonUpdatable()
{
$count = count($this->notUpdatable);
if ($count === 0) {
return;
}
$this->newLine();
$this->line(sprintf('Not updatable bundles: <comment>%d</comment>', $count));
foreach ($this->notUpdatable as $bundle => $reason) {
$this->newLine();
$this->comment($bundle);
$this->line(sprintf(' > %s', $reason));
} }
} }
} }

View File

@ -40,6 +40,9 @@ public function handle()
$bundle->metadata('links')->clear(); $bundle->metadata('links')->clear();
$bundle->metadata('links')->save(); $bundle->metadata('links')->save();
$bundle->metadata('rebrickable')->clear();
$bundle->metadata('rebrickable')->save();
$bundle->save(); $bundle->save();
$this->info('OK'); $this->info('OK');

View File

@ -72,8 +72,8 @@ public function update()
if (!empty($setData['set_img_url'])) { if (!empty($setData['set_img_url'])) {
$ref = $this->bundle->attachments(AttachmentsManager::Images)->add([ $ref = $this->bundle->attachments(AttachmentsManager::Images)->add([
'url' => $setData['set_img_url'], 'original_url' => $setData['set_img_url'],
'attribution' => '&copy; [Rebrickable](https://rebrickable.com/)', 'attribution' => '&copy; [Rebrickable](https://rebrickable.com/)',
]); ]);
$this->bundle->metadata()->set('cover', $ref); $this->bundle->metadata()->set('cover', $ref);
@ -86,8 +86,8 @@ public function update()
} }
$this->bundle->attachments(AttachmentsManager::Images)->add([ $this->bundle->attachments(AttachmentsManager::Images)->add([
'url' => $minifig['set_img_url'], 'original_url' => $minifig['set_img_url'],
'attribution' => '&copy; [Rebrickable](https://rebrickable.com/)', 'attribution' => '&copy; [Rebrickable](https://rebrickable.com/)',
]); ]);
} }
} }