From 2afed432f7cd6c6ce493181b52aa051dbb219412 Mon Sep 17 00:00:00 2001 From: Zoe Roux Date: Sun, 18 Feb 2024 22:23:39 +0100 Subject: [PATCH] Use concurrent map for subtitles --- transcoder/main.go | 50 ++++++++++++++++++++++-------------- transcoder/src/extract.go | 39 ++++++++++------------------ transcoder/src/thumbnails.go | 2 +- transcoder/src/utils.go | 2 +- 4 files changed, 47 insertions(+), 46 deletions(-) diff --git a/transcoder/main.go b/transcoder/main.go index c8ccc73f..44e399d7 100644 --- a/transcoder/main.go +++ b/transcoder/main.go @@ -176,12 +176,16 @@ func (h *Handler) GetInfo(c echo.Context) error { return err } + sha, err := src.GetHash(path) + if err != nil { + return err + } ret, err := src.GetInfo(path) if err != nil { return err } // Run extractors to have them in cache - h.extractor.RunExtractor(ret.Path, ret.Sha, &ret.Subtitles) + src.Extract(ret.Path, sha) go h.thumbnails.ExtractThumbnail( ret.Path, fmt.Sprintf("%s/thumbnails.png", c.Request().Header.Get("X-Route")), @@ -195,46 +199,56 @@ func (h *Handler) GetInfo(c echo.Context) error { // // Path: /attachment/:name func (h *Handler) GetAttachment(c echo.Context) error { + path, err := GetPath(c) + if err != nil { + return err + } name := c.Param("name") - if err := SanitizePath(name); err != nil { return err } - wait, ok := h.extractor.Extract(sha) - if !ok { - return echo.NewHTTPError(http.StatusBadRequest, "Not extracted yet. Call /info to extract.") + sha, err := src.GetHash(path) + if err != nil { + return err + } + wait, err := src.Extract(path, sha) + if err != nil { + return err } <-wait - path := fmt.Sprintf("%s/%s/att/%s", src.Settings.Metadata, sha, name) - return c.File(path) + ret := fmt.Sprintf("%s/%s/att/%s", src.Settings.Metadata, sha, name) + return c.File(ret) } // Get subtitle // // Get a specific subtitle. // -// Path: /:sha/subtitle/:name +// Path: /subtitle/:name func (h *Handler) GetSubtitle(c echo.Context) error { - sha := c.Param("sha") - name := c.Param("name") - - if err := SanitizePath(sha); err != nil { + path, err := GetPath(c) + if err != nil { return err } + name := c.Param("name") if err := SanitizePath(name); err != nil { return err } - wait, ok := h.extractor.Extract(sha) - if !ok { - return echo.NewHTTPError(http.StatusBadRequest, "Not extracted yet. Call /info to extract.") + sha, err := src.GetHash(path) + if err != nil { + return err + } + wait, err := src.Extract(path, sha) + if err != nil { + return err } <-wait - path := fmt.Sprintf("%s/%s/sub/%s", src.Settings.Metadata, sha, name) - return c.File(path) + ret := fmt.Sprintf("%s/%s/sub/%s", src.Settings.Metadata, sha, name) + return c.File(ret) } // Get thumbnail sprite @@ -284,7 +298,6 @@ func (h *Handler) GetThumbnailsVtt(c echo.Context) error { type Handler struct { transcoder *src.Transcoder - extractor *src.Extractor thumbnails *src.ThumbnailsCreator } @@ -300,7 +313,6 @@ func main() { } h := Handler{ transcoder: transcoder, - extractor: src.NewExtractor(), thumbnails: src.NewThumbnailsCreator(), } diff --git a/transcoder/src/extract.go b/transcoder/src/extract.go index 6f2e00ca..fad60be7 100644 --- a/transcoder/src/extract.go +++ b/transcoder/src/extract.go @@ -4,36 +4,24 @@ import ( "fmt" "os" "os/exec" - "sync" ) -type Extractor struct { - extracted map[string]<-chan struct{} - lock sync.RWMutex -} +var extracted = NewCMap[string, <-chan struct{}]() -func NewExtractor() *Extractor { - return &Extractor{ - extracted: make(map[string]<-chan struct{}), - } -} - -func (e *Extractor) Extract(path string, subs *[]Subtitle) (<-chan struct{}, error) { - sha, err := getHash(path) - if err != nil { - return nil, err - } - - e.lock.Lock() - existing, ok := e.extracted[sha] - if ok { +func Extract(path string, sha string) (<-chan struct{}, error) { + ret := make(chan struct{}) + existing, created := extracted.GetOrSet(sha, ret) + if !created { return existing, nil } - ret := make(chan struct{}) - e.extracted[sha] = ret - e.lock.Unlock() go func() { + info, err := GetInfo(path) + if err != nil { + extracted.Remove(sha) + close(ret) + return + } attachment_path := fmt.Sprintf("%s/%s/att", Settings.Metadata, sha) subs_path := fmt.Sprintf("%s/%s/sub", Settings.Metadata, sha) os.MkdirAll(attachment_path, 0o644) @@ -49,7 +37,7 @@ func (e *Extractor) Extract(path string, subs *[]Subtitle) (<-chan struct{}, err ) cmd.Dir = attachment_path - for _, sub := range *subs { + for _, sub := range info.Subtitles { if ext := sub.Extension; ext != nil { cmd.Args = append( cmd.Args, @@ -61,8 +49,9 @@ func (e *Extractor) Extract(path string, subs *[]Subtitle) (<-chan struct{}, err } fmt.Printf("Starting extraction with the command: %s", cmd) cmd.Stdout = nil - err := cmd.Run() + err = cmd.Run() if err != nil { + extracted.Remove(sha) fmt.Println("Error starting ffmpeg extract:", err) } close(ret) diff --git a/transcoder/src/thumbnails.go b/transcoder/src/thumbnails.go index bb0e9edf..aed62a85 100644 --- a/transcoder/src/thumbnails.go +++ b/transcoder/src/thumbnails.go @@ -68,7 +68,7 @@ func (t *ThumbnailsCreator) ExtractThumbnail(path string, name string) (string, func extractThumbnail(path string, name string) (string, error) { defer printExecTime("extracting thumbnails for %s", path)() - sha, err := getHash(path) + sha, err := GetHash(path) if err != nil { return "", err } diff --git a/transcoder/src/utils.go b/transcoder/src/utils.go index 74156d46..9fd84e8b 100644 --- a/transcoder/src/utils.go +++ b/transcoder/src/utils.go @@ -19,7 +19,7 @@ func printExecTime(message string, args ...any) func() { } } -func getHash(path string) (string, error) { +func GetHash(path string) (string, error) { info, err := os.Stat(path) if err != nil { return "", err