change: admin:resyncemoji takes a required list of filenames

Instead of scanning all emoji, target specific files by name:
  admin:resyncemoji "26109.png,1234.gif"

Looks up each by media_path (emoji/{filename}), and for found remote emoji
re-downloads from image_remote_url onto the active disk. Reports per-file
status (resynced/skipped/failed/not_found). --missingonly still guards each
against the disk so present files are left alone; --dry-run and --force.
feat/emoji-cloud-storage-v2
Your Name 3 weeks ago
parent 5764c135f5
commit 186f62fff9

@ -14,8 +14,8 @@ class ResyncEmoji extends Command
* @var string * @var string
*/ */
protected $signature = 'admin:resyncemoji protected $signature = 'admin:resyncemoji
{--missingonly : Only resync emoji whose stored media file is missing on the active disk} {files : Comma-separated emoji filename(s) to resync, e.g. "26109.png,1234.gif"}
{--limit=0 : Max emoji to process this run (0 = no limit)} {--missingonly : Only resync the given files whose media is missing on the active disk}
{--dry-run : Report what would happen without downloading or writing} {--dry-run : Report what would happen without downloading or writing}
{--force : Skip confirmation prompts}'; {--force : Skip confirmation prompts}';
@ -24,7 +24,7 @@ class ResyncEmoji extends Command
* *
* @var string * @var string
*/ */
protected $description = 'Re-download remote custom emoji media from their origin (image_remote_url) and store on the active disk.'; protected $description = 'Re-download specific remote custom emoji from their origin (image_remote_url) and store on the active disk.';
public function handle(): int public function handle(): int
{ {
@ -34,81 +34,82 @@ class ResyncEmoji extends Command
return self::FAILURE; return self::FAILURE;
} }
$missingOnly = (bool) $this->option('missingonly'); // Parse the comma-separated filename list into distinct basenames.
$dryRun = (bool) $this->option('dry-run'); $names = collect(explode(',', (string) $this->argument('files')))
$limit = max(0, (int) $this->option('limit')); ->map(fn ($n) => basename(trim($n)))
->filter()
->unique()
->values();
// Only remote emoji can be re-fetched (they carry an origin URL). if ($names->isEmpty()) {
$query = CustomEmoji::whereNotNull('image_remote_url') $this->error('No emoji filenames provided. Example: admin:resyncemoji "26109.png,1234.gif"');
->orderBy('id')
->when($limit > 0, fn ($q) => $q->limit($limit));
$candidates = $query->get(); return self::FAILURE;
$totalCandidates = $candidates->count(); }
if ($totalCandidates === 0) { $missingOnly = (bool) $this->option('missingonly');
$this->info('No remote emoji found to resync.'); $dryRun = (bool) $this->option('dry-run');
return self::SUCCESS; $resynced = 0;
} $skipped = 0;
$failed = 0;
$notFound = 0;
// With --missingonly, keep only those whose file is absent on the foreach ($names as $name) {
// active disk (checks cloud when cloud storage is enabled). $mediaPath = 'emoji/'.$name;
if ($missingOnly) { $emoji = CustomEmoji::whereMediaPath($mediaPath)->first();
$this->info("Checking {$totalCandidates} remote emoji for missing media...");
$bar = $this->output->createProgressBar($totalCandidates);
$bar->start();
$candidates = $candidates->reject(function (CustomEmoji $emoji) use ($bar) {
$exists = CustomEmoji::mediaExists($emoji->media_path);
$bar->advance();
return $exists; // reject those that already exist
})->values();
$bar->finish();
$this->newLine(2);
}
$total = $candidates->count(); if (! $emoji) {
$this->warn(" not found in DB: {$name} (media_path={$mediaPath})");
$notFound++;
if ($total === 0) { continue;
$this->info('Nothing to resync'.($missingOnly ? '; all remote emoji media present.' : '.')); }
return self::SUCCESS; if (empty($emoji->image_remote_url)) {
} $this->warn(" skip (no origin url, local emoji): {$name}");
$skipped++;
if ($dryRun) { continue;
$this->info("[dry-run] Would resync {$total} emoji from origin."); }
return self::SUCCESS; if ($missingOnly && CustomEmoji::mediaExists($emoji->media_path)) {
} $this->line(" skip (already present): {$name}");
$skipped++;
if (! $this->option('force') && ! $this->confirm("Resync {$total} emoji from their origin servers?", true)) { continue;
$this->comment('Aborted.'); }
return self::SUCCESS; if ($dryRun) {
} $this->line(" [dry-run] would resync: {$name} <- {$emoji->image_remote_url}");
$resynced++;
$resynced = 0; continue;
$skipped = 0; }
$failed = 0;
if (! $this->option('force') && ! $this->confirm("Resync {$name} from {$emoji->image_remote_url}?", true)) {
$this->line(" skipped: {$name}");
$skipped++;
$bar = $this->output->createProgressBar($total); continue;
$bar->start(); }
foreach ($candidates as $emoji) {
$result = CustomEmojiService::resync($emoji); $result = CustomEmojiService::resync($emoji);
match ($result) { if ($result === 'resynced') {
'resynced' => $resynced++, $resynced++;
'skipped' => $skipped++, $this->info(" resynced: {$name}");
default => $failed++, } elseif ($result === 'skipped') {
}; $skipped++;
$bar->advance(); $this->warn(" skipped: {$name}");
} else {
$failed++;
$this->error(" failed: {$name}");
}
} }
$bar->finish(); $this->newLine();
$this->newLine(2); $this->info(($dryRun ? '[dry-run] ' : '')."Done. resynced={$resynced} skipped={$skipped} failed={$failed} not_found={$notFound}.");
$this->info("Done. resynced={$resynced} skipped={$skipped} failed={$failed}.");
return $failed ? self::FAILURE : self::SUCCESS; return ($failed || $notFound) ? self::FAILURE : self::SUCCESS;
} }
} }

Loading…
Cancel
Save