Add video and audio index/segment routes

This commit is contained in:
Zoe Roux 2024-01-14 01:24:40 +01:00
parent d3a1c57111
commit 80d1b1af0f
4 changed files with 189 additions and 2 deletions

View File

@ -54,6 +54,132 @@ func (h *Handler) GetMaster(c echo.Context) error {
return c.String(http.StatusOK, ret)
}
// Transcode video
//
// Transcode the video to the selected quality.
// This route can take a few seconds to respond since it will way for at least one segment to be
// available.
//
// Path: /:resource/:slug/:quality/index.m3u8
func (h *Handler) GetVideoIndex(c echo.Context) error {
resource := c.Param("resource")
slug := c.Param("slug")
quality, err := src.QualityFromString(c.Param("quality"))
if err != nil {
return err
}
client, err := GetClientId(c)
if err != nil {
return err
}
path, err := GetPath(resource, slug)
if err != nil {
return err
}
ret, err := h.transcoder.GetVideoIndex(path, quality, client)
if err != nil {
return err
}
return c.String(http.StatusOK, ret)
}
// Transcode audio
//
// Get the selected audio
// This route can take a few seconds to respond since it will way for at least one segment to be
// available.
//
// Path: /:resource/:slug/audio/:audio/index.m3u8
func (h *Handler) GetAudioIndex(c echo.Context) error {
resource := c.Param("resource")
slug := c.Param("slug")
audio := c.Param("audio")
client, err := GetClientId(c)
if err != nil {
return err
}
path, err := GetPath(resource, slug)
if err != nil {
return err
}
ret, err := h.transcoder.GetAudioIndex(path, audio, client)
if err != nil {
return err
}
return c.String(http.StatusOK, ret)
}
// Get transmuxed chunk
//
// Retrieve a chunk of a transmuxed video.
//
// Path: /:resource/:slug/:quality/segments-:chunk.ts
func (h *Handler) GetVideoSegment(c echo.Context) error {
resource := c.Param("resource")
slug := c.Param("slug")
quality, err := src.QualityFromString(c.Param("quality"))
if err != nil {
return err
}
segment, err := ParseSegment(c.Param("chunk"))
if err != nil {
return err
}
client, err := GetClientId(c)
if err != nil {
return err
}
path, err := GetPath(resource, slug)
if err != nil {
return err
}
ret, err := h.transcoder.GetVideoSegment(path, quality, segment, client)
if err != nil {
return err
}
return c.File(ret)
}
// Get audio chunk
//
// Retrieve a chunk of a transcoded audio.
//
// Path: /:resource/:slug/audio/:audio/segments-:chunk.ts
func (h *Handler) GetAudioSegment(c echo.Context) error {
resource := c.Param("resource")
slug := c.Param("slug")
audio := c.Param("audio")
segment, err := ParseSegment(c.Param("chunk"))
if err != nil {
return err
}
client, err := GetClientId(c)
if err != nil {
return err
}
path, err := GetPath(resource, slug)
if err != nil {
return err
}
ret, err := h.transcoder.GetAudioSegment(path, audio, segment, client)
if err != nil {
return err
}
return c.File(ret)
}
// Identify
//
// # Identify metadata about a file
@ -88,6 +214,10 @@ func main() {
e.GET("/:resource/:slug/direct", DirectStream)
e.GET("/:resource/:slug/master.m3u8", h.GetMaster)
e.GET("/:resource/:slug/:quality/index.m3u8", h.GetVideoIndex)
e.GET("/:resource/:slug/audio/:audio/index.m3u8", h.GetAudioIndex)
e.GET("/:resource/:slug/:quality/:chunk", h.GetVideoSegment)
e.GET("/:resource/:slug/audio/:audio/:chunk", h.GetAudioSegment)
e.GET("/:resource/:slug/info", GetInfo)
e.Logger.Fatal(e.Start(":7666"))

View File

@ -1,5 +1,11 @@
package src
import (
"net/http"
"github.com/labstack/echo/v4"
)
type Quality string
const (
@ -17,6 +23,20 @@ const (
// Purposfully removing Original from this list (since it require special treatments anyways)
var Qualities = []Quality{P240, P360, P480, P720, P1080, P1440, P4k, P8k}
func QualityFromString(str string) (Quality, error) {
if str == string(Original) {
return Original, nil
}
qualities := Qualities
for _, quality := range qualities {
if string(quality) == str {
return quality, nil
}
}
return Original, echo.NewHTTPError(http.StatusBadRequest, "Invalid quality")
}
// I'm not entierly sure about the values for bitrates. Double checking would be nice.
func (v Quality) AverageBitrate() uint32 {
switch v {

View File

@ -73,3 +73,29 @@ func (t *Transcoder) cleanUnused() {
delete(t.streams, path)
}
}
func (t *Transcoder) GetVideoIndex(path string, quality Quality, client string) (string, error) {
return "", nil
}
func (t *Transcoder) GetAudioIndex(path string, audio string, client string) (string, error) {
return "", nil
}
func (t *Transcoder) GetVideoSegment(
path string,
quality Quality,
segment int32,
client string,
) (string, error) {
return "", nil
}
func (t *Transcoder) GetAudioSegment(
path string,
audio string,
segment int32,
client string,
) (string, error) {
return "", nil
}

View File

@ -64,15 +64,26 @@ func GetClientId(c echo.Context) (string, error) {
return key, nil
}
func ParseSegment(segment string) (int32, error) {
var ret int32
_, err := fmt.Sscanf(segment, "segment-%d.ts", &ret)
if err != nil {
return 0, echo.NewHTTPError(http.StatusBadRequest, "Could not parse segment.")
}
return ret, nil
}
func ErrorHandler(err error, c echo.Context) {
code := http.StatusInternalServerError
var message string
if he, ok := err.(*echo.HTTPError); ok {
code = he.Code
message = fmt.Sprint(he.Message)
} else {
c.Logger().Error(err)
message = "Internal server error"
}
c.JSON(code, struct {
Errors []string `json:"errors"`
}{Errors: []string{fmt.Sprint(err)}})
}{Errors: []string{message}})
}