diff --git a/http/subtitle.go b/http/subtitle.go
index 07c2dcfc..24b49256 100644
--- a/http/subtitle.go
+++ b/http/subtitle.go
@@ -2,7 +2,9 @@ package fbhttp
import (
"bytes"
+ "io"
"net/http"
+ "regexp"
"strings"
"github.com/asticode/go-astisub"
@@ -10,6 +12,8 @@ import (
"github.com/filebrowser/filebrowser/v2/files"
)
+var srtLineBreakTag = regexp.MustCompile(`(?i)
]*)?\s*/?>`)
+
var subtitleHandler = withUser(func(w http.ResponseWriter, r *http.Request, d *data) (int, error) {
if !d.user.Perm.Download {
return http.StatusAccepted, nil
@@ -49,7 +53,11 @@ func subtitleFileHandler(w http.ResponseWriter, r *http.Request, file *files.Fil
// load subtitle for conversion to vtt
var sub *astisub.Subtitles
if strings.HasSuffix(file.Name, ".srt") {
- sub, err = astisub.ReadFromSRT(fd)
+ content, readErr := io.ReadAll(fd)
+ if readErr != nil {
+ return http.StatusInternalServerError, readErr
+ }
+ sub, err = astisub.ReadFromSRT(bytes.NewReader(normalizeSRTLineBreaks(content)))
} else if strings.HasSuffix(file.Name, ".ass") || strings.HasSuffix(file.Name, ".ssa") {
sub, err = astisub.ReadFromSSA(fd)
}
@@ -78,3 +86,7 @@ func subtitleFileHandler(w http.ResponseWriter, r *http.Request, file *files.Fil
http.ServeContent(w, r, file.Name, file.ModTime, bytes.NewReader(buf.Bytes()))
return 0, nil
}
+
+func normalizeSRTLineBreaks(content []byte) []byte {
+ return srtLineBreakTag.ReplaceAll(content, []byte("\n"))
+}
diff --git a/http/subtitle_test.go b/http/subtitle_test.go
new file mode 100644
index 00000000..2520d453
--- /dev/null
+++ b/http/subtitle_test.go
@@ -0,0 +1,62 @@
+package fbhttp
+
+import (
+ "net/http"
+ "net/http/httptest"
+ "strings"
+ "testing"
+
+ "github.com/spf13/afero"
+
+ "github.com/filebrowser/filebrowser/v2/files"
+)
+
+func TestNormalizeSRTLineBreaks(t *testing.T) {
+ input := []byte("first
second
third
fourth
fifth")
+ got := string(normalizeSRTLineBreaks(input))
+ want := "first\nsecond\nthird\nfourth\nfifth"
+ if got != want {
+ t.Fatalf("normalizeSRTLineBreaks() = %q, want %q", got, want)
+ }
+}
+
+func TestSubtitleFileHandlerConvertsSRTBreakTags(t *testing.T) {
+ fs := afero.NewMemMapFs()
+ const path = "/sample.srt"
+ const content = "1\n" +
+ "00:00:01,000 --> 00:00:02,000\n" +
+ "First
Second
Third
Fourth\n\n"
+
+ if err := afero.WriteFile(fs, path, []byte(content), 0o644); err != nil {
+ t.Fatalf("failed to write subtitle: %v", err)
+ }
+ info, err := fs.Stat(path)
+ if err != nil {
+ t.Fatalf("failed to stat subtitle: %v", err)
+ }
+
+ file := &files.FileInfo{
+ Fs: fs,
+ Path: path,
+ Name: "sample.srt",
+ ModTime: info.ModTime(),
+ }
+ req := httptest.NewRequest(http.MethodGet, "/api/subtitle/sample.srt?inline=true", http.NoBody)
+ rec := httptest.NewRecorder()
+
+ status, err := subtitleFileHandler(rec, req, file)
+ if err != nil {
+ t.Fatalf("subtitleFileHandler returned error: %v", err)
+ }
+ if status != 0 {
+ t.Fatalf("subtitleFileHandler status = %d, want 0", status)
+ }
+
+ body := rec.Body.String()
+ if strings.Contains(body, "FirstSecond") {
+ t.Fatalf("WebVTT output collapsed SRT
tags: %q", body)
+ }
+ if !strings.Contains(body, "First\nSecond\nThird\nFourth") {
+ t.Fatalf("WebVTT output = %q, want converted SRT
tags as line breaks", body)
+ }
+}