aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--build/server.js124
-rw-r--r--res/client.js205
-rw-r--r--res/langs/en.json3
-rw-r--r--res/langs/ru.json3
-rw-r--r--src/Types.hx12
-rw-r--r--src/VideoList.hx67
-rw-r--r--src/client/Main.hx9
-rw-r--r--src/client/Player.hx125
-rw-r--r--src/client/Utils.hx9
-rw-r--r--src/server/Main.hx44
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);
}
send patches to the email below
yukais@pinapelz.com
include the subject [PATCH repo_name]
pinapelz.com
homepage