From 186f62fff993ed9bdb15aad9246489e6b2f145f2 Mon Sep 17 00:00:00 2001 From: Your Name Date: Sun, 30 Aug 2026 14:28:48 +0930 Subject: [PATCH] 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. --- app/Console/Commands/Admin/ResyncEmoji.php | 121 +++++++++++---------- 1 file changed, 61 insertions(+), 60 deletions(-) diff --git a/app/Console/Commands/Admin/ResyncEmoji.php b/app/Console/Commands/Admin/ResyncEmoji.php index 81b7a3860..e6b60975f 100644 --- a/app/Console/Commands/Admin/ResyncEmoji.php +++ b/app/Console/Commands/Admin/ResyncEmoji.php @@ -14,8 +14,8 @@ class ResyncEmoji extends Command * @var string */ protected $signature = 'admin:resyncemoji - {--missingonly : Only resync emoji whose stored media file is missing on the active disk} - {--limit=0 : Max emoji to process this run (0 = no limit)} + {files : Comma-separated emoji filename(s) to resync, e.g. "26109.png,1234.gif"} + {--missingonly : Only resync the given files whose media is missing on the active disk} {--dry-run : Report what would happen without downloading or writing} {--force : Skip confirmation prompts}'; @@ -24,7 +24,7 @@ class ResyncEmoji extends Command * * @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 { @@ -34,81 +34,82 @@ class ResyncEmoji extends Command return self::FAILURE; } - $missingOnly = (bool) $this->option('missingonly'); - $dryRun = (bool) $this->option('dry-run'); - $limit = max(0, (int) $this->option('limit')); + // Parse the comma-separated filename list into distinct basenames. + $names = collect(explode(',', (string) $this->argument('files'))) + ->map(fn ($n) => basename(trim($n))) + ->filter() + ->unique() + ->values(); - // Only remote emoji can be re-fetched (they carry an origin URL). - $query = CustomEmoji::whereNotNull('image_remote_url') - ->orderBy('id') - ->when($limit > 0, fn ($q) => $q->limit($limit)); + if ($names->isEmpty()) { + $this->error('No emoji filenames provided. Example: admin:resyncemoji "26109.png,1234.gif"'); - $candidates = $query->get(); - $totalCandidates = $candidates->count(); + return self::FAILURE; + } - if ($totalCandidates === 0) { - $this->info('No remote emoji found to resync.'); + $missingOnly = (bool) $this->option('missingonly'); + $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 - // active disk (checks cloud when cloud storage is enabled). - if ($missingOnly) { - $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); - } + foreach ($names as $name) { + $mediaPath = 'emoji/'.$name; + $emoji = CustomEmoji::whereMediaPath($mediaPath)->first(); - $total = $candidates->count(); + if (! $emoji) { + $this->warn(" not found in DB: {$name} (media_path={$mediaPath})"); + $notFound++; - if ($total === 0) { - $this->info('Nothing to resync'.($missingOnly ? '; all remote emoji media present.' : '.')); + continue; + } - return self::SUCCESS; - } + if (empty($emoji->image_remote_url)) { + $this->warn(" skip (no origin url, local emoji): {$name}"); + $skipped++; - if ($dryRun) { - $this->info("[dry-run] Would resync {$total} emoji from origin."); + continue; + } - 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)) { - $this->comment('Aborted.'); + continue; + } - return self::SUCCESS; - } + if ($dryRun) { + $this->line(" [dry-run] would resync: {$name} <- {$emoji->image_remote_url}"); + $resynced++; - $resynced = 0; - $skipped = 0; - $failed = 0; + continue; + } + + if (! $this->option('force') && ! $this->confirm("Resync {$name} from {$emoji->image_remote_url}?", true)) { + $this->line(" skipped: {$name}"); + $skipped++; - $bar = $this->output->createProgressBar($total); - $bar->start(); + continue; + } - foreach ($candidates as $emoji) { $result = CustomEmojiService::resync($emoji); - match ($result) { - 'resynced' => $resynced++, - 'skipped' => $skipped++, - default => $failed++, - }; - $bar->advance(); + if ($result === 'resynced') { + $resynced++; + $this->info(" resynced: {$name}"); + } elseif ($result === 'skipped') { + $skipped++; + $this->warn(" skipped: {$name}"); + } else { + $failed++; + $this->error(" failed: {$name}"); + } } - $bar->finish(); - $this->newLine(2); - $this->info("Done. resynced={$resynced} skipped={$skipped} failed={$failed}."); + $this->newLine(); + $this->info(($dryRun ? '[dry-run] ' : '')."Done. resynced={$resynced} skipped={$skipped} failed={$failed} not_found={$notFound}."); - return $failed ? self::FAILURE : self::SUCCESS; + return ($failed || $notFound) ? self::FAILURE : self::SUCCESS; } }