diff options
| -rw-r--r-- | build/server.js | 124 | ||||
| -rw-r--r-- | res/client.js | 205 | ||||
| -rw-r--r-- | res/langs/en.json | 3 | ||||
| -rw-r--r-- | res/langs/ru.json | 3 | ||||
| -rw-r--r-- | src/Types.hx | 12 | ||||
| -rw-r--r-- | src/VideoList.hx | 67 | ||||
| -rw-r--r-- | src/client/Main.hx | 9 | ||||
| -rw-r--r-- | src/client/Player.hx | 125 | ||||
| -rw-r--r-- | src/client/Utils.hx | 9 | ||||
| -rw-r--r-- | src/server/Main.hx | 44 |
10 files changed, 438 insertions, 163 deletions
diff --git a/build/server.js b/build/server.js index 4cd1089..c90a298 100644 --- a/build/server.js +++ b/build/server.js @@ -183,16 +183,6 @@ Lambda.exists = function(it,f) { } return false; }; -Lambda.find = function(it,f) { - var v = $getIterator(it); - while(v.hasNext()) { - var v1 = v.next(); - if(f(v1)) { - return v1; - } - } - return null; -}; var haxe_ds_StringMap = function() { this.h = { }; }; @@ -319,6 +309,59 @@ StringTools.startsWith = function(s,start) { StringTools.replace = function(s,sub,by) { return s.split(sub).join(by); }; +var _$VideoList_VideoList_$Impl_$ = {}; +_$VideoList_VideoList_$Impl_$.__name__ = true; +_$VideoList_VideoList_$Impl_$._new = function() { + return []; +}; +_$VideoList_VideoList_$Impl_$.findIndex = function(this1,f) { + var i = 0; + var _g = 0; + while(_g < this1.length) { + if(f(this1[_g++])) { + return i; + } + ++i; + } + return -1; +}; +_$VideoList_VideoList_$Impl_$.addItem = function(this1,item,atEnd,itemPos) { + if(atEnd) { + this1.push(item); + } else { + this1.splice(itemPos + 1,0,item); + } +}; +_$VideoList_VideoList_$Impl_$.setNextItem = function(this1,pos,itemPos) { + var next = this1[pos]; + HxOverrides.remove(this1,next); + this1.splice(itemPos + 1,0,next); +}; +_$VideoList_VideoList_$Impl_$.toggleItemType = function(this1,pos) { + this1[pos].isTemp = !this1[pos].isTemp; +}; +_$VideoList_VideoList_$Impl_$.removeItem = function(this1,index,itemPos) { + if(index < itemPos) { + --itemPos; + } + HxOverrides.remove(this1,this1[index]); + if(itemPos >= this1.length) { + itemPos = 0; + } + return itemPos; +}; +_$VideoList_VideoList_$Impl_$.skipItem = function(this1,itemPos) { + var item = this1[itemPos]; + if(!item.isTemp) { + ++itemPos; + } else { + HxOverrides.remove(this1,item); + } + if(itemPos >= this1.length) { + itemPos = 0; + } + return itemPos; +}; var haxe_Log = function() { }; haxe_Log.__name__ = true; haxe_Log.formatOutput = function(v,infos) { @@ -648,7 +691,7 @@ var server_Main = function(port,wsPort) { this.itemPos = 0; this.messages = []; this.videoTimer = new server_VideoTimer(); - this.videoList = []; + this.videoList = _$VideoList_VideoList_$Impl_$._new(); this.freeIds = []; this.clients = []; this.rootDir = "" + __dirname + "/.."; @@ -834,11 +877,7 @@ server_Main.prototype = { })) { return; } - if(data.addVideo.atEnd) { - this.videoList.push(item); - } else { - this.videoList.splice(this.itemPos + 1,0,item); - } + _$VideoList_VideoList_$Impl_$.addItem(this.videoList,item,data.addVideo.atEnd,this.itemPos); this.broadcast(data); if(this.videoList.length == 1) { this.restartWaitTimer(); @@ -926,31 +965,26 @@ server_Main.prototype = { this.videoTimer.play(); this.broadcast(data); break; + case "PlayItem": + this.itemPos = data.playItem.pos; + this.restartWaitTimer(); + this.broadcast(data); + break; case "RemoveVideo": if(this.videoList.length == 0) { return; } var url = data.removeVideo.url; - var item1 = Lambda.find(this.videoList,function(item2) { - return item2.url == url; + var index = _$VideoList_VideoList_$Impl_$.findIndex(this.videoList,function(item1) { + return item1.url == url; }); - if(item1 == null) { + if(index == -1) { return; } - var index = this.videoList.indexOf(item1); var isCurrent = this.videoList[this.itemPos].url == url; - if(index < this.itemPos) { - this.itemPos--; - } - HxOverrides.remove(this.videoList,item1); - if(isCurrent) { - if(this.itemPos >= this.videoList.length) { - this.itemPos = 0; - } - this.videoTimer.stop(); - if(this.videoList.length > 0) { - this.restartWaitTimer(); - } + this.itemPos = _$VideoList_VideoList_$Impl_$.removeItem(this.videoList,index,this.itemPos); + if(isCurrent && this.videoList.length > 0) { + this.restartWaitTimer(); } this.broadcast(data); break; @@ -978,6 +1012,14 @@ server_Main.prototype = { this.broadcast({ type : "Play", play : { time : this.videoTimer.getTime()}}); } break; + case "SetNextItem": + var pos = data.setNextItem.pos; + if(pos == this.itemPos || pos == this.itemPos + 1) { + return; + } + _$VideoList_VideoList_$Impl_$.setNextItem(this.videoList,pos,this.itemPos); + this.broadcast(data); + break; case "SetTime": if(this.videoList.length == 0) { return; @@ -1002,24 +1044,19 @@ server_Main.prototype = { if(this.videoList.length == 0) { return; } - var item3 = this.videoList[this.itemPos]; - if(item3.url != data.skipVideo.url) { + if(this.videoList[this.itemPos].url != data.skipVideo.url) { return; } - if(!item3.isTemp) { - this.itemPos++; - } else { - HxOverrides.remove(this.videoList,item3); - } - if(this.itemPos >= this.videoList.length) { - this.itemPos = 0; - } - this.videoTimer.stop(); + this.itemPos = _$VideoList_VideoList_$Impl_$.skipItem(this.videoList,this.itemPos); if(this.videoList.length > 0) { this.restartWaitTimer(); } this.broadcast(data); break; + case "ToggleItemType": + _$VideoList_VideoList_$Impl_$.toggleItemType(this.videoList,data.toggleItemType.pos); + this.broadcast(data); + break; case "UpdateClients": this.sendClientList(); break; @@ -1072,6 +1109,7 @@ server_Main.prototype = { return false; } ,restartWaitTimer: function() { + this.videoTimer.stop(); if(this.waitVideoStart != null) { this.waitVideoStart.stop(); } diff --git a/res/client.js b/res/client.js index bcbe9cd..3367bcf 100644 --- a/res/client.js +++ b/res/client.js @@ -118,16 +118,6 @@ Lambda.exists = function(it,f) { } return false; }; -Lambda.find = function(it,f) { - var v = $getIterator(it); - while(v.hasNext()) { - var v1 = v.next(); - if(f(v1)) { - return v1; - } - } - return null; -}; var haxe_ds_StringMap = function() { this.h = { }; }; @@ -336,6 +326,59 @@ StringTools.startsWith = function(s,start) { StringTools.replace = function(s,sub,by) { return s.split(sub).join(by); }; +var _$VideoList_VideoList_$Impl_$ = {}; +_$VideoList_VideoList_$Impl_$.__name__ = true; +_$VideoList_VideoList_$Impl_$._new = function() { + return []; +}; +_$VideoList_VideoList_$Impl_$.findIndex = function(this1,f) { + var i = 0; + var _g = 0; + while(_g < this1.length) { + if(f(this1[_g++])) { + return i; + } + ++i; + } + return -1; +}; +_$VideoList_VideoList_$Impl_$.addItem = function(this1,item,atEnd,itemPos) { + if(atEnd) { + this1.push(item); + } else { + this1.splice(itemPos + 1,0,item); + } +}; +_$VideoList_VideoList_$Impl_$.setNextItem = function(this1,pos,itemPos) { + var next = this1[pos]; + HxOverrides.remove(this1,next); + this1.splice(itemPos + 1,0,next); +}; +_$VideoList_VideoList_$Impl_$.toggleItemType = function(this1,pos) { + this1[pos].isTemp = !this1[pos].isTemp; +}; +_$VideoList_VideoList_$Impl_$.removeItem = function(this1,index,itemPos) { + if(index < itemPos) { + --itemPos; + } + HxOverrides.remove(this1,this1[index]); + if(itemPos >= this1.length) { + itemPos = 0; + } + return itemPos; +}; +_$VideoList_VideoList_$Impl_$.skipItem = function(this1,itemPos) { + var item = this1[itemPos]; + if(!item.isTemp) { + ++itemPos; + } else { + HxOverrides.remove(this1,item); + } + if(itemPos >= this1.length) { + itemPos = 0; + } + return itemPos; +}; var client_Buttons = function() { }; client_Buttons.__name__ = true; client_Buttons.init = function(main) { @@ -767,10 +810,10 @@ client_Main.prototype = { this.player.refresh(); } ,getPlaylistLinks: function() { - var items = this.player.getItems(); var _g = []; var _g1 = 0; - while(_g1 < items.length) _g.push(items[_g1++].url); + var _g2 = this.player.getItems(); + while(_g1 < _g2.length) _g.push(_g2[_g1++].url); return _g; } ,tryLocalIp: function(url) { @@ -873,6 +916,9 @@ client_Main.prototype = { this.player.setTime(data.play.time); this.player.play(); break; + case "PlayItem": + this.player.setVideo(data.playItem.pos); + break; case "RemoveVideo": this.player.removeItem(data.removeVideo.url); if(this.player.isListEmpty()) { @@ -890,6 +936,9 @@ client_Main.prototype = { this.player.setTime(this.player.getTime(),false); } break; + case "SetNextItem": + this.player.setNextItem(data.setNextItem.pos); + break; case "SetTime": var newTime1 = data.setTime.time; var time1 = this.player.getTime(); @@ -906,6 +955,9 @@ client_Main.prototype = { this.player.pause(); } break; + case "ToggleItemType": + this.player.toggleItemType(data.toggleItemType.pos); + break; case "UpdateClients": this.updateClients(data.updateClients.clients); this.personal = ClientTools.getByName(this.clients,this.personal.name,this.personal); @@ -1179,12 +1231,44 @@ var client_Player = function(main) { this.currentSrc = ""; this.playerEl = window.document.querySelector("#ytapiplayer"); this.videoItemsEl = window.document.querySelector("#queue"); - this.items = []; + this.items = _$VideoList_VideoList_$Impl_$._new(); this.main = main; + this.initItemButtons(); }; client_Player.__name__ = true; client_Player.prototype = { - setPlayer: function(player) { + initItemButtons: function() { + var _gthis = this; + window.document.querySelector("#queue").onclick = function(e) { + var btn = e.target; + var item = btn.parentElement.parentElement; + var i = client_Utils.getIndex(item.parentElement,item); + if(btn.classList.contains("qbtn-play")) { + _gthis.main.send({ type : "PlayItem", playItem : { pos : i}}); + } + if(btn.classList.contains("qbtn-next")) { + _gthis.main.send({ type : "SetNextItem", setNextItem : { pos : i}}); + } + if(btn.classList.contains("qbtn-tmp")) { + _gthis.main.send({ type : "ToggleItemType", toggleItemType : { pos : i}}); + } + if(btn.classList.contains("qbtn-delete")) { + _gthis.main.send({ type : "RemoveVideo", removeVideo : { url : item.querySelector(".qe_title").getAttribute("href")}}); + } + return; + }; + } + ,setNextItem: function(pos) { + _$VideoList_VideoList_$Impl_$.setNextItem(this.items,pos,this.itemPos); + var next = this.videoItemsEl.children[pos]; + this.videoItemsEl.removeChild(next); + client_Utils.insertAtIndex(this.videoItemsEl,next,this.itemPos + 1); + } + ,toggleItemType: function(pos) { + _$VideoList_VideoList_$Impl_$.toggleItemType(this.items,pos); + this.setItemElementType(this.videoItemsEl.children[pos],this.items[pos].isTemp); + } + ,setPlayer: function(player) { this.player = player; } ,isYoutube: function(url) { @@ -1250,20 +1334,9 @@ client_Player.prototype = { this.main.send({ type : "SetTime", setTime : { time : this.getTime()}}); } ,addVideoItem: function(item,atEnd) { - var _gthis = this; - var itemEl = this.nodeFromString("<li class=\"queue_entry pluid-0\" title=\"" + Lang.get("addedBy") + ": " + item.author + "\">\n\t\t\t\t<a class=\"qe_title\" href=\"" + item.url + "\" target=\"_blank\">" + StringTools.htmlEscape(item.title) + "</a>\n\t\t\t\t<span class=\"qe_time\">" + this.duration(item.duration) + "</span>\n\t\t\t\t<div class=\"qe_clear\"></div>\n\t\t\t\t<div class=\"btn-group\" style=\"display: inline-block;\">\n\t\t\t\t\t<button class=\"btn btn-xs btn-default qbtn-play\">\n\t\t\t\t\t\t<span class=\"glyphicon glyphicon-play\"></span>" + Lang.get("play") + "\n\t\t\t\t\t</button>\n\t\t\t\t\t<button class=\"btn btn-xs btn-default qbtn-next\">\n\t\t\t\t\t\t<span class=\"glyphicon glyphicon-share-alt\"></span>" + Lang.get("skip") + "\n\t\t\t\t\t</button>\n\t\t\t\t\t<button class=\"btn btn-xs btn-default qbtn-tmp\">\n\t\t\t\t\t\t<span class=\"glyphicon glyphicon-flag\"></span>" + Lang.get("makePermanent") + "\n\t\t\t\t\t</button>\n\t\t\t\t\t<button class=\"btn btn-xs btn-default qbtn-delete\" id=\"btn-delete\">\n\t\t\t\t\t\t<span class=\"glyphicon glyphicon-trash\"></span>" + Lang.get("delete") + "\n\t\t\t\t\t</button>\n\t\t\t\t</div>\n\t\t\t</li>"); - if(item.isTemp) { - itemEl.classList.add("queue_temp"); - } - itemEl.querySelector("#btn-delete").onclick = function(e) { - _gthis.main.send({ type : "RemoveVideo", removeVideo : { url : itemEl.querySelector(".qe_title").getAttribute("href")}}); - return; - }; - if(atEnd) { - this.items.push(item); - } else { - this.items.splice(this.itemPos + 1,0,item); - } + var itemEl = this.nodeFromString("<li class=\"queue_entry pluid-0\" title=\"" + Lang.get("addedBy") + ": " + item.author + "\">\n\t\t\t\t<a class=\"qe_title\" href=\"" + item.url + "\" target=\"_blank\">" + StringTools.htmlEscape(item.title) + "</a>\n\t\t\t\t<span class=\"qe_time\">" + this.duration(item.duration) + "</span>\n\t\t\t\t<div class=\"qe_clear\"></div>\n\t\t\t\t<div class=\"btn-group\" style=\"display: inline-block;\">\n\t\t\t\t\t<button class=\"btn btn-xs btn-default qbtn-play\">\n\t\t\t\t\t\t<span class=\"glyphicon glyphicon-play\"></span>" + Lang.get("play") + "\n\t\t\t\t\t</button>\n\t\t\t\t\t<button class=\"btn btn-xs btn-default qbtn-next\">\n\t\t\t\t\t\t<span class=\"glyphicon glyphicon-share-alt\"></span>" + Lang.get("setNext") + "\n\t\t\t\t\t</button>\n\t\t\t\t\t<button class=\"btn btn-xs btn-default qbtn-tmp\">\n\t\t\t\t\t\t<span class=\"glyphicon glyphicon-flag\"></span>\n\t\t\t\t\t</button>\n\t\t\t\t\t<button class=\"btn btn-xs btn-default qbtn-delete\">\n\t\t\t\t\t\t<span class=\"glyphicon glyphicon-trash\"></span>" + Lang.get("delete") + "\n\t\t\t\t\t</button>\n\t\t\t\t</div>\n\t\t\t</li>"); + _$VideoList_VideoList_$Impl_$.addItem(this.items,item,atEnd,this.itemPos); + this.setItemElementType(itemEl,item.isTemp); if(atEnd) { this.videoItemsEl.appendChild(itemEl); } else { @@ -1271,7 +1344,31 @@ client_Player.prototype = { } this.updateCounters(); } + ,setItemElementType: function(item,isTemp) { + var text = isTemp ? Lang.get("makePermanent") : Lang.get("makeTemporary"); + item.querySelector(".qbtn-tmp").innerHTML = "<span class=\"glyphicon glyphicon-flag\"></span>" + text; + if(isTemp) { + item.classList.add("queue_temp"); + } else { + item.classList.remove("queue_temp"); + } + } ,removeItem: function(url) { + this.removeElementItem(url); + var index = _$VideoList_VideoList_$Impl_$.findIndex(this.items,function(item) { + return item.url == url; + }); + if(index == -1) { + return; + } + var isCurrent = this.items[this.itemPos].url == url; + this.itemPos = _$VideoList_VideoList_$Impl_$.removeItem(this.items,index,this.itemPos); + this.updateCounters(); + if(isCurrent && this.items.length > 0) { + this.setVideo(this.itemPos); + } + } + ,removeElementItem: function(url) { var _g = 0; var _g1 = this.videoItemsEl.children; while(_g < _g1.length) { @@ -1282,44 +1379,20 @@ client_Player.prototype = { break; } } - var item = Lambda.find(this.items,function(item1) { - return item1.url == url; - }); - if(item == null) { - return; - } - var index = this.items.indexOf(item); - HxOverrides.remove(this.items,item); - this.updateCounters(); - if(index < this.itemPos) { - this.itemPos--; - return; - } - if(index != this.itemPos) { - return; - } - if(this.items.length == 0) { - return; - } - if(this.items[index] == null) { - index = 0; - } - this.setVideo(index); } ,skipItem: function(url) { - var item = Lambda.find(this.items,function(item1) { - return item1.url == url; + var index = _$VideoList_VideoList_$Impl_$.findIndex(this.items,function(item) { + return item.url == url; }); - if(item == null) { + if(index == -1) { return; } - if(item.isTemp) { - this.removeItem(url); - return; + if(this.items[index].isTemp) { + this.removeElementItem(url); } - var index = this.items.indexOf(item) + 1; - if(index >= this.items.length) { - index = 0; + index = _$VideoList_VideoList_$Impl_$.skipItem(this.items,index); + if(this.items.length == 0) { + return; } this.setVideo(index); } @@ -1444,6 +1517,18 @@ client_Utils.insertAtIndex = function(parent,child,i) { parent.insertBefore(child,parent.children[i]); } }; +client_Utils.getIndex = function(parent,child) { + var i = 0; + var _g = 0; + var _g1 = parent.children; + while(_g < _g1.length) { + if(_g1[_g++] == child) { + break; + } + ++i; + } + return i; +}; client_Utils.toggleFullScreen = function(el) { var state = true; var doc = window.document; diff --git a/res/langs/en.json b/res/langs/en.json index 145e7ae..119dcb4 100644 --- a/res/langs/en.json +++ b/res/langs/en.json @@ -11,8 +11,9 @@ "videos": "videos", "addedBy": "Added by", "play": "Play", - "skip": "Skip", + "setNext": "Next", "makePermanent": "Make Permanent", + "makeTemporary": "Make Temporary", "delete": "Delete", "account": "Account", "exportSettings": "Export Settings", diff --git a/res/langs/ru.json b/res/langs/ru.json index ce5d125..f01262c 100644 --- a/res/langs/ru.json +++ b/res/langs/ru.json @@ -11,8 +11,9 @@ "videos": "видео", "addedBy": "Добавлено", "play": "Воспроизвести", - "skip": "Пропустить", + "setNext": "Следующее", "makePermanent": "Закрепить", + "makeTemporary": "Открепить", "delete": "Удалить", "account": "Аккаунт", "exportSettings": "Экспорт настроек", diff --git a/src/Types.hx b/src/Types.hx index b98a6c2..17b010b 100644 --- a/src/Types.hx +++ b/src/Types.hx @@ -97,6 +97,15 @@ typedef WsEvent = { ?setLeader:{ clientName:String }, + ?playItem:{ + pos:Int + }, + ?setNextItem:{ + pos:Int + }, + ?toggleItemType:{ + pos:Int + }, ?updatePlaylist:{ videoList:Array<VideoItem> } @@ -121,6 +130,9 @@ enum abstract WsEventType(String) { var SetTime; var Rewind; var SetLeader; + var PlayItem; + var SetNextItem; + var ToggleItemType; var ClearChat; var ClearPlaylist; var ShufflePlaylist; diff --git a/src/VideoList.hx b/src/VideoList.hx new file mode 100644 index 0000000..2f13b6c --- /dev/null +++ b/src/VideoList.hx @@ -0,0 +1,67 @@ +package; + +import Types.VideoItem; + +// TODO move itemPos to abstract +// typedef VideoListData = { +// items:Array<VideoItem>, +// itemPos:Int +// } + +@:forward +abstract VideoList(Array<VideoItem>) from Array<VideoItem> to Array<VideoItem> { + + public function new() { + this = []; + } + + @:arrayAccess + public inline function get(i:Int):VideoItem { + return this[i]; + } + + @:arrayAccess + public inline function set(k:Int, v:VideoItem):VideoItem { + return this[k] = v; + } + + public function findIndex(f:(item:VideoItem) -> Bool):Int { + var i = 0; + for (v in this) { + if (f(v)) return i; + i++; + } + return -1; + } + + public function addItem(item:VideoItem, atEnd:Bool, itemPos:Int):Void { + if (atEnd) this.push(item); + else this.insert(itemPos + 1, item); + } + + public function setNextItem(pos:Int, itemPos:Int):Void { + final next = this[pos]; + this.remove(next); + this.insert(itemPos + 1, next); + } + + public function toggleItemType(pos:Int):Void { + this[pos].isTemp = !this[pos].isTemp; + } + + public function removeItem(index:Int, itemPos:Int):Int { + if (index < itemPos) itemPos--; + this.remove(this[index]); + if (itemPos >= this.length) itemPos = 0; + return itemPos; + } + + public function skipItem(itemPos:Int):Int { + final item = this[itemPos]; + if (!item.isTemp) itemPos++; + else this.remove(item); + if (itemPos >= this.length) itemPos = 0; + return itemPos; + } + +} diff --git a/src/client/Main.hx b/src/client/Main.hx index 19ca44b..1804ca1 100644 --- a/src/client/Main.hx +++ b/src/client/Main.hx @@ -307,6 +307,15 @@ class Main { setLeaderButton(isLeader()); if (isLeader()) player.setTime(player.getTime(), false); + case PlayItem: + player.setVideo(data.playItem.pos); + + case SetNextItem: + player.setNextItem(data.setNextItem.pos); + + case ToggleItemType: + player.toggleItemType(data.toggleItemType.pos); + case ClearChat: clearChat(); diff --git a/src/client/Player.hx b/src/client/Player.hx index 2c8f62e..3941bdb 100644 --- a/src/client/Player.hx +++ b/src/client/Player.hx @@ -11,7 +11,7 @@ using Lambda; class Player { final main:Main; - final items:Array<VideoItem> = []; + final items = new VideoList(); final videoItemsEl = ge("#queue"); final playerEl:Element = ge("#ytapiplayer"); var player:Null<IPlayer>; @@ -23,6 +23,58 @@ class Player { public function new(main:Main):Void { this.main = main; + initItemButtons(); + } + + function initItemButtons():Void { + final queue = ge("#queue"); + queue.onclick = e -> { + final btn:Element = cast e.target; + final item = btn.parentElement.parentElement; + final i = Utils.getIndex(item.parentElement, item); + if (btn.classList.contains("qbtn-play")) { + main.send({ + type: PlayItem, playItem: { + pos: i + } + }); + } + if (btn.classList.contains("qbtn-next")) { + main.send({ + type: SetNextItem, setNextItem: { + pos: i + } + }); + } + if (btn.classList.contains("qbtn-tmp")) { + main.send({ + type: ToggleItemType, toggleItemType: { + pos: i + } + }); + } + if (btn.classList.contains("qbtn-delete")) { + main.send({ + type: RemoveVideo, removeVideo: { + url: item.querySelector(".qe_title").getAttribute("href") + } + }); + } + } + } + + public function setNextItem(pos:Int):Void { + items.setNextItem(pos, itemPos); + + final next = videoItemsEl.children[pos]; + videoItemsEl.removeChild(next); + Utils.insertAtIndex(videoItemsEl, next, itemPos + 1); + } + + public function toggleItemType(pos:Int):Void { + items.toggleItemType(pos); + final el = videoItemsEl.children[pos]; + setItemElementType(el, items[pos].isTemp); } function setPlayer(player:IPlayer):Void { @@ -108,67 +160,60 @@ class Player { <span class="glyphicon glyphicon-play"></span>${Lang.get("play")} </button> <button class="btn btn-xs btn-default qbtn-next"> - <span class="glyphicon glyphicon-share-alt"></span>${Lang.get("skip")} + <span class="glyphicon glyphicon-share-alt"></span>${Lang.get("setNext")} </button> <button class="btn btn-xs btn-default qbtn-tmp"> - <span class="glyphicon glyphicon-flag"></span>${Lang.get("makePermanent")} + <span class="glyphicon glyphicon-flag"></span> </button> - <button class="btn btn-xs btn-default qbtn-delete" id="btn-delete"> + <button class="btn btn-xs btn-default qbtn-delete"> <span class="glyphicon glyphicon-trash"></span>${Lang.get("delete")} </button> </div> </li>' ); - if (item.isTemp) itemEl.classList.add("queue_temp"); - final deleteBtn = itemEl.querySelector("#btn-delete"); - deleteBtn.onclick = e -> { - main.send({ - type: RemoveVideo, - removeVideo: { - url: itemEl.querySelector(".qe_title").getAttribute("href") - } - }); - } - if (atEnd) items.push(item); - else items.insert(itemPos + 1, item); + items.addItem(item, atEnd, itemPos); + setItemElementType(itemEl, item.isTemp); if (atEnd) videoItemsEl.appendChild(itemEl); else Utils.insertAtIndex(videoItemsEl, itemEl, itemPos + 1); updateCounters(); } + function setItemElementType(item:Element, isTemp:Bool):Void { + final text = isTemp ? Lang.get("makePermanent") : Lang.get("makeTemporary"); + item.querySelector(".qbtn-tmp").innerHTML = '<span class="glyphicon glyphicon-flag"></span>$text'; + if (isTemp) item.classList.add("queue_temp"); + else item.classList.remove("queue_temp"); + } + public function removeItem(url:String):Void { + removeElementItem(url); + var index = items.findIndex(item -> item.url == url); + if (index == -1) return; + + final isCurrent = items[itemPos].url == url; + itemPos = items.removeItem(index, itemPos); + updateCounters(); + + if (isCurrent && items.length > 0) { + setVideo(itemPos); + } + } + + function removeElementItem(url:String):Void { for (child in videoItemsEl.children) { if (child.querySelector(".qe_title").getAttribute("href") == url) { videoItemsEl.removeChild(child); break; } } - - final item = items.find(item -> item.url == url); - if (item == null) return; - var index = items.indexOf(item); - items.remove(item); - updateCounters(); - - if (index < itemPos) { - itemPos--; - return; - } - if (index != itemPos) return; - if (items.length == 0) return; - if (items[index] == null) index = 0; - setVideo(index); } public function skipItem(url:String):Void { - final item = items.find(item -> item.url == url); - if (item == null) return; - if (item.isTemp) { - removeItem(url); - return; - } - var index = items.indexOf(item) + 1; - if (index >= items.length) index = 0; + var index = items.findIndex(item -> item.url == url); + if (index == -1) return; + if (items[index].isTemp) removeElementItem(url); + index = items.skipItem(index); + if (items.length == 0) return; setVideo(index); } @@ -177,7 +222,7 @@ class Player { ge("#pllength").textContent = totalDuration(); } - public function getItems():Array<VideoItem> { + public function getItems():VideoList { return items; } diff --git a/src/client/Utils.hx b/src/client/Utils.hx index 37de672..69671d2 100644 --- a/src/client/Utils.hx +++ b/src/client/Utils.hx @@ -16,6 +16,15 @@ class Utils { else parent.insertBefore(child, parent.children[i]); } + public static function getIndex(parent:Element, child:Element):Int { + var i = 0; + for (el in parent.children) { + if (el == child) break; + i++; + } + return i; + } + public static function toggleFullScreen(el:Element):Bool { var state = true; final doc:Dynamic = document; diff --git a/src/server/Main.hx b/src/server/Main.hx index e7895ca..e5b50c8 100644 --- a/src/server/Main.hx +++ b/src/server/Main.hx @@ -28,7 +28,7 @@ class Main { final config:Config; final clients:Array<Client> = []; final freeIds:Array<Int> = []; - final videoList:Array<VideoItem> = []; + final videoList = new VideoList(); final videoTimer = new VideoTimer(); final messages:Array<Message> = []; var itemPos = 0; @@ -257,8 +257,7 @@ class Main { // TODO send server message return; } - if (data.addVideo.atEnd) videoList.push(item); - else videoList.insert(itemPos + 1, item); + videoList.addItem(item, data.addVideo.atEnd, itemPos); broadcast(data); // Initial timer start if VideoLoaded is not happen if (videoList.length == 1) restartWaitTimer(); @@ -270,16 +269,13 @@ class Main { case RemoveVideo: if (videoList.length == 0) return; final url = data.removeVideo.url; - final item = videoList.find(item -> item.url == url); - if (item == null) return; - final index = videoList.indexOf(item); + var index = videoList.findIndex(item -> item.url == url); + if (index == -1) return; + final isCurrent = videoList[itemPos].url == url; - if (index < itemPos) itemPos--; - videoList.remove(item); - if (isCurrent) { - if (itemPos >= videoList.length) itemPos = 0; - videoTimer.stop(); - if (videoList.length > 0) restartWaitTimer(); + itemPos = videoList.removeItem(index, itemPos); + if (isCurrent && videoList.length > 0) { + restartWaitTimer(); } broadcast(data); @@ -287,12 +283,7 @@ class Main { if (videoList.length == 0) return; final item = videoList[itemPos]; if (item.url != data.skipVideo.url) return; - - if (!item.isTemp) itemPos++; - else videoList.remove(item); - if (itemPos >= videoList.length) itemPos = 0; - - videoTimer.stop(); + itemPos = videoList.skipItem(itemPos); if (videoList.length > 0) restartWaitTimer(); broadcast(data); @@ -357,6 +348,22 @@ class Main { }); } + case PlayItem: + itemPos = data.playItem.pos; + restartWaitTimer(); + broadcast(data); + + case SetNextItem: + final pos = data.setNextItem.pos; + if (pos == itemPos || pos == itemPos + 1) return; + videoList.setNextItem(pos, itemPos); + broadcast(data); + + case ToggleItemType: + final pos = data.toggleItemType.pos; + videoList.toggleItemType(pos); + broadcast(data); + case ClearChat: messages.resize(0); if (client.isAdmin) broadcast(data); @@ -426,6 +433,7 @@ class Main { var loadedClientsCount = 0; function restartWaitTimer():Void { + videoTimer.stop(); if (waitVideoStart != null) waitVideoStart.stop(); waitVideoStart = Timer.delay(startVideoPlayback, 3000); } |
