option('dry-run') !== false; $force = $this->option('force'); if (!$dryRun && !$force) { $this->warn('Use --dry-run (default) to preview, or --force to delete.'); return 1; } $this->info($dryRun ? 'DRY RUN MODE - No files will be deleted.' : 'FORCE MODE - Deleting orphaned files.'); $disk = Storage::disk('public'); $videoDir = 'videos'; $files = $disk->files($videoDir); if (empty($files)) { $this->info('No video files found in storage/app/public/videos/'); return 0; } // Get all valid filenames from DB (exact match for filename column) $dbFilenames = Video::pluck('filename')->filter()->toArray(); $orphans = []; foreach ($files as $file) { // Only video files (skip non-videos) if (!str_ends_with($file, '.mp4') && !str_ends_with($file, '.webm') && !str_ends_with($file, '.mov')) { continue; } $basename = basename($file); // Check if exact match or compressed_ prefix with base in DB $isOrphan = true; if (in_array($basename, $dbFilenames)) { $isOrphan = false; } elseif (str_starts_with($basename, 'compressed_')) { $originalBasename = substr($basename, 10); // remove 'compressed_' if (in_array($originalBasename, $dbFilenames)) { $isOrphan = false; } } if ($isOrphan) { $orphans[] = $file; } } $totalFiles = count($files); $orphanCount = count($orphans); $this->table( ['Stat', 'Value'], [ ['Total video files scanned', $totalFiles], ['Orphaned files found', $orphanCount], ] ); if ($orphanCount === 0) { $this->info('No orphaned videos found! ✅'); Log::channel('orphaned-videos')->info('Cleanup run: 0 orphans found.'); return 0; } if ($dryRun) { $this->table(['Orphan Files (would delete)'], array_map(fn($f) => [ $f ], $orphans)); Log::channel('orphaned-videos')->info('DRY RUN: Found ' . $orphanCount . ' orphans', ['files' => $orphans]); $this->warn("Run with --force to delete these files."); } else { $bar = $this->output->createProgressBar($orphanCount); $bar->start(); foreach ($orphans as $orphan) { $disk->delete($orphan); Log::channel('orphaned-videos')->info('Deleted orphan: ' . $orphan); $bar->advance(); } $bar->finish(); $this->newLine(); $this->info("✅ Deleted {$orphanCount} orphaned video files."); } return 0; } }