option('artist')) { $spotifyService = new SpotifyService( artistId: $this->option('artist'), ); } if (! $spotifyService->isConfigured()) { $this->error(__('music_productions.spotify_not_configured')); return Command::FAILURE; } $this->info(__('music_productions.spotify_sync_started')); try { $albumSummaries = $spotifyService->getArtistAlbums(); } catch (\Throwable $exception) { $this->error($exception->getMessage()); return Command::FAILURE; } if (empty($albumSummaries)) { $this->warn(__('music_productions.spotify_no_albums')); return Command::SUCCESS; } $created = 0; $updated = 0; $dryRun = (bool) $this->option('dry-run'); foreach ($albumSummaries as $index => $albumSummary) { $albumId = $albumSummary['id'] ?? null; if (blank($albumId)) { continue; } $album = $spotifyService->getAlbum($albumId) ?? $albumSummary; $title = $album['name'] ?? __('music_productions.spotify_untitled_album'); $artistName = collect($album['artists'] ?? [])->pluck('name')->first(); $releaseDate = $this->parseReleaseDate($album['release_date'] ?? null, $album['release_date_precision'] ?? 'day'); $spotifyUrl = $album['external_urls']['spotify'] ?? null; $coverUrl = collect($album['images'] ?? [])->first()['url'] ?? null; $albumType = $album['album_type'] ?? 'album'; $production = $this->findMatchingProduction($albumId, $title); $action = $production ? 'update' : 'create'; $this->line(sprintf( '[%d/%d] %s: %s (%s)', $index + 1, count($albumSummaries), $action === 'create' ? 'Yeni' : 'Güncelle', $title, $releaseDate?->format('Y-m-d') ?? '-' )); if ($dryRun) { continue; } $attributes = [ 'spotify_album_id' => $albumId, 'spotify_url' => $spotifyUrl, 'spotify_cover_url' => $coverUrl, 'spotify_type' => $albumType, 'spotify_synced_at' => now(), ]; if (! $production) { $attributes['title'] = $title; $attributes['slug'] = SpotifyService::uniqueSlug($title); $attributes['client_name'] = $artistName; $attributes['production_date'] = $releaseDate; $attributes['content'] = $spotifyService->buildDefaultContent($album); $attributes['is_active'] = true; $attributes['sort_order'] = 0; $coverPath = $spotifyService->downloadCoverImage($coverUrl, $albumId); if ($coverPath) { $attributes['cover_image'] = $coverPath; } MusicProduction::create($attributes); $created++; continue; } if (blank($production->title)) { $attributes['title'] = $title; } if (blank($production->client_name) && filled($artistName)) { $attributes['client_name'] = $artistName; } if (blank($production->production_date) && $releaseDate) { $attributes['production_date'] = $releaseDate; } if (blank($production->content)) { $attributes['content'] = $spotifyService->buildDefaultContent($album); } if (blank($production->cover_image) && filled($coverUrl)) { $coverPath = $spotifyService->downloadCoverImage($coverUrl, $albumId); if ($coverPath) { $attributes['cover_image'] = $coverPath; } } $production->update($attributes); $updated++; usleep(150000); } $message = __('music_productions.spotify_sync_completed', [ 'created' => $created, 'updated' => $updated, 'total' => count($albumSummaries), ]); $this->info($message); Log::info('Spotify music productions sync completed', [ 'created' => $created, 'updated' => $updated, 'total' => count($albumSummaries), 'dry_run' => $dryRun, ]); return Command::SUCCESS; } protected function findMatchingProduction(string $albumId, string $title): ?MusicProduction { $bySpotifyId = MusicProduction::withTrashed() ->where('spotify_album_id', $albumId) ->first(); if ($bySpotifyId) { return $bySpotifyId->trashed() ? null : $bySpotifyId; } $slug = Str::slug($title); $bySlug = MusicProduction::query() ->where('slug', $slug) ->first(); if ($bySlug) { return $bySlug; } return MusicProduction::query() ->whereRaw('LOWER(title) = ?', [Str::lower($title)], 'and') ->first(); } protected function parseReleaseDate(?string $date, string $precision = 'day'): ?Carbon { if (blank($date)) { return null; } return match ($precision) { 'year' => Carbon::createFromFormat('Y', $date)->startOfYear(), 'month' => Carbon::createFromFormat('Y-m', $date)->startOfMonth(), default => Carbon::parse($date), }; } }