package main import ( "fmt" "log" "github.com/bwmarrin/discordgo" ) // startAsyncDownload initiates a download in a goroutine and handles progress updates func startAsyncDownload(s *discordgo.Session, i *discordgo.InteractionCreate, url, videoFormatID, audioFormatID, outputDir, tempDir string) { progressChan := make(chan ProgressUpdate, 1) resultChan := make(chan DownloadResult, 1) // Start download in goroutine go func() { defer close(resultChan) defer func() { if r := recover(); r != nil { // Handle panic from DownloadVideo resultChan <- DownloadResult{ Success: false, Message: fmt.Sprintf("Download failed: %v", r), URL: url, Format: fmt.Sprintf("video: %s, audio: %s", videoFormatID, audioFormatID), Error: fmt.Errorf("%v", r), } } }() // Call DownloadVideo (it panics on error instead of returning error) DownloadVideo(outputDir, tempDir, url, DownloadOptions{ EmbedThumbnail: true, IncludeSubtitles: true, VideoFormatID: videoFormatID, AudioFormatID: audioFormatID, }, progressChan) // If we reach here, download was successful resultChan <- DownloadResult{ Success: true, Message: "Video Downloaded Successfully!", URL: url, Format: fmt.Sprintf("video: %s, audio: %s", videoFormatID, audioFormatID), Error: nil, } }() // Handle progress and results asynchronously go func() { _, err := s.InteractionResponseEdit(i.Interaction, &discordgo.WebhookEdit{ Content: ptr("⏬ downloading: starting..."), }) if err != nil { log.Printf("Error updating interaction: %v", err) } for { select { case prog, ok := <-progressChan: if !ok { progressChan = nil continue } var content string if prog.Phase == "post-processing" { content = "⚙️ post-processing" } else { var progressStr string if prog.DownloadedBytes > 0 { progressStr = formatBytes(prog.DownloadedBytes) + " downloaded" } else { progressStr = "starting..." } content = fmt.Sprintf("Downloading Video: %s", progressStr) } _, err := s.InteractionResponseEdit(i.Interaction, &discordgo.WebhookEdit{ Content: ptr(content), }) if err != nil { log.Printf("Error updating progress: %v", err) } case result := <-resultChan: if result.Success { _, err = s.FollowupMessageCreate(i.Interaction, false, &discordgo.WebhookParams{ Content: "📥 Video downloaded: " + result.URL, }) if err != nil { log.Printf("Error updating interaction: %v", err) } } else { _, err = s.InteractionResponseEdit(i.Interaction, &discordgo.WebhookEdit{ Content: ptr("❌ Download failed: " + result.Message), }) if err != nil { log.Printf("Error updating interaction: %v", err) } } return } } }() }