package dvr import ( "context" "fmt" "log" "net/http" "net/url" "sync" "time" "github.com/grafov/m3u8" ) // playlistRefresher periodically fetches the playlist and enqueues new segments func PlaylistRefresher(ctx context.Context, playlistURL string, segmentsChan chan<- string, seen *sync.Map, interval time.Duration) { ticker := time.NewTicker(interval) defer ticker.Stop() for { select { case <-ctx.Done(): close(segmentsChan) return case <-ticker.C: segments, err := fetchPlaylistSegments(playlistURL) if err != nil { log.Printf("Error fetching playlist: %v", err) continue } for _, seg := range segments { if _, exists := seen.LoadOrStore(seg, true); !exists { segmentsChan <- seg } } } } } // fetchPlaylistSegments is a placeholder that parses the M3U8 and returns full URLs func fetchPlaylistSegments(playlistURL string) ([]string, error) { resp, err := http.Get(playlistURL) if err != nil { return nil, err } defer resp.Body.Close() playlist, listType, err := m3u8.DecodeFrom(resp.Body, true) if err != nil { return nil, err } if listType == m3u8.MASTER { return nil, fmt.Errorf("playlist is a master playlist") } media := playlist.(*m3u8.MediaPlaylist) base, err := url.Parse(playlistURL) if err != nil { return nil, err } var segments []string for _, segment := range media.Segments { if segment == nil { continue } rel, err := url.Parse(segment.URI) if err != nil { return nil, err } segments = append(segments, base.ResolveReference(rel).String()) } return segments, nil }