diff options
| -rw-r--r-- | .vscode/launch.json | 6 | ||||
| -rw-r--r-- | .vscode/tasks.json | 7 | ||||
| -rw-r--r-- | build-client.hxml | 3 | ||||
| -rw-r--r-- | build-server.hxml | 8 | ||||
| -rw-r--r-- | res/client.js | 153 | ||||
| -rw-r--r-- | src/client/Buttons.hx | 71 | ||||
| -rw-r--r-- | src/client/FileUploader.hx | 93 | ||||
| -rw-r--r-- | src/client/Utils.hx | 21 | ||||
| -rw-r--r-- | tests.hxml | 5 |
9 files changed, 215 insertions, 152 deletions
diff --git a/.vscode/launch.json b/.vscode/launch.json index f91d1ed..e7d6d8b 100644 --- a/.vscode/launch.json +++ b/.vscode/launch.json @@ -5,8 +5,10 @@ "request": "launch", "name": "Node: build and run", "program": "${workspaceFolder}/build/server.js", - "args": ["--verbose"], - "sourceMaps": true, + "runtimeExecutable": "node", + "args": [ + // "--verbose" + ], "preLaunchTask": "Build all", "killBehavior": "polite", "console": "integratedTerminal" diff --git a/.vscode/tasks.json b/.vscode/tasks.json index dbd6a3b..0b315f6 100644 --- a/.vscode/tasks.json +++ b/.vscode/tasks.json @@ -19,12 +19,7 @@ }, "presentation": { "clear": true - }, - "dependsOn": "Clear terminal" - }, - { - "label": "Clear terminal", - "command": "${command:workbench.action.terminal.clear}", + } }, { "label": "Run tests", diff --git a/build-client.hxml b/build-client.hxml index c3dcd74..ae1f26a 100644 --- a/build-client.hxml +++ b/build-client.hxml @@ -1,8 +1,7 @@ ---library youtubeIFramePlayer:git:https://github.com/okawa-h/youtubeIFramePlayer-externs.git
+--library youtubeIFramePlayer:git:https://github.com/haxe-externs/youtubeIFramePlayer-externs.git
--library hls.js-extern:git:https://github.com/zoldesi-andor/hls.js-haxe-extern.git
--class-path src
--main client.Main
-D analyzer-optimize
--w -WDeprecatedEnumAbstract
--dce full
--js res/client.js
diff --git a/build-server.hxml b/build-server.hxml index 8d4f8b4..f326f84 100644 --- a/build-server.hxml +++ b/build-server.hxml @@ -1,15 +1,13 @@ --library hxnodejs
---library hxnodejs-ws
+--library hxnodejs-ws:git:https://github.com/haxe-externs/hxnodejs-ws.git
--library json2object:git:https://github.com/RblSb/json2object.git#nightly_safe_macros
---library ytdlp-nodejs:git:https://github.com/RblSb/ytdlp-nodejs-externs.git
+--library ytdlp-nodejs:git:https://github.com/haxe-externs/ytdlp-nodejs-externs.git
# Client libs for completion
---library youtubeIFramePlayer:git:https://github.com/okawa-h/youtubeIFramePlayer-externs.git
+--library youtubeIFramePlayer:git:https://github.com/haxe-externs/youtubeIFramePlayer-externs.git
--library hls.js-extern:git:https://github.com/zoldesi-andor/hls.js-haxe-extern.git
--library utest
--class-path src
--main server.Main
-D analyzer-optimize
-# -w -WDeprecatedEnumAbstract
--w -WDeprecated
--dce full
--js build/server.js
diff --git a/res/client.js b/res/client.js index 85e1905..eeea7b3 100644 --- a/res/client.js +++ b/res/client.js @@ -815,58 +815,8 @@ client_Buttons.init = function(main) { mediaUrl.focus(); }; window.document.querySelector("#mediaurl-upload").onclick = function(e) { - client_Utils.browseFile(function(buffer,name) { - if(name == null) { - name = ""; - } - var _this_r = new RegExp("[?#%/\\\\]","g".split("u").join("")); - name = StringTools.trim(name.replace(_this_r,"")); - if(name.length == 0) { - name = "video"; - } - name = window.encodeURIComponent(name); - var a = buffer.byteLength - 5242880; - var lastChunk = buffer.slice(a < 0 ? 0 : a); - var chunkReq = window.fetch("/upload-last-chunk",{ method : "POST", headers : { "content-name" : name}, body : lastChunk}); - chunkReq.then(function(e) { - return e.json().then(function(data) { - if(data.errorId != null) { - main.serverMessage(data.info,true,false); - return; - } - window.document.querySelector("#mediaurl").value = data.url; - }); - }); - var request = new XMLHttpRequest(); - request.open("POST","/upload",true); - request.setRequestHeader("content-name",name); - request.upload.onprogress = function(event) { - var ratio = 0.0; - if(event.lengthComputable) { - var v = event.loaded / event.total; - ratio = v < 0 ? 0 : v > 1 ? 1 : v; - } - main.onProgressEvent({ type : "Progress", progress : { type : "Uploading", ratio : ratio}}); - }; - request.onload = function(e) { - var data; - try { - data = JSON.parse(request.responseText); - } catch( _g ) { - haxe_Log.trace(haxe_Exception.caught(_g),{ fileName : "src/client/Buttons.hx", lineNumber : 316, className : "client.Buttons", methodName : "init"}); - return; - } - if(data.errorId == null) { - return; - } - main.serverMessage(data.info,true,false); - }; - request.onloadend = function() { - return haxe_Timer.delay(function() { - main.hideDynamicChin(); - },500); - }; - request.send(new Blob([buffer])); + client_Utils.browseJsFile(function(file) { + new client_FileUploader(main).uploadFile(file); }); }; var showOptions = window.document.querySelector("#showoptions"); @@ -1136,6 +1086,72 @@ client_Buttons.initPageFullscreen = function() { } }; }; +var client_FileUploader = function(main) { + this.main = main; +}; +client_FileUploader.__name__ = true; +client_FileUploader.prototype = { + uploadFile: function(file) { + var _gthis = this; + var _this_r = new RegExp("[?#%/\\\\]","g".split("u").join("")); + var name = StringTools.trim(file.name.replace(_this_r,"")); + if(name.length == 0) { + name = "video"; + } + name = window.encodeURIComponent(name); + this.uploadLastChunk(file,name,function(data) { + if(data.errorId != null) { + _gthis.main.serverMessage(data.info,true,false); + return; + } + window.document.querySelector("#mediaurl").value = data.url; + _gthis.uploadFullFile(name,file); + }); + } + ,uploadFullFile: function(name,file) { + var _gthis = this; + var request = new XMLHttpRequest(); + request.open("POST","/upload",true); + request.setRequestHeader("content-name",name); + request.upload.onprogress = function(event) { + var ratio = 0.0; + if(event.lengthComputable) { + var v = event.loaded / event.total; + ratio = v < 0 ? 0 : v > 1 ? 1 : v; + } + _gthis.main.onProgressEvent({ type : "Progress", progress : { type : "Uploading", ratio : ratio}}); + }; + request.onload = function(e) { + var data; + try { + data = JSON.parse(request.responseText); + } catch( _g ) { + haxe_Log.trace(haxe_Exception.caught(_g),{ fileName : "src/client/FileUploader.hx", lineNumber : 61, className : "client.FileUploader", methodName : "uploadFullFile"}); + return; + } + if(data.errorId == null) { + return; + } + _gthis.main.serverMessage(data.info,true,false); + }; + request.onloadend = function() { + return haxe_Timer.delay(function() { + _gthis.main.hideDynamicChin(); + },500); + }; + request.send(file); + } + ,uploadLastChunk: function(file,name,callback) { + var a = file.size - 5242880; + var lastChunk = file.slice(a < 0 ? 0 : a); + var chunkReq = window.fetch("/upload-last-chunk",{ method : "POST", headers : { "content-name" : name}, body : lastChunk}); + chunkReq.then(function(e) { + return e.json().then(function(data) { + callback(data); + }); + }); + } +}; var client_InputWithHistory = function(element,history,maxItems,onEnter) { this.historyId = -1; this.element = element; @@ -3721,9 +3737,6 @@ client_Utils.copyToClipboard = function(text) { client_Utils.matchedNum = function(ereg) { return ereg.r.m.length; }; -client_Utils.browseFile = function(onFileLoad) { - client_Utils.browseFileImpl(onFileLoad,true,false); -}; client_Utils.browseFileUrl = function(onFileLoad,revoke) { if(revoke == null) { revoke = false; @@ -3770,6 +3783,25 @@ client_Utils.browseFileImpl = function(onFileLoad,isBinary,revokeAfterLoad) { window.document.body.appendChild(input); input.click(); }; +client_Utils.browseJsFile = function(onFileSelected) { + var input = window.document.createElement("input"); + input.style.visibility = "hidden"; + input.type = "file"; + input.id = "browse"; + input.onclick = function(e) { + e.cancelBubble = true; + return e.stopPropagation(); + }; + input.onchange = function(e) { + var tmp = input.files[0]; + if(tmp == null) { + return; + } + onFileSelected(tmp); + }; + window.document.body.appendChild(input); + input.click(); +}; client_Utils.saveFile = function(name,mime,data) { var url = URL.createObjectURL(new Blob([data],{ type : mime})); var a = window.document.createElement("a"); @@ -5879,14 +5911,6 @@ js_Browser.createXMLHttpRequest = function() { }; var js_hlsjs_HlsConfig = function() { }; js_hlsjs_HlsConfig.__name__ = true; -var js_lib__$ArrayBuffer_ArrayBufferCompat = function() { }; -js_lib__$ArrayBuffer_ArrayBufferCompat.__name__ = true; -js_lib__$ArrayBuffer_ArrayBufferCompat.sliceImpl = function(begin,end) { - var u = new Uint8Array(this,begin,end == null ? null : end - begin); - var resultArray = new Uint8Array(u.byteLength); - resultArray.set(u); - return resultArray.buffer; -}; var js_youtube_Youtube = function() { }; js_youtube_Youtube.__name__ = true; js_youtube_Youtube.init = function(onAPIReady) { @@ -5947,9 +5971,6 @@ String.__name__ = true; Array.__name__ = true; Date.__name__ = "Date"; js_Boot.__toStr = ({ }).toString; -if(ArrayBuffer.prototype.slice == null) { - ArrayBuffer.prototype.slice = js_lib__$ArrayBuffer_ArrayBufferCompat.sliceImpl; -} Lang.langs = new haxe_ds_StringMap(); Lang.ids = ["en","ru"]; Lang.lang = HxOverrides.substr($global.navigator.language,0,2).toLowerCase(); diff --git a/src/client/Buttons.hx b/src/client/Buttons.hx index 78b1c5a..56f28d5 100644 --- a/src/client/Buttons.hx +++ b/src/client/Buttons.hx @@ -1,20 +1,15 @@ package client; -import Types.UploadResponse; import client.Main.getEl; -import haxe.Json; import haxe.Timer; 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; @@ -263,69 +258,9 @@ class Buttons { } getEl("#mediaurl-upload").onclick = e -> { - Utils.browseFile((buffer, name) -> { - name ??= ""; - name = ~/[?#%\/\\]/g.replace(name, "").trim(); - if (name.length == 0) name = "video"; - name = (window : Dynamic).encodeURIComponent(name); - - // send last chunk separately to allow server file streaming while uploading - final chunkSize = 1024 * 1024 * 5; // 5 MB - final bufferOffset = (buffer.byteLength - chunkSize).limitMin(0); - final lastChunk = buffer.slice(bufferOffset); - final chunkReq = window.fetch("/upload-last-chunk", { - method: "POST", - headers: { - "content-name": name, - }, - body: lastChunk, - }); - chunkReq.then(e -> { - e.json().then((data:UploadResponse) -> { - 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.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 - } - }); - } - - 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); - } - - request.send(new Blob([buffer])); + Utils.browseJsFile(file -> { + final uploader = new FileUploader(main); + uploader.uploadFile(file); }); } diff --git a/src/client/FileUploader.hx b/src/client/FileUploader.hx new file mode 100644 index 0000000..60cc1d2 --- /dev/null +++ b/src/client/FileUploader.hx @@ -0,0 +1,93 @@ +package client; + +import Types.UploadResponse; +import client.Main.getEl; +import haxe.Json; +import haxe.Timer; +import js.Browser.window; +import js.html.File; +import js.html.InputElement; +import js.html.ProgressEvent; +import js.html.XMLHttpRequest; + +class FileUploader { + final main:Main; + + public function new(main:Main) { + this.main = main; + } + + public function uploadFile(file:File):Void { + var name = ~/[?#%\/\\]/g.replace(file.name, "").trim(); + if (name.length == 0) name = "video"; + name = (window : Dynamic).encodeURIComponent(name); + + // send last chunk separately to allow server file streaming while uploading + uploadLastChunk(file, name, data -> { + if (data.errorId != null) { + main.serverMessage(data.info, true, false); + return; + } + final input:InputElement = getEl("#mediaurl"); + input.value = data.url; + + uploadFullFile(name, file); + }); + } + + function uploadFullFile(name:String, file:File):Void { + final request = new XMLHttpRequest(); + request.open("POST", "/upload", true); + request.setRequestHeader("content-name", name); + + 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 + } + }); + } + + 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); + } + + request.send(file); + } + + function uploadLastChunk(file:File, name:String, callback:(data:UploadResponse) -> Void):Void { + final chunkSize = 1024 * 1024 * 5; // 5 MB + final bufferOffset = (file.size - chunkSize).limitMin(0); + final lastChunk = file.slice(bufferOffset); + final chunkReq = window.fetch("/upload-last-chunk", { + method: "POST", + headers: { + "content-name": name, + }, + body: lastChunk, + }); + chunkReq.then(e -> { + e.json().then((data:UploadResponse) -> { + callback(data); + }); + }); + } +} diff --git a/src/client/Utils.hx b/src/client/Utils.hx index 2234a1b..54025aa 100644 --- a/src/client/Utils.hx +++ b/src/client/Utils.hx @@ -6,6 +6,7 @@ import js.Browser.navigator; import js.Browser.window; import js.html.Blob; import js.html.Element; +import js.html.File; import js.html.FileReader; import js.html.URL; import js.html.audio.AudioContext; @@ -181,6 +182,26 @@ class Utils { input.click(); } + /** Don't extract data for bigger files. **/ + public static function browseJsFile( + onFileSelected:(file:File) -> Void + ):Void { + final input = document.createInputElement(); + input.style.visibility = "hidden"; + input.type = "file"; + input.id = "browse"; + input.onclick = e -> { + e.cancelBubble = true; + e.stopPropagation(); + } + input.onchange = e -> { + final file = input.files[0] ?? return; + onFileSelected(file); + } + document.body.appendChild(input); + input.click(); + } + public static function saveFile(name:String, mime:Mime, data:String):Void { final blob = new Blob([data], { type: mime @@ -1,15 +1,14 @@ --library hxnodejs --library hxnodejs-ws --library json2object:git:https://github.com/RblSb/json2object.git#nightly_safe_macros ---library ytdlp-nodejs:git:https://github.com/RblSb/ytdlp-nodejs-externs.git +--library ytdlp-nodejs:git:https://github.com/haxe-externs/ytdlp-nodejs-externs.git # Client libs for completion ---library youtubeIFramePlayer:git:https://github.com/okawa-h/youtubeIFramePlayer-externs.git +--library youtubeIFramePlayer:git:https://github.com/haxe-externs/youtubeIFramePlayer-externs.git --library hls.js-extern:git:https://github.com/zoldesi-andor/hls.js-haxe-extern.git --library utest --class-path src --class-path test --main Main --w -WDeprecated # -D UTEST_PATTERN=testMain --js build/tests.js --cmd node build/tests.js |
