diff --git a/tabatago-swift/TabataGo/Services/MusicService.swift b/tabatago-swift/TabataGo/Services/MusicService.swift index 957c2f0..f820646 100644 --- a/tabatago-swift/TabataGo/Services/MusicService.swift +++ b/tabatago-swift/TabataGo/Services/MusicService.swift @@ -50,9 +50,6 @@ actor MusicService { // ─── Supabase Fetch ────────────────────────────────────────── private func fetchFromSupabase(vibe: MusicVibe) async -> [MusicTrack]? { - // Re-use the existing SupabaseService's client configuration. - // We build our own client here because SupabaseService is an actor - // and doesn't expose the raw client. guard !AppEnvironment.isPreview else { return nil } let urlRaw = Bundle.main.infoDictionary?["SUPABASE_URL"] as? String ?? "" @@ -63,16 +60,30 @@ actor MusicService { } let client = SupabaseClient(supabaseURL: url, supabaseKey: key) + let genres = vibe.genres do { - let rows: [DownloadItemRow] = try await client - .from("download_items") - .select("id, video_id, title, duration_seconds, public_url, storage_path, genre") - .eq("status", value: "completed") - .in("genre", values: vibe.genres) - .limit(50) - .execute() - .value + let rows: [DownloadItemRow] = try await withThrowingTaskGroup(of: [DownloadItemRow].self) { group in + group.addTask { + try await client + .from("download_items") + .select("id, video_id, title, duration_seconds, public_url, storage_path, genre") + .eq("status", value: "completed") + .in("genre", values: genres) + .limit(50) + .execute() + .value + } + group.addTask { + try await Task.sleep(for: .seconds(6)) + throw CancellationError() + } + guard let result = try await group.next() else { + return [] + } + group.cancelAll() + return result + } let tracks: [MusicTrack] = rows.compactMap { row in guard let trackURL = row.resolvedURL(supabaseBase: urlRaw) else { return nil }