package api import ( "bytes" "fmt" "math" "net/http" "os/exec" "strconv" "strings" ) func RegisterHlsEndpoints() { http.HandleFunc("/hls/index.m3u8", EndpointHlsM3U8) } /* TODO: endpoint for clients to query a video's: video tracks, audio tracks, captions Then add support to existing endpoints for specifiying these 3 options */ func EndpointHlsM3U8(w http.ResponseWriter, r *http.Request) { //TODO: clean up this mess options := strings.Split(strings.Split(strings.Replace(r.URL.String(), "%20", " ", -1), "?")[1], "&") //TODO: make the order of options not hardcoded libPathName := strings.TrimPrefix(options[0], "lib=") var lib Library for _, l := range Libraries { if l.PathName == libPathName { lib = l break } } filePath := lib.Path + strings.TrimPrefix(options[1], "path=") ffprobe := exec.Command( "ffprobe", "-v", "error", "-show_entries", "format=duration", "-of", "default=noprint_wrappers=1:nokey=1", filePath, ) var ffprobeStdout bytes.Buffer ffprobe.Stdout = &ffprobeStdout err := ffprobe.Run() if err != nil { http.Error(w, "Internal server error", http.StatusInternalServerError) return } fileLenStr := strings.TrimSuffix(ffprobeStdout.String(), "\n") fileLenFloat, err := strconv.ParseFloat(fileLenStr, 64) if err != nil { http.Error(w, "Internal server error", http.StatusInternalServerError) return } fileLenFloat = math.Ceil(fileLenFloat/6.0) * 6.0 fileLenInt := int(fileLenFloat) w.Header().Set("Content-Type", "application/vnd.apple.mpegurl") fmt.Fprintln(w, "#EXTM3U") fmt.Fprintln(w, "#EXT-X-VERSION:7") //TODO: make this configurable fmt.Fprintln(w, "#EXT-X-TARGETDURATION:6") fmt.Fprintln(w, "#EXT-X-MEDIA-SEQUENCE:0") for i := 0; i < fileLenInt/6; i++ { fmt.Fprintln(w, "#EXTINF:6.0,") fmt.Fprintf(w, "/hls/segment/%d.mp4?lib=%s&path=%s\n", i, lib.PathName, strings.TrimPrefix(options[1], "path=")) } fmt.Fprintln(w, "#EXT-X-ENDLIST") }