From 98c1f6fa4ec7537ec979a1ae8d68cb6ec11c3fbf Mon Sep 17 00:00:00 2001 From: RblSb Date: Mon, 27 Sep 2021 20:48:29 +0300 Subject: Rework videolist structure --- src/VideoList.hx | 119 +++++++++++++++++++++++++++++++--------------- src/client/JsApi.hx | 2 +- src/client/Player.hx | 107 +++++++++++++++++++++++------------------ src/client/players/Raw.hx | 1 + src/server/Main.hx | 62 +++++++++++------------- 5 files changed, 170 insertions(+), 121 deletions(-) (limited to 'src') diff --git a/src/VideoList.hx b/src/VideoList.hx index ef1d113..2ed1d8f 100644 --- a/src/VideoList.hx +++ b/src/VideoList.hx @@ -2,73 +2,116 @@ package; import Types.VideoItem; -// TODO move itemPos to abstract -// typedef VideoListData = { -// items:Array, -// itemPos:Int -// } -@:forward -abstract VideoList(Array) from Array to Array { - public function new() { - this = []; +using Lambda; + +class VideoList { + public var length(get, never):Int; + public var pos(default, null) = 0; + public var isOpen = true; + + final items:Array = []; + + public function new() {} + + inline function get_length():Int { + return items.length; + } + + public inline function getCurrentItem():VideoItem { + return items[pos]; } - @:arrayAccess - public inline function get(i:Int):VideoItem { - return this[i]; + public inline function getItem(i:Int):VideoItem { + return items[i]; } - @:arrayAccess - public inline function set(k:Int, v:VideoItem):VideoItem { - return this[k] = v; + public inline function setItem(i:Int, item:VideoItem):Void { + items[i] = item; + } + + public inline function getItems():Array { + return items; + } + + public function setItems(items:Array):Void { + clear(); + for (item in items) + this.items.push(item); + } + + public function setPos(i:Int):Void { + if (i < 0 || i > length - 1) i = 0; + pos = i; + } + + public function exists(f:(item:VideoItem) -> Bool):Bool { + return items.exists(f); } public function findIndex(f:(item:VideoItem) -> Bool):Int { var i = 0; - for (v in this) { + for (v in items) { 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 addItem(item:VideoItem, atEnd:Bool):Void { + if (atEnd) items.push(item); + else items.insert(pos + 1, item); } - public function setNextItem(pos:Int, itemPos:Int):Int { - final next = this[pos]; - this.remove(next); - if (pos < itemPos) itemPos--; - this.insert(itemPos + 1, next); - return itemPos; + public function setNextItem(nextPos:Int):Void { + final next = items[nextPos]; + items.remove(next); + if (nextPos < pos) pos--; + items.insert(pos + 1, next); } public function toggleItemType(pos:Int):Void { - this[pos].isTemp = !this[pos].isTemp; + items[pos].isTemp = !items[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 removeItem(index:Int):Void { + if (index < pos) pos--; + items.remove(items[index]); + if (pos >= items.length) pos = 0; } - 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; + public function skipItem():Void { + final item = items[pos]; + if (!item.isTemp) pos++; + else items.remove(item); + if (pos >= items.length) pos = 0; } public function itemsByUser(client:Client):Int { var i = 0; - for (item in this) { + for (item in items) { if (item.author == client.name) i++; } return i; } + + public inline function clear():Void { + items.resize(0); + pos = 0; + } + + public function shuffle() { + final current = items[pos]; + items.remove(current); + shuffleArray(items); + items.insert(pos, current); + } + + function shuffleArray(arr:Array):Void { + for (i => a in arr) { + final n = Std.random(arr.length); + final b = arr[n]; + arr[i] = b; + arr[n] = a; + } + } } diff --git a/src/client/JsApi.hx b/src/client/JsApi.hx index d9e6f02..63b98c5 100644 --- a/src/client/JsApi.hx +++ b/src/client/JsApi.hx @@ -66,7 +66,7 @@ class JsApi { } @:expose - static function getVideoItems():VideoList { + static function getVideoItems():Array { final items = player.getItems(); return [ for (item in items) Reflect.copy(item) diff --git a/src/client/Player.hx b/src/client/Player.hx index 4d70526..496c355 100644 --- a/src/client/Player.hx +++ b/src/client/Player.hx @@ -17,11 +17,10 @@ class Player { final players:Array; final iframePlayer:IPlayer; final rawPlayer:IPlayer; - final items = new VideoList(); + final videoList = new VideoList(); final videoItemsEl = ge("#queue"); final playerEl:Element = ge("#ytapiplayer"); var player:Null; - var itemPos = 0; var isLoaded = false; var skipSetTime = false; var skipSetRate = false; @@ -73,23 +72,23 @@ class Player { } public function setNextItem(pos:Int):Void { - itemPos = items.setNextItem(pos, itemPos); + videoList.setNextItem(pos); final next = videoItemsEl.children[pos]; videoItemsEl.removeChild(next); - Utils.insertAtIndex(videoItemsEl, next, itemPos + 1); + Utils.insertAtIndex(videoItemsEl, next, videoList.pos + 1); } public function toggleItemType(pos:Int):Void { - items.toggleItemType(pos); + videoList.toggleItemType(pos); final el = videoItemsEl.children[pos]; - setItemElementType(el, items[pos].isTemp); + setItemElementType(el, videoList.getItem(videoList.pos).isTemp); } function setPlayer(newPlayer:IPlayer):Void { if (player != newPlayer) { if (player != null) { - JsApi.fireVideoRemoveEvents(items[itemPos]); + JsApi.fireVideoRemoveEvents(videoList.getCurrentItem()); player.removeVideo(); } main.blinkTabWithTitle("*Video*"); @@ -113,18 +112,15 @@ class Player { public function setVideo(i:Int):Void { if (!main.isSyncActive) return; - final item = items[i]; + 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); - final childs = videoItemsEl.children; - if (childs[itemPos] != null) { - childs[itemPos].classList.remove("queue_active"); - } - itemPos = i; - childs[itemPos].classList.add("queue_active"); + removeActiveLabel(videoList.pos); + videoList.setPos(i); + addActiveLabel(videoList.pos); isLoaded = false; player.loadVideo(item); @@ -134,7 +130,7 @@ class Player { public function changeVideoSrc(src:String):Void { if (player == null) return; - final item = items[itemPos]; + final item = videoList.getCurrentItem(); if (item == null) return; player.loadVideo({ url: src, @@ -148,7 +144,7 @@ class Player { } public function removeVideo():Void { - JsApi.fireVideoRemoveEvents(items[itemPos]); + JsApi.fireVideoRemoveEvents(videoList.getCurrentItem()); player.removeVideo(); ge("#currenttitle").textContent = Lang.get("nothingPlaying"); setPauseIndicator(true); @@ -175,7 +171,7 @@ class Player { time: getTime() } }); - final hasAutoPause = main.hasLeaderOnPauseRequest() && items.length > 0; + final hasAutoPause = main.hasLeaderOnPauseRequest() && videoList.length > 0; if (hasAutoPause) { // do not remove leader if user cannot request it back final group:Client.ClientGroup = main.isAdmin() ? Admin : User; @@ -184,7 +180,7 @@ class Player { } public function onPause():Void { - final hasAutoPause = main.hasLeaderOnPauseRequest() && items.length > 0 + final hasAutoPause = main.hasLeaderOnPauseRequest() && videoList.length > 0 && getTime() > 1; if (hasAutoPause && !main.hasLeader()) { JsApi.once(SetLeader, event -> { @@ -255,10 +251,10 @@ class Player { ' ); - items.addItem(item, atEnd, itemPos); + videoList.addItem(item, atEnd); setItemElementType(itemEl, item.isTemp); if (atEnd) videoItemsEl.appendChild(itemEl); - else Utils.insertAtIndex(videoItemsEl, itemEl, itemPos + 1); + else Utils.insertAtIndex(videoItemsEl, itemEl, videoList.pos + 1); updateCounters(); } @@ -273,15 +269,15 @@ class Player { public function removeItem(url:String):Void { removeElementItem(url); - var index = items.findIndex(item -> item.url == url); + var index = videoList.findIndex(item -> item.url == url); if (index == -1) return; - final isCurrent = items[itemPos].url == url; - itemPos = items.removeItem(index, itemPos); + final isCurrent = videoList.getCurrentItem().url == url; + videoList.removeItem(index); updateCounters(); - if (isCurrent && items.length > 0) { - setVideo(itemPos); + if (isCurrent && videoList.length > 0) { + setVideo(videoList.pos); } } @@ -295,47 +291,64 @@ class Player { } public function skipItem(url:String):Void { - var index = items.findIndex(item -> item.url == url); - if (index == -1) return; - if (items[index].isTemp) removeElementItem(url); - index = items.skipItem(index); + final pos = videoList.findIndex(item -> item.url == url); + if (pos == -1) return; + removeActiveLabel(videoList.pos); + videoList.setPos(pos); + if (videoList.getCurrentItem().isTemp) removeElementItem(url); + videoList.skipItem(); updateCounters(); - if (items.length == 0) return; - setVideo(index); + if (videoList.length == 0) return; + setVideo(videoList.pos); + } + + function addActiveLabel(pos:Int):Void { + final childs = videoItemsEl.children; + if (childs[videoList.pos] != null) { + childs[videoList.pos].classList.add("queue_active"); + } + } + + function removeActiveLabel(pos:Int):Void { + final childs = videoItemsEl.children; + if (childs[videoList.pos] != null) { + childs[videoList.pos].classList.remove("queue_active"); + } } function updateCounters():Void { - ge("#plcount").textContent = '${items.length} ${Lang.get("videos")}'; + ge("#plcount").textContent = '${videoList.length} ${Lang.get("videos")}'; ge("#pllength").textContent = totalDuration(); } - public function getItems():VideoList { - return items; + public function getItems():Array { + return videoList.getItems(); } public function setItems(list:Array, ?pos:Int):Void { - final currentUrl = itemPos >= items.length ? "" : items[itemPos].url; + final currentUrl = videoList.pos >= videoList.length ? "" : videoList.getCurrentItem() + .url; clearItems(); - if (pos != null) itemPos = pos; + if (pos != null) videoList.setPos(pos); if (list.length == 0) return; for (video in list) { addVideoItem(video, true); } - if (currentUrl != items[itemPos].url) setVideo(itemPos); - else videoItemsEl.children[itemPos].classList.add("queue_active"); + if (currentUrl != videoList.getCurrentItem().url) setVideo(videoList.pos); + else addActiveLabel(videoList.pos); } public function clearItems():Void { - items.resize(0); + videoList.clear(); videoItemsEl.textContent = ""; updateCounters(); } public function refresh():Void { - if (items.length == 0) return; + if (videoList.length == 0) return; final time = getTime(); removeVideo(); - setVideo(itemPos); + setVideo(videoList.pos); // restore server time for leader with next GetTime if (main.isLeader()) { setTime(time); @@ -357,7 +370,7 @@ class Player { function totalDuration():String { var time = 0.0; - for (item in items) { + for (item in videoList.getItems()) { if (item.isIframe) continue; time += item.duration; } @@ -365,15 +378,15 @@ class Player { } public function isListEmpty():Bool { - return items.length == 0; + return videoList.length == 0; } public function itemsLength():Int { - return items.length; + return videoList.length; } public function getItemPos():Int { - return itemPos; + return videoList.pos; } public function hasVideo():Bool { @@ -381,8 +394,8 @@ class Player { } public function getDuration():Float { - if (itemPos >= items.length) return 0; - return items[itemPos].duration; + if (videoList.pos >= videoList.length) return 0; + return videoList.getCurrentItem().duration; } public function isVideoLoaded():Bool { diff --git a/src/client/players/Raw.hx b/src/client/players/Raw.hx index 4b78b0f..dc3aed5 100644 --- a/src/client/players/Raw.hx +++ b/src/client/players/Raw.hx @@ -127,6 +127,7 @@ class Raw implements IPlayer { if (Utils.isTouch()) return; if (controlsHider != null) controlsHider.stop(); controlsHider = Timer.delay(() -> { + if (video == null) return; video.controls = false; }, 3000); video.onmousemove = e -> { diff --git a/src/server/Main.hx b/src/server/Main.hx index 748c513..3ab0621 100644 --- a/src/server/Main.hx +++ b/src/server/Main.hx @@ -54,8 +54,6 @@ class Main { final videoTimer = new VideoTimer(); final messages:Array = []; final logger:Logger; - var isPlaylistOpen = true; - var itemPos = 0; static function main():Void { new Main({ @@ -245,9 +243,9 @@ class Main { function getCurrentState():ServerState { return { - videoList: videoList, - isPlaylistOpen: isPlaylistOpen, - itemPos: itemPos, + videoList: videoList.getItems(), + isPlaylistOpen: videoList.isOpen, + itemPos: videoList.pos, messages: messages, timer: { time: videoTimer.getTime(), @@ -261,13 +259,10 @@ class Main { if (!FileSystem.exists(statePath)) return; trace("Loading state..."); final data:ServerState = Json.parse(File.getContent(statePath)); - videoList.resize(0); + videoList.setItems(data.videoList); messages.resize(0); - for (item in data.videoList) { - videoList.push(item); - } - isPlaylistOpen = data.isPlaylistOpen; - itemPos = data.itemPos; + videoList.isOpen = data.isPlaylistOpen; + videoList.setPos(data.itemPos); for (message in data.messages) { messages.push(message); } @@ -428,9 +423,9 @@ class Main { isUnknownClient: true, clientName: client.name, clients: clientList(), - videoList: videoList, - isPlaylistOpen: isPlaylistOpen, - itemPos: itemPos, + videoList: videoList.getItems(), + isPlaylistOpen: videoList.isOpen, + itemPos: videoList.pos, globalIp: globalIp } }); @@ -574,7 +569,7 @@ class Main { case ServerMessage: case AddVideo: if (!checkPermission(client, AddVideoPerm)) return; - if (!isPlaylistOpen) { + if (!videoList.isOpen) { if (!checkPermission(client, LockPlaylistPerm)) return; } if (config.totalVideoLimit != 0 && videoList.length >= config.totalVideoLimit) { @@ -599,7 +594,7 @@ class Main { serverMessage(client, "videoAlreadyExistsError"); return; } - videoList.addItem(item, data.addVideo.atEnd, itemPos); + videoList.addItem(item, data.addVideo.atEnd); broadcast(data); // Initial timer start if VideoLoaded is not happen if (videoList.length == 1) restartWaitTimer(); @@ -615,8 +610,8 @@ class Main { var index = videoList.findIndex(item -> item.url == url); if (index == -1) return; - final isCurrent = videoList[itemPos].url == url; - itemPos = videoList.removeItem(index, itemPos); + final isCurrent = videoList.getCurrentItem().url == url; + videoList.removeItem(index); if (isCurrent && videoList.length > 0) { broadcast(data); restartWaitTimer(); @@ -656,11 +651,11 @@ class Main { case GetTime: if (videoList.length == 0) return; - final maxTime = videoList[itemPos].duration - 0.01; + final maxTime = videoList.getCurrentItem().duration - 0.01; if (videoTimer.getTime() > maxTime) { videoTimer.pause(); videoTimer.setTime(maxTime); - final skipUrl = videoList[itemPos].url; + final skipUrl = videoList.getCurrentItem().url; Timer.delay(() -> { skipVideo({ type: SkipVideo, @@ -756,15 +751,16 @@ class Main { case PlayItem: if (!checkPermission(client, ChangeOrderPerm)) return; - itemPos = data.playItem.pos; + videoList.setPos(data.playItem.pos); + data.playItem.pos = videoList.pos; restartWaitTimer(); broadcast(data); case SetNextItem: if (!checkPermission(client, ChangeOrderPerm)) return; final pos = data.setNextItem.pos; - if (pos == itemPos || pos == itemPos + 1) return; - itemPos = videoList.setNextItem(pos, itemPos); + if (pos == videoList.pos || pos == videoList.pos + 1) return; + videoList.setNextItem(pos); broadcast(data); case ToggleItemType: @@ -780,21 +776,17 @@ class Main { case ClearPlaylist: if (!checkPermission(client, RemoveVideoPerm)) return; videoTimer.stop(); - videoList.resize(0); - itemPos = 0; + videoList.clear(); broadcast(data); case ShufflePlaylist: if (!checkPermission(client, ChangeOrderPerm)) return; if (videoList.length == 0) return; - final current = videoList[itemPos]; - videoList.remove(current); - Utils.shuffle(videoList); - videoList.insert(itemPos, current); + videoList.shuffle(); broadcast({ type: UpdatePlaylist, updatePlaylist: { - videoList: videoList + videoList: videoList.getItems() } }); @@ -802,17 +794,17 @@ class Main { broadcast({ type: UpdatePlaylist, updatePlaylist: { - videoList: videoList + videoList: videoList.getItems() } }); case TogglePlaylistLock: if (!checkPermission(client, LockPlaylistPerm)) return; - isPlaylistOpen = !isPlaylistOpen; + videoList.isOpen = !videoList.isOpen; broadcast({ type: TogglePlaylistLock, togglePlaylistLock: { - isOpen: isPlaylistOpen + isOpen: videoList.isOpen } }); @@ -894,9 +886,9 @@ class Main { function skipVideo(data:WsEvent):Void { if (videoList.length == 0) return; - final item = videoList[itemPos]; + final item = videoList.getCurrentItem(); if (item.url != data.skipVideo.url) return; - itemPos = videoList.skipItem(itemPos); + videoList.skipItem(); if (videoList.length > 0) restartWaitTimer(); broadcast(data); } -- cgit v1.2.3