package main import ( "encoding/json" "fmt" "io" "log" "music-downloader/monochrome" "net/http" "os" "path" "strconv" "sync" ) func sendJSON(w http.ResponseWriter, data any, status int) { w.Header().Set("Content-Type", "application/json") w.WriteHeader(status) if err := json.NewEncoder(w).Encode(data); err != nil { http.Error(w, err.Error(), 500) } } func main() { mClient := monochrome.NewClient(monochrome.ClientConfig{ ApiURL: "https://api.monochrome.tf", }) mux := http.NewServeMux() mux.HandleFunc("GET /search", func(w http.ResponseWriter, r *http.Request) { q := r.URL.Query().Get("q") results, err := mClient.SearchAlbum(q) if err != nil { http.Error(w, err.Error(), 404) return } sendJSON(w, results, 200) }) mux.HandleFunc("GET /download-album/{id}", func(w http.ResponseWriter, r *http.Request) { id, err := strconv.Atoi(r.PathValue("id")) if err != nil { http.Error(w, err.Error(), 500) return } album, err := mClient.AlbumInfo(id) if err != nil { http.Error(w, err.Error(), 404) return } if album == nil { http.Error(w, "album not found for some reason", 404) return } if err := os.Mkdir("./music/"+album.Title, 0777); err != nil { http.Error(w, fmt.Sprintf("failed to create album directory: %v", err), 500) return } type Response struct { sync.Mutex count int } response := new(Response) var wg sync.WaitGroup for _, track := range album.Items { wg.Go(func() { info, err := mClient.TrackInfo(track.Item.ID, track.Item.AudioQuality) if err != nil { log.Printf("failed to get track info: %v\n", err) return } manifest, err := mClient.DecodeManifest(info.Manifest) if err != nil { log.Printf("failed to decode track manifest: %v\n", err) return } if manifest.EncryptionType != monochrome.TrackManifestEncryptionNone { log.Println("file is encrypted; can't download") return } if len(manifest.URLs) == 0 { log.Println("track manifest doesn't have urls array") return } resp, err := http.Get(manifest.URLs[0]) if err != nil { log.Printf("failed to download track data: %v\n", err) return } defer resp.Body.Close() data, err := io.ReadAll(resp.Body) if err != nil { log.Printf("failed to read track data: %v\n", err) return } if err := os.WriteFile(path.Join("./music/", album.Title, track.Item.Title+".flac"), data, 0644); err != nil { log.Printf("failed to save track file: %v\n", err) return } response.Lock() response.count++ response.Unlock() }) } wg.Wait() sendJSON(w, struct { DownloadedFilesCount int `json:"downloadedFilesCount"` TotalFilesCount int `json:"totalFilesCount"` }{ DownloadedFilesCount: response.count, TotalFilesCount: len(album.Items), }, 200) }) log.Println("starting http server") if err := http.ListenAndServe(":5000", mux); err != nil { log.Fatalf("failed to start http server: %v\n", err) } }