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, requester, url, videoFormatID, videoFormatName, audioFormatID, audioFormatName, 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: "✅ **Successfully Downloaded**", 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(fmt.Sprintf("%s **Starting Download**", loading_emoji)), }) 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 = fmt.Sprintf("%s **Post Processing**", loading_emoji) } else { var progressStr string if prog.DownloadedBytes > 0 { progressStr = formatBytes(prog.DownloadedBytes) + " downloaded" } else { progressStr = "starting..." } content = fmt.Sprintf("%s **Downloading Video**: %s", loading_emoji, 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.InteractionResponseEdit(i.Interaction, &discordgo.WebhookEdit{ Content: ptr("✅ **Successfully Downloaded**"), }) _, err = s.FollowupMessageCreate(i.Interaction, false, &discordgo.WebhookParams{ Content: fmt.Sprintf("## Video Downloaded \n**URL**: %s \n**Quality**: %s + %s \n**Requested By**: <@%s> \n", result.URL, videoFormatName, audioFormatName, requester), }) 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 } } }() }