Add download package
This commit is contained in:
@@ -0,0 +1,160 @@
|
||||
package download
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"io"
|
||||
"net/http"
|
||||
"os"
|
||||
"path/filepath"
|
||||
)
|
||||
|
||||
// DownloadStatus holds information related to downloads and is
|
||||
// the container for information returned via channels within this
|
||||
// package.
|
||||
type DownloadStatus struct {
|
||||
Min int64 // Current file's bytes downloaded
|
||||
Max int64 // Current file's total size
|
||||
Cur int64 // Overall bytes downloaded
|
||||
Msg string // Status message
|
||||
Err error // Error, if any
|
||||
}
|
||||
|
||||
// DownloadAudioFiles downloads multiple audio files and sends progress updates
|
||||
// to the provided channel. The channel is closed when all downloads are complete.
|
||||
func DownloadAudioFiles(progressChan chan<- DownloadStatus, filenames []string, destDir string) {
|
||||
defer close(progressChan)
|
||||
|
||||
urlBase := "https://files.rhemawavetech.com/audio/"
|
||||
totalDownloaded := int64(0)
|
||||
totalSize := int64(0)
|
||||
|
||||
// First, get the total size of all files
|
||||
for _, filename := range filenames {
|
||||
url := urlBase + filename
|
||||
resp, err := http.Head(url)
|
||||
if err != nil {
|
||||
progressChan <- DownloadStatus{
|
||||
Msg: fmt.Sprintf("Failed to get size for %s: %v", filename, err),
|
||||
Err: err,
|
||||
}
|
||||
return
|
||||
}
|
||||
resp.Body.Close()
|
||||
if resp.StatusCode != http.StatusOK {
|
||||
progressChan <- DownloadStatus{
|
||||
Msg: fmt.Sprintf("Failed to get size for %s: status %s", filename, resp.Status),
|
||||
Err: fmt.Errorf("bad status: %s", resp.Status),
|
||||
}
|
||||
return
|
||||
}
|
||||
totalSize += resp.ContentLength
|
||||
}
|
||||
|
||||
// Send initial status
|
||||
progressChan <- DownloadStatus{
|
||||
Min: 0,
|
||||
Max: totalSize,
|
||||
Cur: 0,
|
||||
Msg: "Starting download...",
|
||||
}
|
||||
|
||||
// Download each file
|
||||
for _, filename := range filenames {
|
||||
url := urlBase + filename
|
||||
destPath := filepath.Join(destDir, filename)
|
||||
|
||||
// Create the destination file
|
||||
out, err := os.Create(destPath)
|
||||
if err != nil {
|
||||
progressChan <- DownloadStatus{
|
||||
Msg: fmt.Sprintf("Failed to create file %s: %v", destPath, err),
|
||||
Err: err,
|
||||
}
|
||||
return
|
||||
}
|
||||
|
||||
// Get the file
|
||||
resp, err := http.Get(url)
|
||||
if err != nil {
|
||||
out.Close()
|
||||
os.Remove(destPath)
|
||||
progressChan <- DownloadStatus{
|
||||
Msg: fmt.Sprintf("Failed to download %s: %v", filename, err),
|
||||
Err: err,
|
||||
}
|
||||
return
|
||||
}
|
||||
defer resp.Body.Close()
|
||||
|
||||
if resp.StatusCode != http.StatusOK {
|
||||
out.Close()
|
||||
os.Remove(destPath)
|
||||
progressChan <- DownloadStatus{
|
||||
Msg: fmt.Sprintf("Failed to download %s: status %s", filename, resp.Status),
|
||||
Err: fmt.Errorf("bad status: %s", resp.Status),
|
||||
}
|
||||
return
|
||||
}
|
||||
|
||||
// Track progress for this file
|
||||
fileSize := resp.ContentLength
|
||||
downloaded := int64(0)
|
||||
|
||||
// Use a buffered reader for efficiency
|
||||
buf := make([]byte, 8192)
|
||||
for {
|
||||
n, err := resp.Body.Read(buf)
|
||||
if err != nil && err != io.EOF {
|
||||
out.Close()
|
||||
os.Remove(destPath)
|
||||
progressChan <- DownloadStatus{
|
||||
Msg: fmt.Sprintf("Failed to read %s: %v", filename, err),
|
||||
Err: err,
|
||||
}
|
||||
return
|
||||
}
|
||||
if n == 0 {
|
||||
break
|
||||
}
|
||||
|
||||
// Write to file
|
||||
if _, err := out.Write(buf[:n]); err != nil {
|
||||
out.Close()
|
||||
os.Remove(destPath)
|
||||
progressChan <- DownloadStatus{
|
||||
Msg: fmt.Sprintf("Failed to write %s: %v", filename, err),
|
||||
Err: err,
|
||||
}
|
||||
return
|
||||
}
|
||||
|
||||
// Update progress
|
||||
downloaded += int64(n)
|
||||
totalDownloaded += int64(n)
|
||||
progressChan <- DownloadStatus{
|
||||
Min: downloaded,
|
||||
Max: fileSize,
|
||||
Cur: totalDownloaded,
|
||||
Msg: fmt.Sprintf("Downloading %s...", filename),
|
||||
}
|
||||
}
|
||||
|
||||
out.Close()
|
||||
|
||||
// Send completion for this file
|
||||
progressChan <- DownloadStatus{
|
||||
Min: fileSize,
|
||||
Max: fileSize,
|
||||
Cur: totalDownloaded,
|
||||
Msg: fmt.Sprintf("Finished downloading %s", filename),
|
||||
}
|
||||
}
|
||||
|
||||
// Send final status
|
||||
progressChan <- DownloadStatus{
|
||||
Min: totalSize,
|
||||
Max: totalSize,
|
||||
Cur: totalDownloaded,
|
||||
Msg: "All downloads completed!",
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user