Advertisement
andreymal

https://ru.stackoverflow.com/questions/1538393

Aug 30th, 2023 (edited)
1,454
0
Never
Not a member of Pastebin yet? Sign Up, it unlocks many cool features!
Go 2.87 KB | None | 0 0
  1. package main
  2.  
  3. import (
  4.     "bytes"
  5.     "fmt"
  6.     "io"
  7.     "net/http"
  8.     "strconv"
  9.     "sync"
  10.     "time"
  11. )
  12.  
  13. func main() {
  14.     var streams = [...]string{"https://c17.radioboss.fm:18509/stream"}
  15.     var wg sync.WaitGroup
  16.  
  17.     for _, stream := range streams {
  18.         time.Sleep(1 * time.Second)
  19.         wg.Add(1)
  20.  
  21.         // Внимание, асинхронный вызов!
  22.         go makePlaylist(stream, &wg)
  23.     }
  24.  
  25.     // Ждём пока все асинхронные горутины завершатся
  26.     wg.Wait()
  27. }
  28.  
  29. func makePlaylist(streamAddress string, wg *sync.WaitGroup) {
  30.     defer wg.Done()
  31.  
  32.     // Формируем HTTP-запрос
  33.     client := &http.Client{}
  34.     req, err := http.NewRequest("GET", streamAddress, nil)
  35.     if err != nil {
  36.         fmt.Println(fmt.Sprintf("%s error: %s", streamAddress, err))
  37.         return
  38.     }
  39.     req.Header.Add("icy-metadata", "1")
  40.  
  41.     // Отправляем
  42.     resp, err := client.Do(req)
  43.     if err != nil {
  44.         fmt.Println(fmt.Sprintf("%s error: %s", streamAddress, err))
  45.         return
  46.     }
  47.     defer resp.Body.Close()
  48.  
  49.     // Получаем размер промежутка, через который сервер присылает информацию о текущем треке
  50.     metaint, err := strconv.Atoi(resp.Header.Get("icy-metaint"))
  51.     if err != nil {
  52.         fmt.Println(fmt.Sprintf("%s error while getting icy-metaint: %s", streamAddress, err))
  53.         return
  54.     }
  55.     if metaint < 1 {
  56.         fmt.Println(fmt.Sprintf("%s sent incorrect icy-metaint value", streamAddress))
  57.         return
  58.     }
  59.  
  60.     // И читаем всё вот в этот буфер в бесконечном цикле
  61.     buf := make([]byte, 65536)
  62.     remaining := metaint
  63.  
  64.     for {
  65.         // Читаем кусок потока (и никак не используем)
  66.         l, err := resp.Body.Read(buf[:remaining])
  67.         if err == io.EOF {
  68.             break
  69.         }
  70.         if err != nil {
  71.             fmt.Println(fmt.Sprintf("%s error: %s", streamAddress, err))
  72.             break
  73.         }
  74.         remaining -= l
  75.  
  76.         if remaining > 0 {
  77.             // Ещё не дочитали до информации о текущем треке
  78.             continue
  79.         }
  80.  
  81.         // Дочитали до информации о текущем треке — считываем её длину
  82.         _, err = io.ReadAtLeast(resp.Body, buf[:1], 1)
  83.         if err != nil {
  84.             fmt.Println(fmt.Sprintf("%s error: %s", streamAddress, err))
  85.             break
  86.         }
  87.  
  88.         metalen := int(buf[0]) * 16
  89.         if metalen < 1 {
  90.             remaining = metaint
  91.             continue
  92.         }
  93.  
  94.         // И считываем информацию с этой длиной
  95.         _, err = io.ReadAtLeast(resp.Body, buf[:metalen], metalen)
  96.         if err != nil {
  97.             fmt.Println(fmt.Sprintf("%s error: %s", streamAddress, err))
  98.             break
  99.         }
  100.  
  101.         // Готово
  102.         streamInfo := string(bytes.Trim(buf[:metalen], "\x00"))
  103.         fmt.Println(fmt.Sprintf("%s - %s", streamAddress, streamInfo))
  104.  
  105.         // Повторяем всё то же самое в следующей итерации цикла
  106.         remaining = metaint
  107.     }
  108. }
  109.  
Advertisement
Add Comment
Please, Sign In to add comment
Advertisement