mirror of
https://github.com/zoriya/Kyoo.git
synced 2025-05-31 20:24:27 -04:00
Add video and audio index/segment routes
This commit is contained in:
parent
d3a1c57111
commit
80d1b1af0f
@ -54,6 +54,132 @@ func (h *Handler) GetMaster(c echo.Context) error {
|
|||||||
return c.String(http.StatusOK, ret)
|
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
|
||||||
//
|
//
|
||||||
// # Identify metadata about a file
|
// # Identify metadata about a file
|
||||||
@ -88,6 +214,10 @@ func main() {
|
|||||||
|
|
||||||
e.GET("/:resource/:slug/direct", DirectStream)
|
e.GET("/:resource/:slug/direct", DirectStream)
|
||||||
e.GET("/:resource/:slug/master.m3u8", h.GetMaster)
|
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.GET("/:resource/:slug/info", GetInfo)
|
||||||
|
|
||||||
e.Logger.Fatal(e.Start(":7666"))
|
e.Logger.Fatal(e.Start(":7666"))
|
||||||
|
@ -1,5 +1,11 @@
|
|||||||
package src
|
package src
|
||||||
|
|
||||||
|
import (
|
||||||
|
"net/http"
|
||||||
|
|
||||||
|
"github.com/labstack/echo/v4"
|
||||||
|
)
|
||||||
|
|
||||||
type Quality string
|
type Quality string
|
||||||
|
|
||||||
const (
|
const (
|
||||||
@ -17,6 +23,20 @@ const (
|
|||||||
// Purposfully removing Original from this list (since it require special treatments anyways)
|
// Purposfully removing Original from this list (since it require special treatments anyways)
|
||||||
var Qualities = []Quality{P240, P360, P480, P720, P1080, P1440, P4k, P8k}
|
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.
|
// I'm not entierly sure about the values for bitrates. Double checking would be nice.
|
||||||
func (v Quality) AverageBitrate() uint32 {
|
func (v Quality) AverageBitrate() uint32 {
|
||||||
switch v {
|
switch v {
|
||||||
|
@ -73,3 +73,29 @@ func (t *Transcoder) cleanUnused() {
|
|||||||
delete(t.streams, path)
|
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
|
||||||
|
}
|
||||||
|
@ -64,15 +64,26 @@ func GetClientId(c echo.Context) (string, error) {
|
|||||||
return key, nil
|
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) {
|
func ErrorHandler(err error, c echo.Context) {
|
||||||
code := http.StatusInternalServerError
|
code := http.StatusInternalServerError
|
||||||
|
var message string
|
||||||
if he, ok := err.(*echo.HTTPError); ok {
|
if he, ok := err.(*echo.HTTPError); ok {
|
||||||
code = he.Code
|
code = he.Code
|
||||||
|
message = fmt.Sprint(he.Message)
|
||||||
} else {
|
} else {
|
||||||
c.Logger().Error(err)
|
c.Logger().Error(err)
|
||||||
|
message = "Internal server error"
|
||||||
}
|
}
|
||||||
c.JSON(code, struct {
|
c.JSON(code, struct {
|
||||||
Errors []string `json:"errors"`
|
Errors []string `json:"errors"`
|
||||||
}{Errors: []string{fmt.Sprint(err)}})
|
}{Errors: []string{message}})
|
||||||
}
|
}
|
||||||
|
|
||||||
|
Loading…
x
Reference in New Issue
Block a user