From d86f0c30e1726a56e670955c3b995945c1daf834 Mon Sep 17 00:00:00 2001 From: RblSb Date: Thu, 6 Feb 2025 06:41:49 +0300 Subject: Fixes pack - Fix timer seek on server pause with double timer.pause() calls - Implement multi-caching - Better uploading progress with XMLHttpRequest - Better upload/cache error reporting --- src/client/Buttons.hx | 86 ++++++++++++++++++++++++++++++--------------------- src/client/Main.hx | 42 +++++++++++++------------ src/client/Player.hx | 11 +++++-- 3 files changed, 81 insertions(+), 58 deletions(-) (limited to 'src/client') diff --git a/src/client/Buttons.hx b/src/client/Buttons.hx index 99e12cb..513133a 100644 --- a/src/client/Buttons.hx +++ b/src/client/Buttons.hx @@ -1,18 +1,20 @@ package client; import Types.UploadResponse; -import Types.WsEvent; import client.Main.getEl; +import haxe.Json; import haxe.Timer; -import haxe.io.Path; import js.Browser.document; import js.Browser.window; +import js.html.Blob; import js.html.Element; import js.html.ImageElement; import js.html.InputElement; import js.html.KeyboardEvent; +import js.html.ProgressEvent; import js.html.TransitionEvent; import js.html.VisualViewport; +import js.html.XMLHttpRequest; class Buttons { static var split:Split; @@ -250,51 +252,63 @@ class Buttons { // send last chunk separately to allow server file streaming while uploading final chunkSize = 1024 * 1024 * 5; // 5 MB - if (buffer.byteLength > chunkSize) { - final lastChunk = buffer.slice(buffer.byteLength - chunkSize); - window.fetch("/upload-last-chunk", { - method: "POST", - headers: { - "content-name": Path.withoutExtension(name), - "client-name": main.getName(), - }, - body: lastChunk, - }); - } - - // send full file - final request = window.fetch("/upload", { + final bufferOffset = (buffer.byteLength - chunkSize).limitMin(0); + final lastChunk = buffer.slice(bufferOffset); + final chunkReq = window.fetch("/upload-last-chunk", { method: "POST", headers: { - "content-name": Path.withoutExtension(name), + "content-name": name, "client-name": main.getName(), }, - body: buffer, + body: lastChunk, }); - request.then(e -> { + chunkReq.then(e -> { e.json().then((data:UploadResponse) -> { - trace(data.info); - if (data.errorId == null) return; - main.serverMessage(data.info, true, false); + if (data.errorId != null) { + main.serverMessage(data.info, true, false); + return; + } + final input:InputElement = getEl("#mediaurl"); + input.value = data.url; + }); + }); + + final request = new XMLHttpRequest(); + request.open("POST", "/upload", true); + request.setRequestHeader("content-name", name); + request.setRequestHeader("client-name", main.getName()); + + request.upload.onprogress = (event:ProgressEvent) -> { + var ratio = 0.0; + if (event.lengthComputable) { + ratio = (event.loaded / event.total).clamp(0, 1); + } + main.onProgressEvent({ + type: Progress, + progress: { + type: Uploading, + ratio: ratio + } }); - }).catchError(err -> { - trace(err); + } + + request.onload = (e:ProgressEvent) -> { + final data:UploadResponse = try { + Json.parse(request.responseText); + } catch (e) { + trace(e); + return; + } + if (data.errorId == null) return; + main.serverMessage(data.info, true, false); + } + request.onloadend = () -> { Timer.delay(() -> { main.hideDynamicChin(); }, 500); - }); - - // set file url to input after upload starts - function onStartUpload(event:WsEvent):Void { - if (event.type != Progress) return; - final data = event.progress; - if (data.type != Uploading) return; - if (data.data == null) return; - final input:InputElement = getEl("#mediaurl"); - input.value = data.data; - JsApi.off(Progress, onStartUpload); } - JsApi.on(Progress, onStartUpload); + + request.send(new Blob([buffer])); }); } diff --git a/src/client/Main.hx b/src/client/Main.hx index 84f6838..5c4b28d 100644 --- a/src/client/Main.hx +++ b/src/client/Main.hx @@ -120,7 +120,7 @@ class Main { if (!player.isVideoLoaded()) return; gotFirstPageInteraction = true; player.unmute(); - if (!hasLeader() && !showingServerPause) player.play(); + if (!hasLeader() && !showingServerPause && !player.inUserInteraction) player.play(); document.removeEventListener("click", onFirstInteraction); } @@ -508,24 +508,7 @@ class Main { serverMessage(text); case Progress: - final data = data.progress; - final text = switch data.type { - case Caching: - final caching = Lang.get("caching"); - final name = data.data; - '$caching $name'; - case Downloading: Lang.get("downloading"); - case Uploading: Lang.get("uploading"); - } - final percent = (data.ratio * 100).toFixed(1); - var text = '$text...'; - if (percent > 0) text += ' $percent%'; - showProgressInfo(text); - if (data.ratio == 1) { - Timer.delay(() -> { - hideDynamicChin(); - }, 500); - } + onProgressEvent(data); case AddVideo: player.addVideoItem(data.addVideo.item, data.addVideo.atEnd); @@ -675,6 +658,27 @@ class Main { } } + public function onProgressEvent(data:WsEvent):Void { + final data = data.progress; + final text = switch data.type { + case Caching: + final caching = Lang.get("caching"); + final name = data.data; + '$caching $name'; + case Downloading: Lang.get("downloading"); + case Uploading: Lang.get("uploading"); + } + final percent = (data.ratio * 100).toFixed(1); + var text = '$text...'; + if (percent > 0) text += ' $percent%'; + showProgressInfo(text); + if (data.ratio == 1) { + Timer.delay(() -> { + hideDynamicChin(); + }, 500); + } + } + function updateLastStateTime():Void { if (lastStateTimeStamp == 0) { lastStateTimeStamp = Timer.stamp(); diff --git a/src/client/Player.hx b/src/client/Player.hx index e5ea87c..64248fe 100644 --- a/src/client/Player.hx +++ b/src/client/Player.hx @@ -279,8 +279,11 @@ class Player { if (!main.isLeader()) { // user click, so we can unpause by removing leader // (doesn't work in Firefox because of no video click propagation) - final allowUnpause = (hasAutoPause && inUserInteraction); - if (allowUnpause || main.hasUnpauseWithoutLeader()) { + var allowUnpause = hasAutoPause && inUserInteraction; + if (!allowUnpause) allowUnpause = main.hasUnpauseWithoutLeader(); + // do not remove leader with custom rate + if (getPlaybackRate() != 1) allowUnpause = false; + if (allowUnpause) { main.removeLeader(); } else { // paused and no leader - instant pause @@ -299,7 +302,9 @@ class Player { }); if (hasAutoPause) { // do not remove leader if user cannot request it back - if (main.hasPermission(RequestLeaderPerm)) main.toggleLeader(); + if (main.hasPermission(RequestLeaderPerm) && getPlaybackRate() == 1) { + main.removeLeader(); + } } } -- cgit v1.2.3