package mediastream import ( "errors" "fmt" "net/http" "net/url" "os" "path/filepath" "seanime/internal/events" "seanime/internal/util" "github.com/labstack/echo/v4" ) ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// // Direct ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// func (r *Repository) ServeEchoFile(c echo.Context, rawFilePath string, clientId string, libraryPaths []string) error { // Unescape the file path, ignore errors filePath, _ := url.PathUnescape(rawFilePath) // If the file path is base64 encoded, decode it if util.IsBase64(rawFilePath) { var err error filePath, err = util.Base64DecodeStr(rawFilePath) if err != nil { // this shouldn't happen, but just in case IsBase64 is wrong filePath, _ = url.PathUnescape(rawFilePath) } } // Make sure the file is in the library directories inLibrary := false for _, libraryPath := range libraryPaths { if util.IsFileUnderDir(filePath, libraryPath) { inLibrary = true break } } if !inLibrary { return c.NoContent(http.StatusNotFound) } r.logger.Trace().Str("filepath", filePath).Str("payload", rawFilePath).Msg("mediastream: Served file") // Content disposition filename := filepath.Base(filePath) c.Response().Header().Set("Content-Disposition", fmt.Sprintf("inline; filename=\"%s\"", filename)) return c.File(filePath) } func (r *Repository) ServeEchoDirectPlay(c echo.Context, clientId string) error { if !r.IsInitialized() { r.wsEventManager.SendEvent(events.MediastreamShutdownStream, "Module not initialized") return errors.New("module not initialized") } // Get current media mediaContainer, found := r.playbackManager.currentMediaContainer.Get() if !found { r.wsEventManager.SendEvent(events.MediastreamShutdownStream, "no file has been loaded") return errors.New("no file has been loaded") } if c.Request().Method == http.MethodHead { r.logger.Trace().Msg("mediastream: Received HEAD request for direct play") // Get the file size fileInfo, err := os.Stat(mediaContainer.Filepath) if err != nil { r.logger.Error().Msg("mediastream: Failed to get file info") return c.NoContent(http.StatusInternalServerError) } // Set the content length c.Response().Header().Set("Content-Length", fmt.Sprintf("%d", fileInfo.Size())) c.Response().Header().Set("Content-Type", "video/mp4") c.Response().Header().Set("Accept-Ranges", "bytes") filename := filepath.Base(mediaContainer.Filepath) c.Response().Header().Set("Content-Disposition", fmt.Sprintf("inline; filename=\"%s\"", filename)) return c.NoContent(http.StatusOK) } return c.File(mediaContainer.Filepath) }