video-server-backend/api/handler/streamvideo.go
Jose134 d9fbf941bd
All checks were successful
gitea/video-server-backend/pipeline/head This commit looks good
Structured the project in different files
2024-08-13 19:41:53 +02:00

75 lines
1.7 KiB
Go

package handler
import (
"errors"
"fmt"
"net/http"
"os"
"strconv"
"strings"
)
func StreamVideoHandler(w http.ResponseWriter, r *http.Request) {
videoPath := r.URL.Query().Get("v")
videoFile, err := os.Open(videoPath)
if err != nil {
http.Error(w, "Video file not found.", http.StatusNotFound)
return
}
defer videoFile.Close()
fileInfo, err := videoFile.Stat()
if err != nil {
http.Error(w, "Could not obtain file info.", http.StatusInternalServerError)
return
}
fileSize := fileInfo.Size()
rangeHeader := r.Header.Get("Range")
if rangeHeader == "" {
http.ServeFile(w, r, videoPath)
return
}
start, end, err := getStartEndRange(rangeHeader, fileSize)
if err != nil || start > end || end >= fileSize {
http.Error(w, "Invalid range.", http.StatusBadRequest)
return
}
w.Header().Set("Content-Type", "video/mp4")
w.Header().Set("Content-Range", fmt.Sprintf("bytes %d-%d/%d", start, end, fileSize))
w.Header().Set("Accept-Ranges", "bytes")
w.WriteHeader(http.StatusPartialContent)
videoFile.Seek(start, 0)
buf := make([]byte, end-start+1)
videoFile.Read(buf)
w.Write(buf)
}
func getStartEndRange(rangeHeader string, fileSize int64) (int64, int64, error) {
rangeParts := strings.Split(rangeHeader, "=")
if len(rangeParts) != 2 || rangeParts[0] != "bytes" {
return 0, 0, errors.New("invalid range header")
}
rangeSpec := strings.Split(rangeParts[1], "-")
start, err := strconv.ParseInt(rangeSpec[0], 10, 64)
if err != nil {
return 0, 0, errors.New("invalid range start")
}
var end int64
if len(rangeSpec) == 2 && rangeSpec[1] != "" {
end, err = strconv.ParseInt(rangeSpec[1], 10, 64)
if err != nil {
return 0, 0, errors.New("invalid range end")
}
} else {
end = fileSize - 1
}
return start, end, nil
}