['ext' => 'webm', 'mime' => 'video/webm'], 'mov' => ['ext' => 'mov', 'mime' => 'video/quicktime'], 'webp' => ['ext' => 'webp', 'mime' => 'image/webp'], 'gif' => ['ext' => 'gif', 'mime' => 'image/gif'], ]; /** * Run the database seeds. */ public function run(): void { $this->command->info('šŸš€ Starting meme media import...'); // Ensure media collection exists $this->ensureMediaCollectionExists(); // Read CSV file $csvPath = database_path('seeders/data/webm_metadata.csv'); $memeData = $this->parseCsvFile($csvPath); $this->command->info('šŸ“Š Found '.count($memeData).' memes to import'); // Process in chunks for memory efficiency $chunks = array_chunk($memeData, 50); $totalProcessed = 0; $totalSkipped = 0; $totalFailed = 0; foreach ($chunks as $chunkIndex => $chunk) { $this->command->info('Processing chunk '.($chunkIndex + 1).'/'.count($chunks)); DB::transaction(function () use ($chunk, &$totalProcessed, &$totalSkipped, &$totalFailed) { foreach ($chunk as $memeRecord) { try { // Extract base filename for duplicate checking $baseFilename = pathinfo($memeRecord['filename'], PATHINFO_FILENAME); // Check if already exists by checking if webm_url contains this filename if (MemeMedia::where('webm_url', 'like', "%/{$baseFilename}.webm")->exists()) { $this->command->warn("ā­ļø Skipping existing: {$memeRecord['filename']} ({$memeRecord['name']})"); $totalSkipped++; continue; } $this->importSingleMeme($memeRecord); $totalProcessed++; if ($totalProcessed % 10 === 0) { $this->command->info("āœ… Processed {$totalProcessed} memes..."); } } catch (\Exception $e) { $totalFailed++; $this->command->error("āŒ Failed to import: {$memeRecord['filename']} - {$e->getMessage()}"); } } }); } // Summary $this->command->info("\nšŸŽÆ Import Summary:"); $this->command->info("āœ… Successfully imported: {$totalProcessed} memes"); if ($totalSkipped > 0) { $this->command->info("ā­ļø Skipped (existing): {$totalSkipped} memes"); } if ($totalFailed > 0) { $this->command->error("āŒ Failed: {$totalFailed} memes"); } $totalMediaRecords = $totalProcessed * 4; $this->command->info("šŸ“Š Created {$totalMediaRecords} media records and {$totalProcessed} meme_media records"); } /** * Parse CSV file and return array of meme data */ private function parseCsvFile(string $csvPath): array { if (! file_exists($csvPath)) { throw new \RuntimeException("CSV file not found: {$csvPath}"); } $csvContent = file_get_contents($csvPath); $lines = str_getcsv($csvContent, "\n"); // Parse header row $headers = str_getcsv(array_shift($lines)); $memeData = []; foreach ($lines as $line) { if (empty(trim($line))) { continue; } $row = str_getcsv($line); if (count($row) === count($headers)) { $memeData[] = array_combine($headers, $row); } } return $memeData; } /** * Import a single meme with all its formats */ private function importSingleMeme(array $memeRecord): void { // Extract base filename (remove .webm extension) $baseFilename = pathinfo($memeRecord['filename'], PATHINFO_FILENAME); $mediaUuids = []; $mediaUrls = []; // Create MediaEngine entries for each format foreach (self::FORMATS as $format => $config) { $url = $this->generateCdnUrl($baseFilename, $config['ext']); // Create media entry using save_url mode $media = MediaEngine::addMedia( 'temps', // Media collection key $memeRecord['type'], // video or image 'system_uploaded', // Media source 'meme_cdn', // Media provider null, // No file content $url, // CDN URL 'save_url', // Mode: just save URL reference null, // Auto-generate filename 'r2', // Disk (not used for URL mode) trim($memeRecord['name'])." ({$format})", // Name with format null, // No specific user $config['mime'] // MIME type ); $mediaUuids[$format.'_uuid'] = $media->uuid; $mediaUrls[$format.'_url'] = $url; } // Create MemeMedia record MemeMedia::create([ 'type' => $memeRecord['type'], 'sub_type' => $memeRecord['sub_type'], 'name' => trim($memeRecord['name']), 'description' => $memeRecord['description'], 'keywords' => $memeRecord['keywords'], // UUIDs from MediaEngine 'mov_uuid' => $mediaUuids['mov_uuid'], 'webm_uuid' => $mediaUuids['webm_uuid'], 'gif_uuid' => $mediaUuids['gif_uuid'], 'webp_uuid' => $mediaUuids['webp_uuid'], // Direct CDN URLs 'mov_url' => $mediaUrls['mov_url'], 'webm_url' => $mediaUrls['webm_url'], 'gif_url' => $mediaUrls['gif_url'], 'webp_url' => $mediaUrls['webp_url'], // Embedding will be null initially 'embedding' => null, ]); $this->command->info('āœ… Imported: '.trim($memeRecord['name'])); } /** * Generate CDN URL for specific format */ private function generateCdnUrl(string $baseFilename, string $extension): string { return self::CDN_BASE_URL."/{$extension}/{$baseFilename}.{$extension}"; } /** * Ensure the temps media collection exists */ private function ensureMediaCollectionExists(): void { $collection = MediaCollection::firstOrCreate([ 'key' => 'temps', ], [ 'name' => 'Temp Files', 'description' => 'Temporary and external file references', 'is_system' => true, ]); $this->command->info("šŸ“ Using media collection: {$collection->key}"); } }