From be0bd81107301cb7f8450001a0ff6b399661b8b3 Mon Sep 17 00:00:00 2001 From: Arthur Jamet Date: Sat, 11 May 2024 11:06:27 +0200 Subject: [PATCH 1/4] Transcoder: Prevent error caused by buggy chapters parsing by mediainfo --- transcoder/src/info.go | 21 +++++++++++++++++++-- 1 file changed, 19 insertions(+), 2 deletions(-) diff --git a/transcoder/src/info.go b/transcoder/src/info.go index 3a75c621c..10f32b409 100644 --- a/transcoder/src/info.go +++ b/transcoder/src/info.go @@ -13,6 +13,7 @@ import ( "strconv" "strings" "sync" + "unicode" "github.com/zoriya/go-mediainfo" ) @@ -152,6 +153,15 @@ func Map[T, U any](ts []T, f func(T, int) U) []U { return us } +func Filter[T any](ss []T, test func(T, int) bool) (ret []T) { + for i, s := range ss { + if test(s, i) { + ret = append(ret, s) + } + } + return +} + func OrNull(str string) *string { if str == "" { return nil @@ -300,13 +310,20 @@ func getInfo(path string) (*MediaInfo, error) { Link: link, } }), - Chapters: Map(make([]Chapter, max(chapters_end-chapters_begin, 1)-1), func(_ Chapter, i int) Chapter { + Chapters: Filter(Map(make([]Chapter, max(chapters_end-chapters_begin, 1)-1), func(_ Chapter, i int) Chapter { + startTime := mi.GetI(mediainfo.StreamMenu, 0, int(chapters_begin)+i, mediainfo.InfoName) + // We expect `startTime` to be something like `00:00:00` + if len(startTime) > 0 && !unicode.IsDigit(rune(startTime[0])) { + return Chapter{} + } return Chapter{ - StartTime: ParseTime(mi.GetI(mediainfo.StreamMenu, 0, int(chapters_begin)+i, mediainfo.InfoName)), + StartTime: ParseTime(startTime), // +1 is safe, the value at chapters_end contains the right duration EndTime: ParseTime(mi.GetI(mediainfo.StreamMenu, 0, int(chapters_begin)+i+1, mediainfo.InfoName)), Name: mi.GetI(mediainfo.StreamMenu, 0, int(chapters_begin)+i, mediainfo.InfoText), } + }), func(chapter Chapter, i int) bool { + return chapter != Chapter{} }), Fonts: Map( attachments, From 9222b2e2d3150d01f34e1c0b69e15c7120d95778 Mon Sep 17 00:00:00 2001 From: Arthur Jamet Date: Sat, 11 May 2024 13:41:23 +0200 Subject: [PATCH 2/4] Transcoder: More sturdy fix for faulty chapter parsing --- transcoder/src/info.go | 46 ++++++++++++++++++++++++++++-------------- 1 file changed, 31 insertions(+), 15 deletions(-) diff --git a/transcoder/src/info.go b/transcoder/src/info.go index 10f32b409..16a8268a3 100644 --- a/transcoder/src/info.go +++ b/transcoder/src/info.go @@ -310,21 +310,7 @@ func getInfo(path string) (*MediaInfo, error) { Link: link, } }), - Chapters: Filter(Map(make([]Chapter, max(chapters_end-chapters_begin, 1)-1), func(_ Chapter, i int) Chapter { - startTime := mi.GetI(mediainfo.StreamMenu, 0, int(chapters_begin)+i, mediainfo.InfoName) - // We expect `startTime` to be something like `00:00:00` - if len(startTime) > 0 && !unicode.IsDigit(rune(startTime[0])) { - return Chapter{} - } - return Chapter{ - StartTime: ParseTime(startTime), - // +1 is safe, the value at chapters_end contains the right duration - EndTime: ParseTime(mi.GetI(mediainfo.StreamMenu, 0, int(chapters_begin)+i+1, mediainfo.InfoName)), - Name: mi.GetI(mediainfo.StreamMenu, 0, int(chapters_begin)+i, mediainfo.InfoText), - } - }), func(chapter Chapter, i int) bool { - return chapter != Chapter{} - }), + Chapters: getChapters(chapters_begin, chapters_end, mi), Fonts: Map( attachments, func(font string, _ int) string { @@ -354,3 +340,33 @@ func getInfo(path string) (*MediaInfo, error) { } return &ret, nil } + +func chapterTimeIsValid(chapterTime string) bool { + return len(chapterTime) > 0 && unicode.IsDigit(rune(chapterTime[0])) +} + +func getChapters(chapters_begin uint32, chapters_end uint32, mi *mediainfo.File) []Chapter { + chapterCount := max(chapters_end-chapters_begin, 1) - 1 + chapterIterationCount := chapterCount + + for i := uint32(0); i < chapterIterationCount; i++ { + startTime := mi.GetI(mediainfo.StreamMenu, 0, int(chapters_begin+i), mediainfo.InfoName) + if !chapterTimeIsValid(startTime) { + chapterIterationCount = chapterIterationCount + 1 + } + } + return Filter(Map(make([]Chapter, chapterIterationCount), func(_ Chapter, i int) Chapter { + startTime := mi.GetI(mediainfo.StreamMenu, 0, int(chapters_begin)+i, mediainfo.InfoName) + if !chapterTimeIsValid(startTime) { + return Chapter{} + } + return Chapter{ + StartTime: ParseTime(startTime), + // +1 is safe, the value at chapters_end contains the right duration + EndTime: ParseTime(mi.GetI(mediainfo.StreamMenu, 0, int(chapters_begin)+i+1, mediainfo.InfoName)), + Name: mi.GetI(mediainfo.StreamMenu, 0, int(chapters_begin)+i, mediainfo.InfoText), + } + }), func(chapter Chapter, i int) bool { + return chapter != Chapter{} + }) +} From 8a2343e76b8e1f1508ec58aa37f7b75ee754ec5b Mon Sep 17 00:00:00 2001 From: Arthur Jamet Date: Mon, 13 May 2024 20:12:59 +0200 Subject: [PATCH 3/4] Transcoder: Fix missing last chapter --- transcoder/src/info.go | 22 ++++++++++++++-------- 1 file changed, 14 insertions(+), 8 deletions(-) diff --git a/transcoder/src/info.go b/transcoder/src/info.go index 16a8268a3..1481f3315 100644 --- a/transcoder/src/info.go +++ b/transcoder/src/info.go @@ -252,13 +252,14 @@ func getInfo(path string) (*MediaInfo, error) { // fmt.Printf("%s", mi.Option("info_parameters", "")) + // duration in seconds + duration := ParseFloat(mi.Parameter(mediainfo.StreamGeneral, 0, "Duration")) / 1000 ret := MediaInfo{ Path: path, // Remove leading . Extension: filepath.Ext(path)[1:], Size: ParseUint64(mi.Parameter(mediainfo.StreamGeneral, 0, "FileSize")), - // convert ms to seconds - Duration: ParseFloat(mi.Parameter(mediainfo.StreamGeneral, 0, "Duration")) / 1000, + Duration: duration, Container: OrNull(mi.Parameter(mediainfo.StreamGeneral, 0, "Format")), Videos: Map(make([]Video, ParseUint(mi.Parameter(mediainfo.StreamVideo, 0, "StreamCount"))), func(_ Video, i int) Video { return Video{ @@ -310,7 +311,7 @@ func getInfo(path string) (*MediaInfo, error) { Link: link, } }), - Chapters: getChapters(chapters_begin, chapters_end, mi), + Chapters: getChapters(chapters_begin, chapters_end, mi, duration), Fonts: Map( attachments, func(font string, _ int) string { @@ -345,8 +346,8 @@ func chapterTimeIsValid(chapterTime string) bool { return len(chapterTime) > 0 && unicode.IsDigit(rune(chapterTime[0])) } -func getChapters(chapters_begin uint32, chapters_end uint32, mi *mediainfo.File) []Chapter { - chapterCount := max(chapters_end-chapters_begin, 1) - 1 +func getChapters(chapters_begin uint32, chapters_end uint32, mi *mediainfo.File, duration float32) []Chapter { + chapterCount := max(chapters_end-chapters_begin, 1) chapterIterationCount := chapterCount for i := uint32(0); i < chapterIterationCount; i++ { @@ -360,11 +361,16 @@ func getChapters(chapters_begin uint32, chapters_end uint32, mi *mediainfo.File) if !chapterTimeIsValid(startTime) { return Chapter{} } + // +1 is safe, the value at chapters_end contains the right duration + rawEndTime := mi.GetI(mediainfo.StreamMenu, 0, int(chapters_begin)+i+1, mediainfo.InfoName) + parsedEndTime := duration + if chapterTimeIsValid(rawEndTime) { + parsedEndTime = ParseTime(rawEndTime) + } return Chapter{ StartTime: ParseTime(startTime), - // +1 is safe, the value at chapters_end contains the right duration - EndTime: ParseTime(mi.GetI(mediainfo.StreamMenu, 0, int(chapters_begin)+i+1, mediainfo.InfoName)), - Name: mi.GetI(mediainfo.StreamMenu, 0, int(chapters_begin)+i, mediainfo.InfoText), + EndTime: parsedEndTime, + Name: mi.GetI(mediainfo.StreamMenu, 0, int(chapters_begin)+i, mediainfo.InfoText), } }), func(chapter Chapter, i int) bool { return chapter != Chapter{} From 324afc8022f3b2a9f369369b9e8c64d9f0d9fd0d Mon Sep 17 00:00:00 2001 From: Arthur Jamet Date: Mon, 13 May 2024 21:43:35 +0200 Subject: [PATCH 4/4] Transcoder: Make Chapter parsing simpler --- transcoder/src/info.go | 49 ++++++++++++++++++------------------------ 1 file changed, 21 insertions(+), 28 deletions(-) diff --git a/transcoder/src/info.go b/transcoder/src/info.go index 1481f3315..5d30b0280 100644 --- a/transcoder/src/info.go +++ b/transcoder/src/info.go @@ -153,15 +153,6 @@ func Map[T, U any](ts []T, f func(T, int) U) []U { return us } -func Filter[T any](ss []T, test func(T, int) bool) (ret []T) { - for i, s := range ss { - if test(s, i) { - ret = append(ret, s) - } - } - return -} - func OrNull(str string) *string { if str == "" { return nil @@ -349,30 +340,32 @@ func chapterTimeIsValid(chapterTime string) bool { func getChapters(chapters_begin uint32, chapters_end uint32, mi *mediainfo.File, duration float32) []Chapter { chapterCount := max(chapters_end-chapters_begin, 1) chapterIterationCount := chapterCount + chapters := make([]Chapter, chapterCount) + chapterIndex := 0 - for i := uint32(0); i < chapterIterationCount; i++ { - startTime := mi.GetI(mediainfo.StreamMenu, 0, int(chapters_begin+i), mediainfo.InfoName) - if !chapterTimeIsValid(startTime) { + for i := 0; i < int(chapterIterationCount); i++ { + rawStartTime := mi.GetI(mediainfo.StreamMenu, 0, int(chapters_begin)+i, mediainfo.InfoName) + rawEndTime := mi.GetI(mediainfo.StreamMenu, 0, int(chapters_begin)+i+1, mediainfo.InfoName) + // If true, this "chapter" is invalid. We skip it + if !chapterTimeIsValid(rawStartTime) { chapterIterationCount = chapterIterationCount + 1 + continue } - } - return Filter(Map(make([]Chapter, chapterIterationCount), func(_ Chapter, i int) Chapter { - startTime := mi.GetI(mediainfo.StreamMenu, 0, int(chapters_begin)+i, mediainfo.InfoName) - if !chapterTimeIsValid(startTime) { - return Chapter{} - } - // +1 is safe, the value at chapters_end contains the right duration - rawEndTime := mi.GetI(mediainfo.StreamMenu, 0, int(chapters_begin)+i+1, mediainfo.InfoName) - parsedEndTime := duration + var endTime float32 + // If this fails, we probably are at the end of the video + // Since there would be no following chapter, + // we defacto set the end time to the end of the video (i.e. its duration) if chapterTimeIsValid(rawEndTime) { - parsedEndTime = ParseTime(rawEndTime) + endTime = ParseTime(rawEndTime) + } else { + endTime = duration } - return Chapter{ - StartTime: ParseTime(startTime), - EndTime: parsedEndTime, + chapters[chapterIndex] = Chapter{ + StartTime: ParseTime(rawStartTime), + EndTime: endTime, Name: mi.GetI(mediainfo.StreamMenu, 0, int(chapters_begin)+i, mediainfo.InfoText), } - }), func(chapter Chapter, i int) bool { - return chapter != Chapter{} - }) + chapterIndex++ + } + return chapters }