package main import ( "bytes" "fmt" "io" "net/http" "strconv" "sync" "time" ) func main() { var streams = [...]string{"https://c17.radioboss.fm:18509/stream"} var wg sync.WaitGroup for _, stream := range streams { time.Sleep(1 * time.Second) wg.Add(1) // Внимание, асинхронный вызов! go makePlaylist(stream, &wg) } // Ждём пока все асинхронные горутины завершатся wg.Wait() } func makePlaylist(streamAddress string, wg *sync.WaitGroup) { defer wg.Done() // Формируем HTTP-запрос client := &http.Client{} req, err := http.NewRequest("GET", streamAddress, nil) if err != nil { fmt.Println(fmt.Sprintf("%s error: %s", streamAddress, err)) return } req.Header.Add("icy-metadata", "1") // Отправляем resp, err := client.Do(req) if err != nil { fmt.Println(fmt.Sprintf("%s error: %s", streamAddress, err)) return } defer resp.Body.Close() // Получаем размер промежутка, через который сервер присылает информацию о текущем треке metaint, err := strconv.Atoi(resp.Header.Get("icy-metaint")) if err != nil { fmt.Println(fmt.Sprintf("%s error while getting icy-metaint: %s", streamAddress, err)) return } if metaint < 1 { fmt.Println(fmt.Sprintf("%s sent incorrect icy-metaint value", streamAddress)) return } // И читаем всё вот в этот буфер в бесконечном цикле buf := make([]byte, 65536) remaining := metaint for { // Читаем кусок потока (и никак не используем) l, err := resp.Body.Read(buf[:remaining]) if err == io.EOF { break } if err != nil { fmt.Println(fmt.Sprintf("%s error: %s", streamAddress, err)) break } remaining -= l if remaining > 0 { // Ещё не дочитали до информации о текущем треке continue } // Дочитали до информации о текущем треке — считываем её длину _, err = io.ReadAtLeast(resp.Body, buf[:1], 1) if err != nil { fmt.Println(fmt.Sprintf("%s error: %s", streamAddress, err)) break } metalen := int(buf[0]) * 16 if metalen < 1 { remaining = metaint continue } // И считываем информацию с этой длиной _, err = io.ReadAtLeast(resp.Body, buf[:metalen], metalen) if err != nil { fmt.Println(fmt.Sprintf("%s error: %s", streamAddress, err)) break } // Готово streamInfo := string(bytes.Trim(buf[:metalen], "\x00")) fmt.Println(fmt.Sprintf("%s - %s", streamAddress, streamInfo)) // Повторяем всё то же самое в следующей итерации цикла remaining = metaint } }