From 31d33ce0fd2c4010b5c6dc871bd93eb5621a99df Mon Sep 17 00:00:00 2001 From: Brahim Hadriche Date: Sun, 27 Nov 2022 18:18:25 -0500 Subject: [PATCH 01/10] [Test] inject thumbnails in DASH --- src/components/VideoPlayer/Video.bs | 15 +- .../WebServer/Middleware/DashRouter.bs | 151 ++++++++++++++++++ .../WebServer/Task/WebServerTask.bs | 2 + src/source/utils/StringUtils.bs | 12 ++ 4 files changed, 175 insertions(+), 5 deletions(-) create mode 100644 src/components/WebServer/Middleware/DashRouter.bs diff --git a/src/components/VideoPlayer/Video.bs b/src/components/VideoPlayer/Video.bs index f01b71e7..c2d2944a 100644 --- a/src/components/VideoPlayer/Video.bs +++ b/src/components/VideoPlayer/Video.bs @@ -2,6 +2,7 @@ import "pkg:/source/services/Invidious.bs" function ShowVideoScreenEmbedded(videoId as string, thumbnailNode as object) m.videoPlayer = CreateObject("roSGNode", "VideoPlayer") + m.videoPlayer.id = "VideoPlayer" AddVideoFields() m.videoPlayer.embedded = true @@ -14,12 +15,11 @@ end function function ShowVideoScreenFull(videoId as string, sender as object) m.videoPlayer = CreateObject("roSGNode", "VideoPlayer") + m.videoPlayer.id = "VideoPlayer" m.videoPlayer.sender = sender AddVideoFields() m.videoPlayer.embedded = false - - ' TODO: make sure video is at right node - m.top.getParent().AppendChild(m.videoPlayer) + m.videoPlayer.getScene().AppendChild(m.videoPlayer) ShowVideoScreen(videoId) end function @@ -129,12 +129,17 @@ function StartVideoDetailsTask(videoId as string) metadata = task.output.metadata if metadata <> invalid contentNode = CreateObject("roSGNode", "ContentNode") - contentNode.addFields({ videoId: videoId }) + contentNode.addFields({ + videoId: videoId, + metadata: metadata + }) if metadata.hlsUrl <> invalid contentNode.url = metadata.hlsUrl else if metadata.dashUrl <> invalid - contentNode.url = metadata.dashUrl + ' Redirect to our server so we can inject thumbnails (storyboards) into the DASH manifest + ' TODO: make this optional, in case it breaks the DASH manifest + contentNode.url = `http://${GetLocalIpAddress()}:8888/dash?v=${videoId}` else stream = metadata.formatStreams[metadata.formatStreams.Count() - 1] itag = stream.itag diff --git a/src/components/WebServer/Middleware/DashRouter.bs b/src/components/WebServer/Middleware/DashRouter.bs new file mode 100644 index 00000000..9e462487 --- /dev/null +++ b/src/components/WebServer/Middleware/DashRouter.bs @@ -0,0 +1,151 @@ +import "pkg:/source/services/InvidiousSettings.bs" +import "pkg:/source/roku_modules/rokurequests/Requests.brs" + +namespace Http + + class DashRouter extends HttpRouter + + function new() + super() + + m.Get("*", function(context as object) as boolean + request = context.request + response = context.response + router = context.router + + route = request.uri + if not route.StartsWith("/dash") + return false + end if + + v = request.query.v + local = request.query.local + + instance = InvidiousSettings.GetSelectedInstance() + metadata = router.GetVideoMetadata(context, v) + dashUrl = `${instance}/api/manifest/dash/id/${v}` + + if metadata = invalid and local = invalid + m.Redirect(dashUrl, 302) + return true + end if + + if local <> invalid + dashUrl = `${dashUrl}?local=${local}` + end if + + resp = Requests().get(dashUrl) + text = resp.text + if resp.statuscode = 200 and local = "true" + text = text.Replace("/videoplayback", `${instance}/videoplayback`) + end if + + if resp.statuscode = 200 and metadata <> invalid + text = router.InjectStoryBoard(router, text, metadata) + end if + + response.http_code = resp.statuscode + response.buf.fromasciistring(text) + response.length = response.buf.count() + response.mimetype = "application/xml" + response.GenerateHeader(true) + response.source = Http.HttpResponseSource.GENERATED + + return true + end function) + end function + + function GetVideoMetadata(context as object, videoId as string) as object + scene = context.server.task.top.getScene() + videoPlayer = scene.findNode("VideoPlayer") + metadata = videoPlayer?.content?.metadata + if metadata <> invalid and metadata.videoId = videoId + return metadata + end if + metadata = Invidious.GetVideoMetadata(videoId) + return metadata + end function + + function InjectStoryBoard(router as object, dash as string, metadata as object) as string + xml = CreateObject ("roXMLElement") + if not xml.Parse(dash) + return dash + end if + + thumb_id = 0 + period = xml.GetChildNodes()[0] + sets = period.GetChildNodes() + for each set in sets + attributes = set.GetAttributes() + id = attributes.id + idInt = id.toInt() + if idInt >= thumb_id + thumb_id = idInt + 1 + end if + end for + + thumbnails = router.GenerateThumbnailAdaptationSet(metadata, thumb_id) + + injectPoint = StringLastIndexOf(dash, "") + "".Len() + + newDash = dash.Left(injectPoint) + thumbnails + dash.Mid(injectPoint) + + return newDash + end function + + function GenerateThumbnailAdaptationSet(metadata as object, id as integer) as string + result = "" + storyboards = metadata.storyboards + for each storyboard in storyboards + ' Broken storyboards have interval = 0 + ' TODO: implement proper segments when storyboard.storyboardCount > 1 + if storyboard.interval > 0 and storyboard.storyboardCount = 1 + tilesPerPage = storyboard.storyboardWidth * storyboard.storyboardHeight + intervalSeconds = (storyboard.interval / 1000) + for i = 0 to storyboard.storyboardCount - 1 + width = storyboard.width * storyboard.storyboardWidth + height = storyboard.height * storyboard.storyboardHeight + + tileCount = tilesPerPage + if i = storyboard.storyboardCount - 1 + tileCount = storyboard.count mod tilesPerPage + end if + + presentationTimeOffset = i * tilesPerPage * intervalSeconds + + duration = tileCount * intervalSeconds + + result += `` + result += `` + + ' TODO: estimate bandwidth? + result += `` + url = storyboard.templateUrl.Replace("$M", `${i}`) + + urlEscapeChars = {} + urlEscapeChars["&"] = "&" + urlEscapeChars["'"] = "'" + urlEscapeChars[`"`] = """ + urlEscapeChars["<"] = "<" + urlEscapeChars[">"] = ">" + + for each escapeChar in urlEscapeChars + url = url.Replace(escapeChar, urlEscapeChars[escapeChar]) + end for + + result += `${url}` + result += `` + result += `` + exit for + end for + result += `` + id += 1 + exit for + end if + end for + return result + end function + + end class + +end namespace diff --git a/src/components/WebServer/Task/WebServerTask.bs b/src/components/WebServer/Task/WebServerTask.bs index 072ffade..547ed650 100644 --- a/src/components/WebServer/Task/WebServerTask.bs +++ b/src/components/WebServer/Task/WebServerTask.bs @@ -7,6 +7,7 @@ import "pkg:/components/WebServer/Middleware/RegistryApiRouter.bs" import "pkg:/components/WebServer/Middleware/StateApiRouter.bs" import "pkg:/components/WebServer/Middleware/CommandsApiRouter.bs" import "pkg:/components/WebServer/Middleware/CorsMiddleware.bs" +import "pkg:/components/WebServer/Middleware/DashRouter.bs" function Init() m.top.functionName = "WebServerLoop" @@ -30,6 +31,7 @@ function WebServerLoop() m.server.UseRouter(new Http.CorsMiddleware(`http://${GetLocalIpAddress()}:8888`)) m.server.UseRouter(homeRouter) + m.server.UseRouter(new Http.DashRouter()) m.server.UseRouter(new Http.CommandsApiRouter()) m.server.UseRouter(new Http.StateApiRouter()) m.server.UseRouter(new Http.RegistryApiRouter()) diff --git a/src/source/utils/StringUtils.bs b/src/source/utils/StringUtils.bs index 3e73dac4..b3220adb 100644 --- a/src/source/utils/StringUtils.bs +++ b/src/source/utils/StringUtils.bs @@ -113,3 +113,15 @@ end function function Quote() as string return chr(34) end function + +function StringLastIndexOf(str as string, substr as string) as integer + index = str.InStr(substr) + while index <> -1 + newIndex = str.InStr(index + 1, substr) + if newIndex = -1 + return index + end if + index = newIndex + end while + return index +end function From c98aca10835fb4ed5862f8665f02c54b72a4ac75 Mon Sep 17 00:00:00 2001 From: Brahim Hadriche Date: Sun, 27 Nov 2022 19:14:34 -0500 Subject: [PATCH 02/10] Address wrong storyboard hight --- .../WebServer/Middleware/DashRouter.bs | 16 ++++++++++++---- 1 file changed, 12 insertions(+), 4 deletions(-) diff --git a/src/components/WebServer/Middleware/DashRouter.bs b/src/components/WebServer/Middleware/DashRouter.bs index 9e462487..430826c4 100644 --- a/src/components/WebServer/Middleware/DashRouter.bs +++ b/src/components/WebServer/Middleware/DashRouter.bs @@ -97,14 +97,22 @@ namespace Http result = "" storyboards = metadata.storyboards for each storyboard in storyboards - ' Broken storyboards have interval = 0 + ' BUG: Broken storyboards have interval = 0 https://github.com/iv-org/invidious/issues/3441 ' TODO: implement proper segments when storyboard.storyboardCount > 1 if storyboard.interval > 0 and storyboard.storyboardCount = 1 - tilesPerPage = storyboard.storyboardWidth * storyboard.storyboardHeight + + ' BUG: storyboardHeight can be wrong https://github.com/iv-org/invidious/issues/3440 + ' TODO: this fix/assumption is only if we have storyboard.storyboardCount = 1 + storyboardHeight = storyboard.count \ storyboard.storyboardWidth + if storyboard.count mod storyboard.storyboardWidth > 0 + storyboardHeight += 1 + end if + + tilesPerPage = storyboard.storyboardWidth * storyboardHeight intervalSeconds = (storyboard.interval / 1000) for i = 0 to storyboard.storyboardCount - 1 width = storyboard.width * storyboard.storyboardWidth - height = storyboard.height * storyboard.storyboardHeight + height = storyboard.height * storyboardHeight tileCount = tilesPerPage if i = storyboard.storyboardCount - 1 @@ -134,7 +142,7 @@ namespace Http end for result += `${url}` - result += `` + result += `` result += `` exit for end for From 87501c3553db8cc368cf6b09e2c088337e86a67f Mon Sep 17 00:00:00 2001 From: Brahim Hadriche Date: Mon, 28 Nov 2022 10:23:19 -0500 Subject: [PATCH 03/10] Better dash --- src/components/WebServer/HttpRequest.bs | 2 +- .../WebServer/Middleware/DashRouter.bs | 91 ++++++++++--------- .../WebServer/Task/WebServerTask.bs | 2 +- 3 files changed, 50 insertions(+), 45 deletions(-) diff --git a/src/components/WebServer/HttpRequest.bs b/src/components/WebServer/HttpRequest.bs index cefb276f..6579cd02 100644 --- a/src/components/WebServer/HttpRequest.bs +++ b/src/components/WebServer/HttpRequest.bs @@ -159,7 +159,7 @@ namespace Http m.ready_for_response = true return false end if - + m.ready_for_response = m.body.len() = contentLength return m.ready_for_response end if diff --git a/src/components/WebServer/Middleware/DashRouter.bs b/src/components/WebServer/Middleware/DashRouter.bs index 430826c4..da5b5ab4 100644 --- a/src/components/WebServer/Middleware/DashRouter.bs +++ b/src/components/WebServer/Middleware/DashRouter.bs @@ -46,7 +46,7 @@ namespace Http response.http_code = resp.statuscode response.buf.fromasciistring(text) - response.length = response.buf.count() + response.length = response.buf.count() response.mimetype = "application/xml" response.GenerateHeader(true) response.source = Http.HttpResponseSource.GENERATED @@ -84,7 +84,7 @@ namespace Http end if end for - thumbnails = router.GenerateThumbnailAdaptationSet(metadata, thumb_id) + thumbnails = router.GenerateThumbnailAdaptationSet(router, metadata, thumb_id) injectPoint = StringLastIndexOf(dash, "") + "".Len() @@ -93,67 +93,72 @@ namespace Http return newDash end function - function GenerateThumbnailAdaptationSet(metadata as object, id as integer) as string + function GenerateThumbnailAdaptationSet(router as object, metadata as object, id as integer) as string result = "" storyboards = metadata.storyboards for each storyboard in storyboards ' BUG: Broken storyboards have interval = 0 https://github.com/iv-org/invidious/issues/3441 ' TODO: implement proper segments when storyboard.storyboardCount > 1 - if storyboard.interval > 0 and storyboard.storyboardCount = 1 - + if storyboard.interval > 0 ' BUG: storyboardHeight can be wrong https://github.com/iv-org/invidious/issues/3440 ' TODO: this fix/assumption is only if we have storyboard.storyboardCount = 1 - storyboardHeight = storyboard.count \ storyboard.storyboardWidth - if storyboard.count mod storyboard.storyboardWidth > 0 - storyboardHeight += 1 + storyboardHeight = storyboard.storyboardHeight + if storyboard.storyboardCount = 1 + storyboardHeight = storyboard.count \ storyboard.storyboardWidth + if storyboard.count mod storyboard.storyboardWidth > 0 + storyboardHeight += 1 + end if end if tilesPerPage = storyboard.storyboardWidth * storyboardHeight intervalSeconds = (storyboard.interval / 1000) - for i = 0 to storyboard.storyboardCount - 1 - width = storyboard.width * storyboard.storyboardWidth - height = storyboard.height * storyboardHeight - tileCount = tilesPerPage - if i = storyboard.storyboardCount - 1 - tileCount = storyboard.count mod tilesPerPage - end if + url = router.EscapeUrlForXml(storyboard.templateUrl.Replace("$M", "$Number$")) + + tileCount = tilesPerPage + duration = tileCount * intervalSeconds + + width = storyboard.width * storyboard.storyboardWidth + height = storyboard.height * storyboardHeight + + ' Bandwidth is kind of a guess... + bandwidth = Int((width * height * 0.5) / duration) - presentationTimeOffset = i * tilesPerPage * intervalSeconds - - duration = tileCount * intervalSeconds - - result += `` - result += `` - - ' TODO: estimate bandwidth? - result += `` - url = storyboard.templateUrl.Replace("$M", `${i}`) - - urlEscapeChars = {} - urlEscapeChars["&"] = "&" - urlEscapeChars["'"] = "'" - urlEscapeChars[`"`] = """ - urlEscapeChars["<"] = "<" - urlEscapeChars[">"] = ">" - - for each escapeChar in urlEscapeChars - url = url.Replace(escapeChar, urlEscapeChars[escapeChar]) - end for - - result += `${url}` - result += `` - result += `` - exit for - end for + result += `` + result += `` + result += `` + + ' TODO: the last image in the list is usually smaller than the others. For example: + ' Consider a video with 85 thumbnails, in tiles of 5x5 + ' 1st tile is 5x5 (25) + ' 2nd tile is 5x5 (50) + ' 3rd tile is 5x5 (75) + ' 4th tile is 5x2 (85) + ' This makes the display always misinterpret the the last tile if it is smaller + result += `` + result += `` result += `` + id += 1 - exit for end if end for return result end function + function EscapeUrlForXml(url as string) as string + urlEscapeChars = {} + urlEscapeChars["&"] = "&" + urlEscapeChars["'"] = "'" + urlEscapeChars[`"`] = """ + urlEscapeChars["<"] = "<" + urlEscapeChars[">"] = ">" + + for each escapeChar in urlEscapeChars + url = url.Replace(escapeChar, urlEscapeChars[escapeChar]) + end for + return url + end function + end class end namespace diff --git a/src/components/WebServer/Task/WebServerTask.bs b/src/components/WebServer/Task/WebServerTask.bs index 547ed650..54c7125b 100644 --- a/src/components/WebServer/Task/WebServerTask.bs +++ b/src/components/WebServer/Task/WebServerTask.bs @@ -19,7 +19,7 @@ function WebServerLoop() m.settings = new Http.HttpSettings(m.webServerPort) ' Root at www to get http://IP_ADDRESS:PORT/index.html m.settings.WwwRoot = "pkg:/www" - m.settings.Timeout = 5000 + m.settings.Timeout = 2000 m.server = new Http.HttpServer(m.settings, m) homeRouter = new Http.HttpRouter() From 76845337cdaa7f624d14148291f860ec29a5cd42 Mon Sep 17 00:00:00 2001 From: Brahim Hadriche Date: Mon, 28 Nov 2022 10:45:36 -0500 Subject: [PATCH 04/10] Feature flag it for now --- src/components/VideoPlayer/Video.bs | 13 ++++++++++--- 1 file changed, 10 insertions(+), 3 deletions(-) diff --git a/src/components/VideoPlayer/Video.bs b/src/components/VideoPlayer/Video.bs index 53063971..89d64ee3 100644 --- a/src/components/VideoPlayer/Video.bs +++ b/src/components/VideoPlayer/Video.bs @@ -1,5 +1,7 @@ import "pkg:/source/services/Invidious.bs" +#const DASH_THUMBNAILS = false + function ShowVideoScreen(videoId as string, sender as object) m.videoPlayer = CreateObject("roSGNode", "VideoPlayer") m.videoPlayer.sender = sender @@ -100,9 +102,14 @@ function StartVideoDetailsTask(videoId as string) if metadata.hlsUrl <> invalid contentNode.url = metadata.hlsUrl else if metadata.dashUrl <> invalid - ' Redirect to our server so we can inject thumbnails (storyboards) into the DASH manifest - ' TODO: make this optional, in case it breaks the DASH manifest - contentNode.url = `http://${GetLocalIpAddress()}:8888/dash?v=${videoId}` + #if DASH_THUMBNAILS + ' Redirect to our server so we can inject thumbnails (storyboards) into the DASH manifest + ' TODO: make this optional, in case it breaks the DASH manifest + contentNode.url = `http://${GetLocalIpAddress()}:8888/dash?v=${videoId}` + #else + contentNode.url = metadata.dashUrl + #end if + else stream = metadata.formatStreams[metadata.formatStreams.Count() - 1] itag = stream.itag From a7619c35b1facc97c78c6bca2b86c08081118b29 Mon Sep 17 00:00:00 2001 From: Brahim Hadriche Date: Mon, 28 Nov 2022 11:56:53 -0500 Subject: [PATCH 05/10] Add a small safety check and some comments --- src/components/WebServer/Middleware/DashRouter.bs | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/src/components/WebServer/Middleware/DashRouter.bs b/src/components/WebServer/Middleware/DashRouter.bs index da5b5ab4..a3707ca7 100644 --- a/src/components/WebServer/Middleware/DashRouter.bs +++ b/src/components/WebServer/Middleware/DashRouter.bs @@ -113,6 +113,12 @@ namespace Http tilesPerPage = storyboard.storyboardWidth * storyboardHeight intervalSeconds = (storyboard.interval / 1000) + ' If the template changed from known format, abort. + if storyboard.templateUrl.Instr("$M") + return "" + end if + ' Youtube template uses the var $M for tile pages + ' DASH-IF uses $Number$ in the SegmentTemplate url = router.EscapeUrlForXml(storyboard.templateUrl.Replace("$M", "$Number$")) tileCount = tilesPerPage From 80976d9f6c0bf2eb47cad81d0849f3c8c9c128c6 Mon Sep 17 00:00:00 2001 From: Brahim Hadriche Date: Tue, 29 Nov 2022 18:14:39 -0500 Subject: [PATCH 06/10] Fix thumbnails --- src/components/WebServer/Middleware/DashRouter.bs | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/src/components/WebServer/Middleware/DashRouter.bs b/src/components/WebServer/Middleware/DashRouter.bs index a3707ca7..5b09b68b 100644 --- a/src/components/WebServer/Middleware/DashRouter.bs +++ b/src/components/WebServer/Middleware/DashRouter.bs @@ -114,7 +114,7 @@ namespace Http intervalSeconds = (storyboard.interval / 1000) ' If the template changed from known format, abort. - if storyboard.templateUrl.Instr("$M") + if storyboard.templateUrl.Instr("$M") = -1 return "" end if ' Youtube template uses the var $M for tile pages @@ -132,7 +132,8 @@ namespace Http result += `` result += `` - result += `` + result += `` ' TODO: the last image in the list is usually smaller than the others. For example: ' Consider a video with 85 thumbnails, in tiles of 5x5 From b360707b40d4a4577bbca3ec0a54c5ba682d238e Mon Sep 17 00:00:00 2001 From: Brahim Hadriche Date: Tue, 29 Nov 2022 18:35:35 -0500 Subject: [PATCH 07/10] Fix content type --- src/components/WebServer/Middleware/DashRouter.bs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/components/WebServer/Middleware/DashRouter.bs b/src/components/WebServer/Middleware/DashRouter.bs index 5b09b68b..50eabba4 100644 --- a/src/components/WebServer/Middleware/DashRouter.bs +++ b/src/components/WebServer/Middleware/DashRouter.bs @@ -47,7 +47,7 @@ namespace Http response.http_code = resp.statuscode response.buf.fromasciistring(text) response.length = response.buf.count() - response.mimetype = "application/xml" + response.mimetype = "application/dash+xml" response.GenerateHeader(true) response.source = Http.HttpResponseSource.GENERATED From 3590b38d2392cdd15f2a7632f6006e24b215f7c8 Mon Sep 17 00:00:00 2001 From: Brahim Hadriche Date: Tue, 29 Nov 2022 18:49:36 -0500 Subject: [PATCH 08/10] Fix dash router --- src/components/WebServer/Middleware/DashRouter.bs | 12 +++--------- 1 file changed, 3 insertions(+), 9 deletions(-) diff --git a/src/components/WebServer/Middleware/DashRouter.bs b/src/components/WebServer/Middleware/DashRouter.bs index 50eabba4..31c344a8 100644 --- a/src/components/WebServer/Middleware/DashRouter.bs +++ b/src/components/WebServer/Middleware/DashRouter.bs @@ -8,16 +8,11 @@ namespace Http function new() super() - m.Get("*", function(context as object) as boolean + m.Get("/dash", function(context as object) as boolean request = context.request response = context.response router = context.router - route = request.uri - if not route.StartsWith("/dash") - return false - end if - v = request.query.v local = request.query.local @@ -45,9 +40,8 @@ namespace Http end if response.http_code = resp.statuscode - response.buf.fromasciistring(text) - response.length = response.buf.count() - response.mimetype = "application/dash+xml" + response.SetBodyDataString(text) + response.ContentType("application/dash+xml") response.GenerateHeader(true) response.source = Http.HttpResponseSource.GENERATED From b3694e5fc8c72a19bbb78139e98879456a07bdec Mon Sep 17 00:00:00 2001 From: Brahim Hadriche Date: Tue, 29 Nov 2022 18:51:05 -0500 Subject: [PATCH 09/10] Remove comment --- src/components/WebServer/Middleware/DashRouter.bs | 1 - 1 file changed, 1 deletion(-) diff --git a/src/components/WebServer/Middleware/DashRouter.bs b/src/components/WebServer/Middleware/DashRouter.bs index 31c344a8..65918cf6 100644 --- a/src/components/WebServer/Middleware/DashRouter.bs +++ b/src/components/WebServer/Middleware/DashRouter.bs @@ -92,7 +92,6 @@ namespace Http storyboards = metadata.storyboards for each storyboard in storyboards ' BUG: Broken storyboards have interval = 0 https://github.com/iv-org/invidious/issues/3441 - ' TODO: implement proper segments when storyboard.storyboardCount > 1 if storyboard.interval > 0 ' BUG: storyboardHeight can be wrong https://github.com/iv-org/invidious/issues/3440 ' TODO: this fix/assumption is only if we have storyboard.storyboardCount = 1 From b74ad15707bb5a5d6dd2d84a6b3c79f247aa9e61 Mon Sep 17 00:00:00 2001 From: Brahim Hadriche Date: Tue, 29 Nov 2022 21:23:34 -0500 Subject: [PATCH 10/10] Move function, add null check --- .../WebServer/Middleware/DashRouter.bs | 19 +++---------------- src/source/utils/WebUtils.bs | 14 ++++++++++++++ 2 files changed, 17 insertions(+), 16 deletions(-) diff --git a/src/components/WebServer/Middleware/DashRouter.bs b/src/components/WebServer/Middleware/DashRouter.bs index 65918cf6..9bbe7ba1 100644 --- a/src/components/WebServer/Middleware/DashRouter.bs +++ b/src/components/WebServer/Middleware/DashRouter.bs @@ -1,3 +1,4 @@ +import "pkg:/source/utils/WebUtils.bs" import "pkg:/source/services/InvidiousSettings.bs" import "pkg:/source/roku_modules/rokurequests/Requests.brs" @@ -30,7 +31,7 @@ namespace Http end if resp = Requests().get(dashUrl) - text = resp.text + text = resp.text ?? "" if resp.statuscode = 200 and local = "true" text = text.Replace("/videoplayback", `${instance}/videoplayback`) end if @@ -112,7 +113,7 @@ namespace Http end if ' Youtube template uses the var $M for tile pages ' DASH-IF uses $Number$ in the SegmentTemplate - url = router.EscapeUrlForXml(storyboard.templateUrl.Replace("$M", "$Number$")) + url = WebUtils.EscapeUrlForXml(storyboard.templateUrl.Replace("$M", "$Number$")) tileCount = tilesPerPage duration = tileCount * intervalSeconds @@ -145,20 +146,6 @@ namespace Http return result end function - function EscapeUrlForXml(url as string) as string - urlEscapeChars = {} - urlEscapeChars["&"] = "&" - urlEscapeChars["'"] = "'" - urlEscapeChars[`"`] = """ - urlEscapeChars["<"] = "<" - urlEscapeChars[">"] = ">" - - for each escapeChar in urlEscapeChars - url = url.Replace(escapeChar, urlEscapeChars[escapeChar]) - end for - return url - end function - end class end namespace diff --git a/src/source/utils/WebUtils.bs b/src/source/utils/WebUtils.bs index ad08ce5e..300bc1a8 100644 --- a/src/source/utils/WebUtils.bs +++ b/src/source/utils/WebUtils.bs @@ -125,4 +125,18 @@ namespace WebUtils return validstr(hcm["n" + Stri(code).trim()]) end function + function EscapeUrlForXml(url as string) as string + urlEscapeChars = {} + urlEscapeChars["&"] = "&" + urlEscapeChars["'"] = "'" + urlEscapeChars[`"`] = """ + urlEscapeChars["<"] = "<" + urlEscapeChars[">"] = ">" + + for each escapeChar in urlEscapeChars + url = url.Replace(escapeChar, urlEscapeChars[escapeChar]) + end for + return url + end function + end namespace