package spm import ( "bufio" "io" "net/http" "os" "strings" ) const appIndexURL = "https://downloads.sourceforge.net/project/spitfire-browser/APPINDEX" func DownloadAppIndex(dest string) error { UpdateProgress(0, "Downloading APPINDEX") resp, err := http.Get(appIndexURL) if err != nil { return err } defer resp.Body.Close() out, err := os.Create(dest) if err != nil { return err } defer out.Close() totalSize := resp.ContentLength var downloaded int64 // Track progress as bytes are downloaded buf := make([]byte, 1024) for { n, err := resp.Body.Read(buf) if n > 0 { downloaded += int64(n) percentage := int(float64(downloaded) / float64(totalSize) * 100) UpdateProgress(percentage, "Downloading APPINDEX") if _, err := out.Write(buf[:n]); err != nil { return err } } if err == io.EOF { break } if err != nil { return err } } UpdateProgress(100, "APPINDEX downloaded") return nil } type AppIndexEntry struct { Name string Version string Release string Arch string OS string DownloadURL string } func ParseAppIndex(filePath string) ([]AppIndexEntry, error) { file, err := os.Open(filePath) if err != nil { return nil, err } defer file.Close() var entries []AppIndexEntry scanner := bufio.NewScanner(file) entry := AppIndexEntry{} for scanner.Scan() { line := scanner.Text() if strings.HasPrefix(line, "C:") { if entry.Name != "" { entries = append(entries, entry) entry = AppIndexEntry{} } } parts := strings.SplitN(line, ":", 2) if len(parts) < 2 { continue } switch parts[0] { case "P": entry.Name = parts[1] case "R": entry.Release = parts[1] case "V": entry.Version = parts[1] case "A": entry.Arch = parts[1] case "p": entry.OS = parts[1] case "d": entry.DownloadURL = parts[1] } } if entry.Name != "" { entries = append(entries, entry) } return entries, scanner.Err() }