diff --git a/transcoder/main.go b/transcoder/main.go index 44e399d7..c3e355a3 100644 --- a/transcoder/main.go +++ b/transcoder/main.go @@ -176,19 +176,20 @@ func (h *Handler) GetInfo(c echo.Context) error { return err } + route := GetRoute(c) sha, err := src.GetHash(path) if err != nil { return err } - ret, err := src.GetInfo(path) + ret, err := src.GetInfo(path, sha, route) if err != nil { return err } // Run extractors to have them in cache - src.Extract(ret.Path, sha) + src.Extract(ret.Path, sha, route) go h.thumbnails.ExtractThumbnail( ret.Path, - fmt.Sprintf("%s/thumbnails.png", c.Request().Header.Get("X-Route")), + fmt.Sprintf("%s/thumbnails.png", route), ) return c.JSON(http.StatusOK, ret) } @@ -208,11 +209,12 @@ func (h *Handler) GetAttachment(c echo.Context) error { return err } + route := GetRoute(c) sha, err := src.GetHash(path) if err != nil { return err } - wait, err := src.Extract(path, sha) + wait, err := src.Extract(path, sha, route) if err != nil { return err } @@ -237,11 +239,12 @@ func (h *Handler) GetSubtitle(c echo.Context) error { return err } + route := GetRoute(c) sha, err := src.GetHash(path) if err != nil { return err } - wait, err := src.Extract(path, sha) + wait, err := src.Extract(path, sha, route) if err != nil { return err } @@ -264,7 +267,7 @@ func (h *Handler) GetThumbnails(c echo.Context) error { out, err := h.thumbnails.ExtractThumbnail( path, - fmt.Sprintf("%s/thumbnails.png", c.Request().Header.Get("X-Route")), + fmt.Sprintf("%s/thumbnails.png", GetRoute(c)), ) if err != nil { return err @@ -287,7 +290,7 @@ func (h *Handler) GetThumbnailsVtt(c echo.Context) error { out, err := h.thumbnails.ExtractThumbnail( path, - fmt.Sprintf("%s/thumbnails.png", c.Request().Header.Get("X-Route")), + fmt.Sprintf("%s/thumbnails.png", GetRoute(c)), ) if err != nil { return err diff --git a/transcoder/src/cmap.go b/transcoder/src/cmap.go index e10447cf..949d5e3f 100644 --- a/transcoder/src/cmap.go +++ b/transcoder/src/cmap.go @@ -48,6 +48,13 @@ func (m *CMap[K, V]) GetOrSet(key K, val V) (V, bool) { return m.GetOrCreate(key, func() V { return val }) } +func (m *CMap[K, V]) Set(key K, val V) { + m.lock.Lock() + defer m.lock.Unlock() + + m.data[key] = val +} + func (m *CMap[K, V]) Remove(key K) { m.lock.Lock() defer m.lock.Unlock() diff --git a/transcoder/src/extract.go b/transcoder/src/extract.go index fad60be7..390c8a9c 100644 --- a/transcoder/src/extract.go +++ b/transcoder/src/extract.go @@ -8,7 +8,7 @@ import ( var extracted = NewCMap[string, <-chan struct{}]() -func Extract(path string, sha string) (<-chan struct{}, error) { +func Extract(path string, sha string, route string) (<-chan struct{}, error) { ret := make(chan struct{}) existing, created := extracted.GetOrSet(sha, ret) if !created { @@ -16,7 +16,7 @@ func Extract(path string, sha string) (<-chan struct{}, error) { } go func() { - info, err := GetInfo(path) + info, err := GetInfo(path, sha, route) if err != nil { extracted.Remove(sha) close(ret) diff --git a/transcoder/src/info.go b/transcoder/src/info.go index 3e1c6431..07be5eaa 100644 --- a/transcoder/src/info.go +++ b/transcoder/src/info.go @@ -1,8 +1,6 @@ package src import ( - "crypto/sha1" - "encoding/hex" "fmt" "path/filepath" "strconv" @@ -12,6 +10,8 @@ import ( ) type MediaInfo struct { + // closed if the mediainfo is ready for read. open otherwise + ready <-chan struct{} // The sha1 of the video file. Sha string `json:"sha"` /// The internal path of the video file. @@ -173,7 +173,32 @@ var SubtitleExtensions = map[string]string{ "vtt": "vtt", } -func GetInfo(path string) (*MediaInfo, error) { +var infos = NewCMap[string, *MediaInfo]() + +func GetInfo(path string, sha string, route string) (*MediaInfo, error) { + var err error + + ret, _ := infos.GetOrCreate(sha, func() *MediaInfo { + readyChan := make(chan struct{}) + mi := &MediaInfo{ + Sha: sha, + ready: readyChan, + } + go func() { + var val *MediaInfo + val, err = getInfo(path, route) + *mi = *val + mi.ready = readyChan + mi.Sha = sha + close(readyChan) + }() + return mi + }) + <-ret.ready + return ret, err +} + +func getInfo(path string, route string) (*MediaInfo, error) { defer printExecTime("mediainfo for %s", path)() mi, err := mediainfo.Open(path) @@ -182,17 +207,6 @@ func GetInfo(path string) (*MediaInfo, error) { } defer mi.Close() - sha := mi.Parameter(mediainfo.StreamGeneral, 0, "UniqueID") - // Remove dummy values that some tools use. - if len(sha) <= 5 { - date := mi.Parameter(mediainfo.StreamGeneral, 0, "File_Modified_Date") - - h := sha1.New() - h.Write([]byte(path)) - h.Write([]byte(date)) - sha = hex.EncodeToString(h.Sum(nil)) - } - chapters_begin := ParseUint(mi.Parameter(mediainfo.StreamMenu, 0, "Chapters_Pos_Begin")) chapters_end := ParseUint(mi.Parameter(mediainfo.StreamMenu, 0, "Chapters_Pos_End")) @@ -204,7 +218,6 @@ func GetInfo(path string) (*MediaInfo, error) { // fmt.Printf("%s", mi.Option("info_parameters", "")) ret := MediaInfo{ - Sha: sha, Path: path, // Remove leading . Extension: filepath.Ext(path)[1:], @@ -248,7 +261,7 @@ func GetInfo(path string) (*MediaInfo, error) { extension := OrNull(SubtitleExtensions[format]) var link *string if extension != nil { - x := fmt.Sprintf("/video/%s/subtitle/%d.%s", sha, i, *extension) + x := fmt.Sprintf("%s/subtitle/%d.%s", route, i, *extension) link = &x } return Subtitle{ @@ -273,7 +286,7 @@ func GetInfo(path string) (*MediaInfo, error) { Fonts: Map( attachments, func(font string, _ int) string { - return fmt.Sprintf("/video/%s/attachment/%s", sha, font) + return fmt.Sprintf("%s/attachment/%s", route, font) }), } if len(ret.Videos) > 0 { diff --git a/transcoder/utils.go b/transcoder/utils.go index 6474aebd..4eaf7d4e 100644 --- a/transcoder/utils.go +++ b/transcoder/utils.go @@ -23,6 +23,10 @@ func GetPath(c echo.Context) (string, error) { return key, nil } +func GetRoute(c echo.Context) string { + return c.Request().Header.Get("X-Route") +} + func SanitizePath(path string) error { if strings.Contains(path, "/") || strings.Contains(path, "..") { return echo.NewHTTPError(http.StatusBadRequest, "Invalid parameter. Can't contains path delimiters or ..")