diff options
| -rw-r--r-- | build/server.js | 33 | ||||
| -rw-r--r-- | res/client.js | 68 | ||||
| -rw-r--r-- | src/Types.hx | 30 | ||||
| -rw-r--r-- | src/VideoList.hx | 4 | ||||
| -rw-r--r-- | src/client/JsApi.hx | 4 | ||||
| -rw-r--r-- | src/client/Player.hx | 37 | ||||
| -rw-r--r-- | src/client/players/Youtube.hx | 5 | ||||
| -rw-r--r-- | src/server/Main.hx | 10 |
8 files changed, 128 insertions, 63 deletions
diff --git a/build/server.js b/build/server.js index 301f7d7..c29204f 100644 --- a/build/server.js +++ b/build/server.js @@ -456,6 +456,22 @@ json2object_reader_BaseParser.prototype = { } return defaultValue; } + ,loadObjectFieldReflect: function(loadJsonFn,field,name,assigned,pos) { + try { + this.value[name] = loadJsonFn(field.value,field.name); + this.mapSet(assigned,name,true); + } catch( _g ) { + var _g1 = haxe_Exception.caught(_g).unwrap(); + if(js_Boot.__instanceof(_g1,json2object_InternalError)) { + var e = _g1; + if(e != json2object_InternalError.ParsingThrow) { + throw haxe_Exception.thrown(e); + } + } else { + this.errors.push(json2object_Error.CustomFunctionException(_g1,pos)); + } + } + } ,objectSetupAssign: function(assigned,keys,values) { var _g = 0; var _g1 = keys.length; @@ -1332,7 +1348,7 @@ JsonParser_$43.prototype = $extend(json2object_reader_BaseParser.prototype,{ this.value.title = this.loadObjectField(($_=new JsonParser_$44(this.errors,this.putils,1),$bind($_,$_.loadJson)),field,"title",assigned,this.value.title,pos); break; case "url": - this.value.url = this.loadObjectField(($_=new JsonParser_$44(this.errors,this.putils,1),$bind($_,$_.loadJson)),field,"url",assigned,this.value.url,pos); + this.loadObjectFieldReflect(($_=new JsonParser_$44(this.errors,this.putils,1),$bind($_,$_.loadJson)),field,"url",assigned,pos); break; default: this.errors.push(json2object_Error.UnknownVariable(field.name,this.putils.convertPosition(field.namePos))); @@ -2768,6 +2784,11 @@ StringTools.hex = function(n,digits) { } return s; }; +var _$Types_VideoItemTools = function() { }; +_$Types_VideoItemTools.__name__ = true; +_$Types_VideoItemTools.withUrl = function(item,url) { + return { url : url, title : item.title, author : item.author, duration : item.duration, subs : item.subs, isTemp : item.isTemp, isIframe : item.isIframe}; +}; var VideoList = function() { this.items = []; this.isOpen = true; @@ -4913,9 +4934,10 @@ server_Main.prototype = { } var item = data.addVideo.item; item.author = client.name; - var local = "" + this.localIp + ":" + this.port; - if(item.url.indexOf(local) != -1) { - item.url = StringTools.replace(item.url,local,"" + this.globalIp + ":" + this.port); + var localIpPort = "" + this.localIp + ":" + this.port; + if(item.url.indexOf(localIpPort) != -1) { + var newUrl = StringTools.replace(item.url,localIpPort,"" + this.globalIp + ":" + this.port); + item = _$Types_VideoItemTools.withUrl(item,newUrl); } if(this.videoList.exists(function(i) { return i.url == item.url; @@ -4923,6 +4945,7 @@ server_Main.prototype = { this.serverMessage(client,"videoAlreadyExistsError"); return; } + data.addVideo.item = item; this.videoList.addItem(item,data.addVideo.atEnd); this.broadcast(data); if(this.videoList.items.length == 1) { @@ -5461,7 +5484,7 @@ server_Main.prototype = { client.setGroupFlag(ClientGroup.Banned,!isOutdated); if(isOutdated) { HxOverrides.remove(this.userList.bans,ban); - haxe_Log.trace("" + client.name + " ban removed",{ fileName : "src/server/Main.hx", lineNumber : 971, className : "server.Main", methodName : "checkBan"}); + haxe_Log.trace("" + client.name + " ban removed",{ fileName : "src/server/Main.hx", lineNumber : 973, className : "server.Main", methodName : "checkBan"}); this.sendClientList(); } break; diff --git a/res/client.js b/res/client.js index 48bf37c..35ed305 100644 --- a/res/client.js +++ b/res/client.js @@ -481,6 +481,11 @@ StringTools.hex = function(n,digits) { } return s; }; +var _$Types_VideoItemTools = function() { }; +_$Types_VideoItemTools.__name__ = true; +_$Types_VideoItemTools.withUrl = function(item,url) { + return { url : url, title : item.title, author : item.author, duration : item.duration, subs : item.subs, isTemp : item.isTemp, isIframe : item.isIframe}; +}; var VideoList = function() { this.items = []; this.pos = 0; @@ -1186,8 +1191,8 @@ client_JsApi.isLeader = $hx_exports["client"]["JsApi"]["isLeader"] = function() client_JsApi.forceSyncNextTick = $hx_exports["client"]["JsApi"]["forceSyncNextTick"] = function(flag) { client_JsApi.main.forceSyncNextTick = flag; }; -client_JsApi.setVideoSrc = $hx_exports["client"]["JsApi"]["setVideoSrc"] = function(src) { - client_JsApi.player.changeVideoSrc(src); +client_JsApi.setVideoSrc = $hx_exports["client"]["JsApi"]["setVideoSrc"] = function(url) { + client_JsApi.player.changeVideoSrc(url); }; client_JsApi.getLocalIp = $hx_exports["client"]["JsApi"]["getLocalIp"] = function() { return client_JsApi.main.host; @@ -2412,16 +2417,7 @@ client_Player.prototype = { return; } var item = this.videoList.items[i]; - var currentPlayer = Lambda.find(this.players,function(p) { - return p.isSupportedLink(item.url); - }); - if(currentPlayer != null) { - this.setPlayer(currentPlayer); - } else if(item.isIframe) { - this.setPlayer(this.iframePlayer); - } else { - this.setPlayer(this.rawPlayer); - } + this.setSupportedPlayer(item.url,item.isIframe); this.removeActiveLabel(this.videoList.pos); this.videoList.setPos(i); this.addActiveLabel(this.videoList.pos); @@ -2434,11 +2430,20 @@ client_Player.prototype = { client_JsApi.fireVideoChangeEvents(item); window.document.querySelector("#currenttitle").textContent = item.title; } - ,changeVideoSrc: function(src) { - if(!this.main.isVideoEnabled) { - return; + ,setSupportedPlayer: function(url,isIframe) { + var currentPlayer = Lambda.find(this.players,function(p) { + return p.isSupportedLink(url); + }); + if(currentPlayer != null) { + this.setPlayer(currentPlayer); + } else if(isIframe) { + this.setPlayer(this.iframePlayer); + } else { + this.setPlayer(this.rawPlayer); } - if(this.player == null) { + } + ,changeVideoSrc: function(url) { + if(!this.main.isVideoEnabled) { return; } var _this = this.videoList; @@ -2446,7 +2451,8 @@ client_Player.prototype = { if(tmp == null) { return; } - this.player.loadVideo({ url : src, title : tmp.title, author : tmp.author, duration : tmp.duration, subs : tmp.subs, isTemp : tmp.isTemp, isIframe : tmp.isIframe}); + this.setSupportedPlayer(url,tmp.isIframe); + this.player.loadVideo(_$Types_VideoItemTools.withUrl(tmp,url)); } ,removeVideo: function() { var _this = this.videoList; @@ -2485,6 +2491,19 @@ client_Player.prototype = { } ,onPause: function() { var _gthis = this; + var _this = this.videoList; + var tmp = _this.items[_this.pos]; + if(tmp == null) { + return; + } + if(this.getTime() >= tmp.duration - 0.01) { + return; + } + if(this.player == this.rawPlayer && this.youtube.isSupportedLink(tmp.url)) { + if(this.getTime() >= tmp.duration - 1) { + return; + } + } if(this.main.hasLeaderOnPauseRequest() && this.videoList.items.length > 0 && this.getTime() > 1 && !this.main.hasLeader()) { client_JsApi.once("SetLeader",function(event) { if(event.setLeader.clientName != _gthis.main.personal.name) { @@ -2810,7 +2829,7 @@ client_Player.prototype = { } }; http.onError = function(msg) { - haxe_Log.trace(msg,{ fileName : "src/client/Player.hx", lineNumber : 482, className : "client.Player", methodName : "skipAd"}); + haxe_Log.trace(msg,{ fileName : "src/client/Player.hx", lineNumber : 485, className : "client.Player", methodName : "skipAd"}); }; http.request(); } @@ -3693,7 +3712,11 @@ client_players_Youtube.prototype = { _gthis.player.onRateChange(); }, onError : function(e) { haxe_Log.trace("Error " + e.data,{ fileName : "src/client/players/Youtube.hx", lineNumber : 245, className : "client.players.Youtube", methodName : "loadVideo"}); - _gthis.rawSourceFallback(item.url); + var tmp = _gthis.player.getCurrentItem(); + if(tmp == null) { + return; + } + _gthis.rawSourceFallback(tmp.url); }}}); } ,rawSourceFallback: function(url) { @@ -3702,12 +3725,11 @@ client_players_Youtube.prototype = { var info = event.getYoutubeVideoInfo.response; var tmp = _gthis.getBestStreamFormat(info); if(tmp == null) { - haxe_Log.trace("format not found in response info:",{ fileName : "src/client/players/Youtube.hx", lineNumber : 257, className : "client.players.Youtube", methodName : "rawSourceFallback"}); - haxe_Log.trace(info,{ fileName : "src/client/players/Youtube.hx", lineNumber : 258, className : "client.players.Youtube", methodName : "rawSourceFallback"}); + haxe_Log.trace("format not found in response info:",{ fileName : "src/client/players/Youtube.hx", lineNumber : 258, className : "client.players.Youtube", methodName : "rawSourceFallback"}); + haxe_Log.trace(info,{ fileName : "src/client/players/Youtube.hx", lineNumber : 259, className : "client.players.Youtube", methodName : "rawSourceFallback"}); return; } - _gthis.player.getCurrentItem().url = tmp.url; - _gthis.player.refresh(); + _gthis.player.changeVideoSrc(tmp.url); }); this.main.send({ type : "GetYoutubeVideoInfo", getYoutubeVideoInfo : { url : url}}); } diff --git a/src/Types.hx b/src/Types.hx index eeae641..27b2cce 100644 --- a/src/Types.hx +++ b/src/Types.hx @@ -98,14 +98,30 @@ typedef Message = { time:String } +@:using(Types.VideoItemTools) typedef VideoItem = { - url:String, - title:String, - author:String, - duration:Float, - ?subs:String, - isTemp:Bool, - isIframe:Bool + /** Immutable, used as identifier for skipping / removing items **/ + final url:String; + var title:String; + var author:String; + var duration:Float; + var ?subs:String; + var isTemp:Bool; + var isIframe:Bool; +} + +private class VideoItemTools { + public static function withUrl(item:VideoItem, url:String):VideoItem { + return { + url: url, + title: item.title, + author: item.author, + duration: item.duration, + subs: item.subs, + isTemp: item.isTemp, + isIframe: item.isIframe + }; + } } typedef FlashbackItem = { diff --git a/src/VideoList.hx b/src/VideoList.hx index 094d2ab..b677060 100644 --- a/src/VideoList.hx +++ b/src/VideoList.hx @@ -17,13 +17,13 @@ class VideoList { return items.length; } - public var currentItem(get, never):VideoItem; + public var currentItem(get, never):Null<VideoItem>; inline function get_currentItem():Null<VideoItem> { return items[pos]; } - public inline function getItem(i:Int):VideoItem { + public inline function getItem(i:Int):Null<VideoItem> { return items[i]; } diff --git a/src/client/JsApi.hx b/src/client/JsApi.hx index 637878d..09e6edb 100644 --- a/src/client/JsApi.hx +++ b/src/client/JsApi.hx @@ -104,8 +104,8 @@ class JsApi { } @:expose - public static function setVideoSrc(src:String):Void { - player.changeVideoSrc(src); + public static function setVideoSrc(url:String):Void { + player.changeVideoSrc(url); } /** Returns current page hostname (domain without protocol) **/ diff --git a/src/client/Player.hx b/src/client/Player.hx index 06a8f3e..c250a34 100644 --- a/src/client/Player.hx +++ b/src/client/Player.hx @@ -89,7 +89,7 @@ class Player { setItemElementType(el, videoList.getItem(pos).isTemp); } - public function getCurrentItem():VideoItem { + public function getCurrentItem():Null<VideoItem> { return videoList.currentItem; } @@ -121,10 +121,7 @@ class Player { public function setVideo(i:Int):Void { if (!main.isSyncActive) return; final item = videoList.getItem(i); - var currentPlayer = players.find(p -> p.isSupportedLink(item.url)); - if (currentPlayer != null) setPlayer(currentPlayer); - else if (item.isIframe) setPlayer(iframePlayer); - else setPlayer(rawPlayer); + setSupportedPlayer(item.url, item.isIframe); removeActiveLabel(videoList.pos); videoList.setPos(i); @@ -140,19 +137,18 @@ class Player { ge("#currenttitle").textContent = item.title; } - public function changeVideoSrc(src:String):Void { + function setSupportedPlayer(url:String, isIframe:Bool):Void { + final currentPlayer = players.find(p -> p.isSupportedLink(url)); + if (currentPlayer != null) setPlayer(currentPlayer); + else if (isIframe) setPlayer(iframePlayer); + else setPlayer(rawPlayer); + } + + public function changeVideoSrc(url:String):Void { if (!main.isVideoEnabled) return; - if (player == null) return; - final item = videoList.currentItem ?? return; - player.loadVideo({ - url: src, - title: item.title, - author: item.author, - duration: item.duration, - subs: item.subs, - isTemp: item.isTemp, - isIframe: item.isIframe - }); + final item:VideoItem = videoList.currentItem ?? return; + setSupportedPlayer(url, item.isIframe); + player.loadVideo(item.withUrl(url)); } public function removeVideo():Void { @@ -191,6 +187,13 @@ class Player { } public function onPause():Void { + final item = videoList.currentItem ?? return; + // do not send pause if video is ended + if (getTime() >= item.duration - 0.01) return; + // youtube raw fallback has around one second difference from rounded youtube duration + if (player == rawPlayer && youtube.isSupportedLink(item.url)) { + if (getTime() >= item.duration - 1) return; + } final hasAutoPause = main.hasLeaderOnPauseRequest() && videoList.length > 0 && getTime() > 1; if (hasAutoPause && !main.hasLeader()) { diff --git a/src/client/players/Youtube.hx b/src/client/players/Youtube.hx index 5308b63..7c98b3f 100644 --- a/src/client/players/Youtube.hx +++ b/src/client/players/Youtube.hx @@ -243,6 +243,7 @@ class Youtube implements IPlayer { onError: e -> { // TODO message error codes trace('Error ${e.data}'); + final item = player.getCurrentItem() ?? return; rawSourceFallback(item.url); } } @@ -258,9 +259,7 @@ class Youtube implements IPlayer { trace(info); return; }; - final item = player.getCurrentItem(); - item.url = format.url; - player.refresh(); + player.changeVideoSrc(format.url); }); main.send({ type: GetYoutubeVideoInfo, diff --git a/src/server/Main.hx b/src/server/Main.hx index e7c38a6..4f09108 100644 --- a/src/server/Main.hx +++ b/src/server/Main.hx @@ -612,16 +612,18 @@ class Main { if (!data.addVideo.atEnd && !checkPermission(client, ChangeOrderPerm)) { data.addVideo.atEnd = true; } - final item = data.addVideo.item; + var item = data.addVideo.item; item.author = client.name; - final local = '$localIp:$port'; - if (item.url.contains(local)) { - item.url = item.url.replace(local, '$globalIp:$port'); + final localIpPort = '$localIp:$port'; + if (item.url.contains(localIpPort)) { + final newUrl = item.url.replace(localIpPort, '$globalIp:$port'); + item = item.withUrl(newUrl); } if (videoList.exists(i -> i.url == item.url)) { serverMessage(client, "videoAlreadyExistsError"); return; } + data.addVideo.item = item; videoList.addItem(item, data.addVideo.atEnd); broadcast(data); // Initial timer start if VideoLoaded is not happen |
