diff options
| -rw-r--r-- | build/server.js | 127 | ||||
| -rw-r--r-- | res/client.js | 6 | ||||
| -rw-r--r-- | src/Types.hx | 6 | ||||
| -rw-r--r-- | src/VideoList.hx | 4 | ||||
| -rw-r--r-- | src/client/Main.hx | 6 | ||||
| -rw-r--r-- | src/client/Player.hx | 19 | ||||
| -rw-r--r-- | src/server/HttpServer.hx | 7 | ||||
| -rw-r--r-- | src/server/Main.hx | 79 |
8 files changed, 183 insertions, 71 deletions
diff --git a/build/server.js b/build/server.js index b5b2902..c4fd7c8 100644 --- a/build/server.js +++ b/build/server.js @@ -3784,7 +3784,7 @@ server_HttpServer.serveMedia = function(req,res,filePath) { return true; }; server_HttpServer.isMediaExtension = function(ext) { - if(!(ext == "mp4" || ext == "mp3")) { + if(!(ext == "mp4" || ext == "webm" || ext == "mp3")) { return ext == "wav"; } else { return true; @@ -3968,7 +3968,7 @@ server_Logger.prototype = { ,__class__: server_Logger }; var server_Main = function(opts) { - this.flashbackTime = 0.0; + this.flashbackTimes = []; this.loadedClientsCount = 0; this.matchGuestName = new EReg("guest [0-9]+",""); this.matchHtmlChars = new EReg("[&^<>'\"]",""); @@ -4030,7 +4030,7 @@ var server_Main = function(opts) { preparePort = function() { server_Utils.isPortFree(_gthis.port,function(isFree) { if(!isFree && attempts > 0) { - haxe_Log.trace("Warning: port " + _gthis.port + " is already in use. Changed to " + (_gthis.port + 1),{ fileName : "src/server/Main.hx", lineNumber : 111, className : "server.Main", methodName : "new"}); + haxe_Log.trace("Warning: port " + _gthis.port + " is already in use. Changed to " + (_gthis.port + 1),{ fileName : "src/server/Main.hx", lineNumber : 113, className : "server.Main", methodName : "new"}); attempts -= 1; _gthis.port++; preparePort(); @@ -4048,13 +4048,13 @@ server_Main.main = function() { server_Main.prototype = { runServer: function() { var _gthis = this; - haxe_Log.trace("Local: http://" + this.localIp + ":" + this.port,{ fileName : "src/server/Main.hx", lineNumber : 124, className : "server.Main", methodName : "runServer"}); + haxe_Log.trace("Local: http://" + this.localIp + ":" + this.port,{ fileName : "src/server/Main.hx", lineNumber : 126, className : "server.Main", methodName : "runServer"}); if(this.config.localNetworkOnly) { - haxe_Log.trace("Global network is disabled in config",{ fileName : "src/server/Main.hx", lineNumber : 126, className : "server.Main", methodName : "runServer"}); + haxe_Log.trace("Global network is disabled in config",{ fileName : "src/server/Main.hx", lineNumber : 128, className : "server.Main", methodName : "runServer"}); } else if(!this.isNoState) { server_Utils.getGlobalIp(function(ip) { _gthis.globalIp = ip; - haxe_Log.trace("Global: http://" + _gthis.globalIp + ":" + _gthis.port,{ fileName : "src/server/Main.hx", lineNumber : 130, className : "server.Main", methodName : "runServer"}); + haxe_Log.trace("Global: http://" + _gthis.globalIp + ":" + _gthis.port,{ fileName : "src/server/Main.hx", lineNumber : 132, className : "server.Main", methodName : "runServer"}); }); } var dir = "" + this.rootDir + "/res"; @@ -4139,7 +4139,7 @@ server_Main.prototype = { var field = _g1[_g]; ++_g; if(Reflect.field(config,field) == null) { - haxe_Log.trace("Warning: config field \"" + field + "\" is unknown",{ fileName : "src/server/Main.hx", lineNumber : 199, className : "server.Main", methodName : "getUserConfig"}); + haxe_Log.trace("Warning: config field \"" + field + "\" is unknown",{ fileName : "src/server/Main.hx", lineNumber : 201, className : "server.Main", methodName : "getUserConfig"}); } config[field] = Reflect.field(customConfig,field); } @@ -4150,14 +4150,14 @@ server_Main.prototype = { var emote = _g1[_g]; ++_g; if(emoteCopies_h[emote.name]) { - haxe_Log.trace("Warning: emote name \"" + emote.name + "\" has copy",{ fileName : "src/server/Main.hx", lineNumber : 205, className : "server.Main", methodName : "getUserConfig"}); + haxe_Log.trace("Warning: emote name \"" + emote.name + "\" has copy",{ fileName : "src/server/Main.hx", lineNumber : 207, className : "server.Main", methodName : "getUserConfig"}); } emoteCopies_h[emote.name] = true; if(!this.verbose) { continue; } if(emoteCopies_h[emote.image]) { - haxe_Log.trace("Warning: emote url of name \"" + emote.name + "\" has copy",{ fileName : "src/server/Main.hx", lineNumber : 209, className : "server.Main", methodName : "getUserConfig"}); + haxe_Log.trace("Warning: emote url of name \"" + emote.name + "\" has copy",{ fileName : "src/server/Main.hx", lineNumber : 211, className : "server.Main", methodName : "getUserConfig"}); } emoteCopies_h[emote.image] = true; } @@ -4195,7 +4195,7 @@ server_Main.prototype = { js_node_Fs.writeFileSync("" + folder + "/users.json",JSON.stringify({ admins : users1, bans : _g, salt : users.salt},null,"\t")); } ,saveState: function() { - haxe_Log.trace("Saving state...",{ fileName : "src/server/Main.hx", lineNumber : 248, className : "server.Main", methodName : "saveState"}); + haxe_Log.trace("Saving state...",{ fileName : "src/server/Main.hx", lineNumber : 250, className : "server.Main", methodName : "saveState"}); var json = JSON.stringify(this.getCurrentState(),null,"\t"); js_node_Fs.writeFileSync(this.statePath,json); this.writeUsers(this.userList); @@ -4210,7 +4210,7 @@ server_Main.prototype = { if(!sys_FileSystem.exists(this.statePath)) { return; } - haxe_Log.trace("Loading state...",{ fileName : "src/server/Main.hx", lineNumber : 270, className : "server.Main", methodName : "loadState"}); + haxe_Log.trace("Loading state...",{ fileName : "src/server/Main.hx", lineNumber : 272, className : "server.Main", methodName : "loadState"}); var data = JSON.parse(js_node_Fs.readFileSync(this.statePath,{ encoding : "utf8"})); this.videoList.setItems(data.videoList); this.messages.length = 0; @@ -4224,7 +4224,7 @@ server_Main.prototype = { this.videoTimer.pause(); } ,logError: function(type,data) { - haxe_Log.trace(type,{ fileName : "src/server/Main.hx", lineNumber : 285, className : "server.Main", methodName : "logError", customParams : [data]}); + haxe_Log.trace(type,{ fileName : "src/server/Main.hx", lineNumber : 287, className : "server.Main", methodName : "logError", customParams : [data]}); var crashesFolder = "" + this.rootDir + "/user/crashes"; server_Utils.ensureDir(crashesFolder); var name = DateTools.format(new Date(),"%Y-%m-%d_%H_%M_%S") + "-" + type; @@ -4242,7 +4242,7 @@ server_Main.prototype = { if(_gthis.clients.length == 0) { return; } - haxe_Log.trace("Ping " + url,{ fileName : "src/server/Main.hx", lineNumber : 302, className : "server.Main", methodName : "initIntergationHandlers"}); + haxe_Log.trace("Ping " + url,{ fileName : "src/server/Main.hx", lineNumber : 304, className : "server.Main", methodName : "initIntergationHandlers"}); js_node_Http.get(url,null,function(r) { }); }; @@ -4262,13 +4262,13 @@ server_Main.prototype = { password += this.config.salt; var hash = haxe_crypto_Sha256.encode(password); this.userList.admins.push({ name : name, hash : hash}); - haxe_Log.trace("Admin " + name + " added.",{ fileName : "src/server/Main.hx", lineNumber : 325, className : "server.Main", methodName : "addAdmin"}); + haxe_Log.trace("Admin " + name + " added.",{ fileName : "src/server/Main.hx", lineNumber : 327, className : "server.Main", methodName : "addAdmin"}); } ,removeAdmin: function(name) { HxOverrides.remove(this.userList.admins,Lambda.find(this.userList.admins,function(item) { return item.name == name; })); - haxe_Log.trace("Admin " + name + " removed.",{ fileName : "src/server/Main.hx", lineNumber : 332, className : "server.Main", methodName : "removeAdmin"}); + haxe_Log.trace("Admin " + name + " removed.",{ fileName : "src/server/Main.hx", lineNumber : 334, className : "server.Main", methodName : "removeAdmin"}); } ,replayLog: function(events) { var _gthis = this; @@ -4312,7 +4312,7 @@ server_Main.prototype = { var ip = this.clientIp(req); var id = this.freeIds.length > 0 ? this.freeIds.shift() : this.clients.length; var name = "Guest " + (id + 1); - haxe_Log.trace(HxOverrides.dateStr(new Date()),{ fileName : "src/server/Main.hx", lineNumber : 370, className : "server.Main", methodName : "onConnect", customParams : ["" + name + " connected (" + ip + ")"]}); + haxe_Log.trace(HxOverrides.dateStr(new Date()),{ fileName : "src/server/Main.hx", lineNumber : 372, className : "server.Main", methodName : "onConnect", customParams : ["" + name + " connected (" + ip + ")"]}); var isAdmin = this.config.localAdmins && req.socket.localAddress == ip; var client = new Client(ws,req,id,name,0); client.setGroupFlag(ClientGroup.Admin,isAdmin); @@ -4325,7 +4325,7 @@ server_Main.prototype = { var obj = _gthis.wsEventParser.fromJson(data.toString()); if(_gthis.wsEventParser.errors.length > 0 || _gthis.noTypeObj(obj)) { var errors = "" + ("Wrong request for type \"" + obj.type + "\":") + "\n" + json2object_ErrorUtils.convertErrorArray(_gthis.wsEventParser.errors); - haxe_Log.trace(errors,{ fileName : "src/server/Main.hx", lineNumber : 386, className : "server.Main", methodName : "onConnect"}); + haxe_Log.trace(errors,{ fileName : "src/server/Main.hx", lineNumber : 388, className : "server.Main", methodName : "onConnect"}); _gthis.serverMessage(client,errors); return; } @@ -4443,6 +4443,10 @@ server_Main.prototype = { if(!this.checkPermission(client,"removeVideo")) { return; } + if(this.videoTimer.getTime() > 30) { + var _this = this.videoList; + this.saveFlashbackTime(_this.items[_this.pos]); + } this.videoTimer.stop(); var _this = this.videoList; _this.items.length = 0; @@ -4466,7 +4470,7 @@ server_Main.prototype = { if(!internal) { return; } - haxe_Log.trace(HxOverrides.dateStr(new Date()),{ fileName : "src/server/Main.hx", lineNumber : 446, className : "server.Main", methodName : "onMessage", customParams : ["Client " + client.name + " disconnected"]}); + haxe_Log.trace(HxOverrides.dateStr(new Date()),{ fileName : "src/server/Main.hx", lineNumber : 448, className : "server.Main", methodName : "onMessage", customParams : ["Client " + client.name + " disconnected"]}); server_Utils.sortedPush(this.freeIds,client.id); HxOverrides.remove(this.clients,client); this.sendClientList(); @@ -4514,7 +4518,8 @@ server_Main.prototype = { if(this.videoList.items.length == 0) { return; } - this.loadFlashbackTime(); + var _this = this.videoList; + this.loadFlashbackTime(_this.items[_this.pos]); this.broadcast({ type : "Rewind", rewind : { time : this.videoTimer.getTime()}}); break; case "GetTime": @@ -4590,7 +4595,7 @@ server_Main.prototype = { this.send(client,{ type : "LoginError"}); return; } - haxe_Log.trace(HxOverrides.dateStr(new Date()),{ fileName : "src/server/Main.hx", lineNumber : 533, className : "server.Main", methodName : "onMessage", customParams : ["Client " + client.name + " logged as " + name]}); + haxe_Log.trace(HxOverrides.dateStr(new Date()),{ fileName : "src/server/Main.hx", lineNumber : 535, className : "server.Main", methodName : "onMessage", customParams : ["Client " + client.name + " logged as " + name]}); client.name = name; client.setGroupFlag(ClientGroup.User,true); this.checkBan(client); @@ -4603,7 +4608,7 @@ server_Main.prototype = { var oldName = client.name; client.name = "Guest " + (this.clients.indexOf(client) + 1); client.setGroupFlag(ClientGroup.User,false); - haxe_Log.trace(HxOverrides.dateStr(new Date()),{ fileName : "src/server/Main.hx", lineNumber : 554, className : "server.Main", methodName : "onMessage", customParams : ["Client " + oldName + " logout to " + client.name]}); + haxe_Log.trace(HxOverrides.dateStr(new Date()),{ fileName : "src/server/Main.hx", lineNumber : 556, className : "server.Main", methodName : "onMessage", customParams : ["Client " + oldName + " logout to " + client.name]}); this.send(client,{ type : data.type, logout : { oldClientName : oldName, clientName : client.name, clients : this.clientList()}}); this.sendClientListExcept(client); break; @@ -4638,7 +4643,8 @@ server_Main.prototype = { return; } if(Math.abs(data.pause.time - this.videoTimer.getTime()) > 30) { - this.saveFlashbackTime(); + var _this = this.videoList; + this.saveFlashbackTime(_this.items[_this.pos]); } this.videoTimer.setTime(data.pause.time); this.videoTimer.pause(); @@ -4652,7 +4658,8 @@ server_Main.prototype = { return; } if(Math.abs(data.play.time - this.videoTimer.getTime()) > 30) { - this.saveFlashbackTime(); + var _this = this.videoList; + this.saveFlashbackTime(_this.items[_this.pos]); } this.videoTimer.setTime(data.play.time); this.videoTimer.play(); @@ -4662,6 +4669,10 @@ server_Main.prototype = { if(!this.checkPermission(client,"changeOrder")) { return; } + if(this.videoTimer.getTime() > 30) { + var _this = this.videoList; + this.saveFlashbackTime(_this.items[_this.pos]); + } this.videoList.setPos(data.playItem.pos); data.playItem.pos = this.videoList.pos; this.restartWaitTimer(); @@ -4686,6 +4697,10 @@ server_Main.prototype = { } var _this = this.videoList; var isCurrent = _this.items[_this.pos].url == url; + if(isCurrent && this.videoTimer.getTime() > 30) { + var _this = this.videoList; + this.saveFlashbackTime(_this.items[_this.pos]); + } this.videoList.removeItem(index); if(isCurrent && this.videoList.items.length > 0) { this.broadcast(data); @@ -4705,7 +4720,8 @@ server_Main.prototype = { if(data.rewind.time < 0) { data.rewind.time = 0; } - this.saveFlashbackTime(); + var _this = this.videoList; + this.saveFlashbackTime(_this.items[_this.pos]); this.videoTimer.setTime(data.rewind.time); this.broadcast({ type : data.type, rewind : data.rewind}); break; @@ -4767,7 +4783,8 @@ server_Main.prototype = { return; } if(Math.abs(data.setTime.time - this.videoTimer.getTime()) > 30) { - this.saveFlashbackTime(); + var _this = this.videoList; + this.saveFlashbackTime(_this.items[_this.pos]); } this.videoTimer.setTime(data.setTime.time); this.broadcastExcept(client,{ type : data.type, setTime : data.setTime}); @@ -4865,6 +4882,12 @@ server_Main.prototype = { if(_this.items[_this.pos].url != data.skipVideo.url) { return; } + var _this = this.videoList; + var dur = _this.items[_this.pos].duration; + if(this.videoTimer.getTime() > 30 && this.videoTimer.getTime() < dur - 30) { + var _this = this.videoList; + this.saveFlashbackTime(_this.items[_this.pos]); + } this.videoList.skipItem(); if(this.videoList.items.length > 0) { this.restartWaitTimer(); @@ -4900,7 +4923,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 : 939, className : "server.Main", methodName : "checkBan"}); + haxe_Log.trace("" + client.name + " ban removed",{ fileName : "src/server/Main.hx", lineNumber : 955, className : "server.Main", methodName : "checkBan"}); this.sendClientList(); } break; @@ -4927,9 +4950,6 @@ server_Main.prototype = { return false; } ,restartWaitTimer: function() { - if(this.videoTimer.getTime() > 30) { - this.saveFlashbackTime(); - } this.videoTimer.stop(); if(this.waitVideoStart != null) { this.waitVideoStart.stop(); @@ -4956,17 +4976,49 @@ server_Main.prototype = { this.broadcast({ type : "VideoLoaded"}); this.videoTimer.start(); } - ,saveFlashbackTime: function() { + ,saveFlashbackTime: function(item) { + var url = item.url; + var duration = item.duration; var time = this.videoTimer.getTime(); - if(Math.abs(this.flashbackTime - time) < 30) { + if(Math.abs(this.findFlashbackTime(url,duration) - time) < 30) { return; } - this.flashbackTime = time; + this.addRecentFlashback(url,duration,time); } - ,loadFlashbackTime: function() { + ,loadFlashbackTime: function(item) { + var url = item.url; + var duration = item.duration; var time = this.videoTimer.getTime(); - this.videoTimer.setTime(this.flashbackTime); - this.flashbackTime = time; + var flashbackTime = this.findFlashbackTime(url,duration); + this.videoTimer.setTime(flashbackTime); + this.addRecentFlashback(url,duration,time); + } + ,findFlashbackTime: function(url,duration) { + var tmp = this.findFlashbackItem(url,duration); + var tmp1 = tmp != null ? tmp.time : null; + if(tmp1 != null) { + return tmp1; + } else { + return 0.0; + } + } + ,findFlashbackItem: function(url,duration) { + var item = Lambda.find(this.flashbackTimes,function(item) { + return item.url == url; + }); + if(duration != null && item == null) { + item = Lambda.find(this.flashbackTimes,function(item) { + return item.duration == duration; + }); + } + return item; + } + ,addRecentFlashback: function(url,duration,time) { + HxOverrides.remove(this.flashbackTimes,this.findFlashbackItem(url)); + this.flashbackTimes.unshift({ url : url, duration : duration, time : time}); + if(Lambda.count(this.flashbackTimes) > 10) { + this.flashbackTimes.pop(); + } } ,isPlaylistLockedFor: function(client) { if(!this.videoList.isOpen) { @@ -5244,13 +5296,16 @@ server_HttpServer.mimeTypes = (function($this) { _g.h["css"] = "text/css"; _g.h["json"] = "application/json"; _g.h["png"] = "image/png"; - _g.h["jpg"] = "image/jpg"; + _g.h["jpg"] = "image/jpeg"; + _g.h["jpeg"] = "image/jpeg"; _g.h["gif"] = "image/gif"; + _g.h["webp"] = "image/webp"; _g.h["svg"] = "image/svg+xml"; _g.h["ico"] = "image/x-icon"; _g.h["wav"] = "audio/wav"; _g.h["mp3"] = "audio/mpeg"; _g.h["mp4"] = "video/mp4"; + _g.h["webm"] = "video/webm"; _g.h["woff"] = "application/font-woff"; _g.h["ttf"] = "application/font-ttf"; _g.h["eot"] = "application/vnd.ms-fontobject"; diff --git a/res/client.js b/res/client.js index 432ac20..beb88e3 100644 --- a/res/client.js +++ b/res/client.js @@ -1884,7 +1884,7 @@ client_Main.prototype = { while(_g < _g1.length) { var emote = _g1[_g]; ++_g; - var tag = StringTools.endsWith(emote.image,"mp4") ? "video autoplay=\"\" loop=\"\" muted=\"\"" : "img"; + var tag = StringTools.endsWith(emote.image,"mp4") || StringTools.endsWith(emote.image,"webm") ? "video autoplay=\"\" loop=\"\" muted=\"\"" : "img"; this.filters.push({ regex : new EReg("(^| )" + this.escapeRegExp(emote.name) + "(?!\\S)","g"), replace : "$1<" + tag + " class=\"channel-emote\" src=\"" + emote.image + "\" title=\"" + emote.name + "\"/>"}); } window.document.querySelector("#smilesbtn").classList.remove("active"); @@ -1905,7 +1905,7 @@ client_Main.prototype = { while(_g < _g1.length) { var emote = _g1[_g]; ++_g; - var tag = StringTools.endsWith(emote.image,"mp4") ? "video" : "img"; + var tag = StringTools.endsWith(emote.image,"mp4") || StringTools.endsWith(emote.image,"webm") ? "video" : "img"; var el = window.document.createElement(tag); el.className = "smile-preview"; el.dataset.src = emote.image; @@ -2737,7 +2737,7 @@ client_Player.prototype = { } }; http.onError = function(msg) { - haxe_Log.trace(msg,{ fileName : "src/client/Player.hx", lineNumber : 479, className : "client.Player", methodName : "skipAd"}); + haxe_Log.trace(msg,{ fileName : "src/client/Player.hx", lineNumber : 478, className : "client.Player", methodName : "skipAd"}); }; http.request(); } diff --git a/src/Types.hx b/src/Types.hx index fe0e6b2..4ef233b 100644 --- a/src/Types.hx +++ b/src/Types.hx @@ -107,6 +107,12 @@ typedef VideoItem = { isIframe:Bool } +typedef FlashbackItem = { + url:String, + duration:Float, + time:Float +} + typedef WsEvent = { type:WsEventType, ?connected:{ diff --git a/src/VideoList.hx b/src/VideoList.hx index 2ed1d8f..094d2ab 100644 --- a/src/VideoList.hx +++ b/src/VideoList.hx @@ -17,7 +17,9 @@ class VideoList { return items.length; } - public inline function getCurrentItem():VideoItem { + public var currentItem(get, never):VideoItem; + + inline function get_currentItem():Null<VideoItem> { return items[pos]; } diff --git a/src/client/Main.hx b/src/client/Main.hx index 69450d9..b1e0eb6 100644 --- a/src/client/Main.hx +++ b/src/client/Main.hx @@ -720,7 +720,8 @@ class Main { }); } for (emote in config.emotes) { - final tag = emote.image.endsWith("mp4") ? 'video autoplay="" loop="" muted=""' : "img"; + final isVideoExt = emote.image.endsWith("mp4") || emote.image.endsWith("webm"); + final tag = isVideoExt ? 'video autoplay="" loop="" muted=""' : "img"; filters.push({ regex: new EReg("(^| )" + escapeRegExp(emote.name) + "(?!\\S)", "g"), replace: '$1<$tag class="channel-emote" src="${emote.image}" title="${emote.name}"/>' @@ -739,7 +740,8 @@ class Main { } smilesList.textContent = ""; for (emote in config.emotes) { - final tag = emote.image.endsWith("mp4") ? "video" : "img"; + final isVideoExt = emote.image.endsWith("mp4") || emote.image.endsWith("webm"); + final tag = isVideoExt ? "video" : "img"; final el = document.createElement(tag); el.className = "smile-preview"; el.dataset.src = emote.image; diff --git a/src/client/Player.hx b/src/client/Player.hx index 6113c07..75b44b5 100644 --- a/src/client/Player.hx +++ b/src/client/Player.hx @@ -92,7 +92,7 @@ class Player { function setPlayer(newPlayer:IPlayer):Void { if (player != newPlayer) { if (player != null) { - JsApi.fireVideoRemoveEvents(videoList.getCurrentItem()); + JsApi.fireVideoRemoveEvents(videoList.currentItem); player.removeVideo(); } main.blinkTabWithTitle("*Video*"); @@ -139,7 +139,7 @@ class Player { public function changeVideoSrc(src:String):Void { if (!main.isVideoEnabled) return; if (player == null) return; - final item = videoList.getCurrentItem() ?? return; + final item = videoList.currentItem ?? return; player.loadVideo({ url: src, title: item.title, @@ -152,7 +152,7 @@ class Player { } public function removeVideo():Void { - JsApi.fireVideoRemoveEvents(videoList.getCurrentItem()); + JsApi.fireVideoRemoveEvents(videoList.currentItem); player.removeVideo(); ge("#currenttitle").textContent = Lang.get("nothingPlaying"); setPauseIndicator(true); @@ -278,7 +278,7 @@ class Player { var index = videoList.findIndex(item -> item.url == url); if (index == -1) return; - final isCurrent = videoList.getCurrentItem().url == url; + final isCurrent = videoList.currentItem.url == url; videoList.removeItem(index); updateCounters(); @@ -301,7 +301,7 @@ class Player { if (pos == -1) return; removeActiveLabel(videoList.pos); videoList.setPos(pos); - if (videoList.getCurrentItem().isTemp) removeElementItem(url); + if (videoList.currentItem.isTemp) removeElementItem(url); videoList.skipItem(); updateCounters(); if (videoList.length == 0) return; @@ -332,15 +332,14 @@ class Player { } public function setItems(list:Array<VideoItem>, ?pos:Int):Void { - final currentUrl = videoList.pos >= videoList.length ? "" : videoList.getCurrentItem() - .url; + final currentUrl = videoList.pos >= videoList.length ? "" : videoList.currentItem.url; clearItems(); if (list.length == 0) return; for (video in list) { addVideoItem(video, true); } if (pos != null) videoList.setPos(pos); - if (currentUrl != videoList.getCurrentItem().url) setVideo(videoList.pos); + if (currentUrl != videoList.currentItem.url) setVideo(videoList.pos); else addActiveLabel(videoList.pos); } @@ -401,7 +400,7 @@ class Player { public function getDuration():Float { if (videoList.pos >= videoList.length) return 0; - return videoList.getCurrentItem().duration; + return videoList.currentItem.duration; } public function isVideoLoaded():Bool { @@ -451,7 +450,7 @@ class Player { } public function skipAd():Void { - final item = videoList.getCurrentItem() ?? return; + final item = videoList.currentItem ?? return; if (!youtube.isSupportedLink(item.url)) return; final id = youtube.extractVideoId(item.url); final url = 'https://sponsor.ajay.app/api/skipSegments?videoID=$id'; diff --git a/src/server/HttpServer.hx b/src/server/HttpServer.hx index 4bf16c4..acb8955 100644 --- a/src/server/HttpServer.hx +++ b/src/server/HttpServer.hx @@ -21,13 +21,16 @@ class HttpServer { "css" => "text/css", "json" => "application/json", "png" => "image/png", - "jpg" => "image/jpg", + "jpg" => "image/jpeg", + "jpeg" => "image/jpeg", "gif" => "image/gif", + "webp" => "image/webp", "svg" => "image/svg+xml", "ico" => "image/x-icon", "wav" => "audio/wav", "mp3" => "audio/mpeg", "mp4" => "video/mp4", + "webm" => "video/webm", "woff" => "application/font-woff", "ttf" => "application/font-ttf", "eot" => "application/vnd.ms-fontobject", @@ -152,7 +155,7 @@ class HttpServer { } static function isMediaExtension(ext:String):Bool { - return ext == "mp4" || ext == "mp3" || ext == "wav"; + return ext == "mp4" || ext == "webm" || ext == "mp3" || ext == "wav"; } static final matchLang = ~/^[A-z]+/; diff --git a/src/server/Main.hx b/src/server/Main.hx index ab48592..0da88e7 100644 --- a/src/server/Main.hx +++ b/src/server/Main.hx @@ -2,9 +2,11 @@ package server; import Client.ClientData; import Types.Config; +import Types.FlashbackItem; import Types.Message; import Types.Permission; import Types.UserList; +import Types.VideoItem; import Types.WsEvent; import haxe.Json; import haxe.Timer; @@ -618,10 +620,13 @@ class Main { if (!checkPermission(client, RemoveVideoPerm)) return; if (videoList.length == 0) return; final url = data.removeVideo.url; - var index = videoList.findIndex(item -> item.url == url); + final index = videoList.findIndex(item -> item.url == url); if (index == -1) return; - final isCurrent = videoList.getCurrentItem().url == url; + final isCurrent = videoList.currentItem.url == url; + if (isCurrent && videoTimer.getTime() > FLASHBACK_DIST) { + saveFlashbackTime(videoList.currentItem); + } videoList.removeItem(index); if (isCurrent && videoList.length > 0) { broadcast(data); @@ -638,7 +643,7 @@ class Main { if (videoList.length == 0) return; if (!client.isLeader) return; if (Math.abs(data.pause.time - videoTimer.getTime()) > FLASHBACK_DIST) { - saveFlashbackTime(); + saveFlashbackTime(videoList.currentItem); } videoTimer.setTime(data.pause.time); videoTimer.pause(); @@ -651,7 +656,7 @@ class Main { if (videoList.length == 0) return; if (!client.isLeader) return; if (Math.abs(data.play.time - videoTimer.getTime()) > FLASHBACK_DIST) { - saveFlashbackTime(); + saveFlashbackTime(videoList.currentItem); } videoTimer.setTime(data.play.time); videoTimer.play(); @@ -662,11 +667,11 @@ class Main { case GetTime: if (videoList.length == 0) return; - final maxTime = videoList.getCurrentItem().duration - 0.01; + final maxTime = videoList.currentItem.duration - 0.01; if (videoTimer.getTime() > maxTime) { videoTimer.pause(); videoTimer.setTime(maxTime); - final skipUrl = videoList.getCurrentItem().url; + final skipUrl = videoList.currentItem.url; Timer.delay(() -> { skipVideo({ type: SkipVideo, @@ -694,7 +699,7 @@ class Main { if (videoList.length == 0) return; if (!client.isLeader) return; if (Math.abs(data.setTime.time - videoTimer.getTime()) > FLASHBACK_DIST) { - saveFlashbackTime(); + saveFlashbackTime(videoList.currentItem); } videoTimer.setTime(data.setTime.time); broadcastExcept(client, { @@ -716,7 +721,7 @@ class Main { if (videoList.length == 0) return; data.rewind.time += videoTimer.getTime(); if (data.rewind.time < 0) data.rewind.time = 0; - saveFlashbackTime(); + saveFlashbackTime(videoList.currentItem); videoTimer.setTime(data.rewind.time); broadcast({ type: data.type, @@ -726,7 +731,7 @@ class Main { case Flashback: if (!checkPermission(client, RewindPerm)) return; if (videoList.length == 0) return; - loadFlashbackTime(); + loadFlashbackTime(videoList.currentItem); broadcast({ type: Rewind, rewind: { @@ -762,6 +767,9 @@ class Main { case PlayItem: if (!checkPermission(client, ChangeOrderPerm)) return; + if (videoTimer.getTime() > FLASHBACK_DIST) { + saveFlashbackTime(videoList.currentItem); + } videoList.setPos(data.playItem.pos); data.playItem.pos = videoList.pos; restartWaitTimer(); @@ -790,6 +798,9 @@ class Main { case ClearPlaylist: if (isPlaylistLockedFor(client)) return; if (!checkPermission(client, RemoveVideoPerm)) return; + if (videoTimer.getTime() > FLASHBACK_DIST) { + saveFlashbackTime(videoList.currentItem); + } videoTimer.stop(); videoList.clear(); broadcast(data); @@ -902,8 +913,13 @@ class Main { function skipVideo(data:WsEvent):Void { if (videoList.length == 0) return; - final item = videoList.getCurrentItem(); + final item = videoList.currentItem; if (item.url != data.skipVideo.url) return; + final dur = videoList.currentItem.duration; + if (videoTimer.getTime() > FLASHBACK_DIST + && videoTimer.getTime() < dur - FLASHBACK_DIST) { + saveFlashbackTime(videoList.currentItem); + } videoList.skipItem(); if (videoList.length > 0) restartWaitTimer(); broadcast(data); @@ -959,7 +975,6 @@ class Main { var loadedClientsCount = 0; function restartWaitTimer():Void { - if (videoTimer.getTime() > FLASHBACK_DIST) saveFlashbackTime(); videoTimer.stop(); if (waitVideoStart != null) waitVideoStart.stop(); waitVideoStart = Timer.delay(startVideoPlayback, VIDEO_START_MAX_DELAY); @@ -979,18 +994,48 @@ class Main { videoTimer.start(); } - var flashbackTime = 0.0; - - function saveFlashbackTime() { + function saveFlashbackTime(item:VideoItem):Void { + final url = item.url; + final duration = item.duration; final time = videoTimer.getTime(); + final flashbackTime = findFlashbackTime(url, duration); if (Math.abs(flashbackTime - time) < FLASHBACK_DIST) return; - flashbackTime = time; + addRecentFlashback(url, duration, time); } - function loadFlashbackTime() { + function loadFlashbackTime(item:VideoItem):Void { + final url = item.url; + final duration = item.duration; final time = videoTimer.getTime(); + final flashbackTime = findFlashbackTime(url, duration); videoTimer.setTime(flashbackTime); - flashbackTime = time; + addRecentFlashback(url, duration, time); + } + + function findFlashbackTime(url:String, duration:Float):Float { + return findFlashbackItem(url, duration)?.time ?? 0.0; + } + + final flashbackTimes:Array<FlashbackItem> = []; + + function findFlashbackItem(url:String, ?duration:Float):Null<FlashbackItem> { + var item = flashbackTimes.find(item -> item.url == url); + // if there is no url match, find recent flashback item with same duration + if (duration != null && item == null) { + item = flashbackTimes.find(item -> item.duration == duration); + } + return item; + } + + function addRecentFlashback(url:String, duration:Float, time:Float):Void { + flashbackTimes.remove(findFlashbackItem(url)); + flashbackTimes.unshift({ + url: url, + duration: duration, + time: time + }); + final length = flashbackTimes.count(); + if (length > 10) flashbackTimes.pop(); } function isPlaylistLockedFor(client:Client):Bool { |
