diff options
Diffstat (limited to 'src/client/Player.hx')
| -rw-r--r-- | src/client/Player.hx | 153 |
1 files changed, 116 insertions, 37 deletions
diff --git a/src/client/Player.hx b/src/client/Player.hx index 68b1a4a..4e1b8a6 100644 --- a/src/client/Player.hx +++ b/src/client/Player.hx @@ -9,14 +9,17 @@ import client.players.Iframe; import client.players.Peertube; import client.players.Raw; import client.players.Streamable; +import client.players.Vimeo; import client.players.Vk; import client.players.Youtube; import haxe.Http; import haxe.Json; import haxe.Timer; +import js.Browser.document; import js.html.Audio; import js.html.Element; import js.html.InputElement; +import js.html.MouseEvent; class Player { final main:Main; @@ -44,14 +47,16 @@ class Player { public function new(main:Main):Void { this.main = main; youtube = new Youtube(main, this); + iframePlayer = new Iframe(main, this); + rawPlayer = new Raw(main, this); players = [ youtube, + new Vimeo(main, this), new Vk(main, this), new Streamable(main, this), new Peertube(main, this), + iframePlayer, ]; - iframePlayer = new Iframe(main, this); - rawPlayer = new Raw(main, this); initItemButtons(); final resizeObserver = Utils.createResizeObserver(entries -> { @@ -73,11 +78,27 @@ class Player { // for some reason Chrome has ~300ms event delay Timer.delay(() -> inUserInteraction = false, 350); }, {}); + + playerEl.oncontextmenu = e -> { + if (!main.settings.fullscreenAction) return; + e.preventDefault(); + + final isPlayerFs = document.fullscreenElement == playerEl; + if (isPlayerFs) { + if (main.settings.pageFullscreen) { + Utils.switchToPageFullscreen(); + } else { + Utils.cancelFullscreen(); + } + } else { + Utils.requestFullscreen(playerEl); + } + } } function initItemButtons():Void { final queue = getEl("#queue"); - queue.onclick = e -> { + queue.onclick = (e:MouseEvent) -> { final btn:Element = cast e.target; final item = btn.parentElement.parentElement; final i = Utils.getIndex(item.parentElement, item); @@ -98,12 +119,16 @@ class Player { }); } if (btn.classList.contains("qbtn-tmp")) { - main.send({ - type: ToggleItemType, - toggleItemType: { - pos: i - } - }); + if (e.altKey || e.shiftKey) { + toggleAllItemTypes(i); + } else { + main.send({ + type: ToggleItemType, + toggleItemType: { + pos: i + } + }); + } } if (btn.classList.contains("qbtn-delete")) { main.removeVideoItem(item.querySelector(".qe_title").getAttribute("href")); @@ -111,6 +136,16 @@ class Player { } } + public function toggleAllItemTypes(pos:Int):Void { + main.send({ + type: ToggleItemType, + toggleItemType: { + pos: pos, + all: true + } + }); + } + public function setNextItem(pos:Int):Void { videoList.setNextItem(pos); @@ -183,11 +218,11 @@ class Player { public function setVideo(i:Int):Void { if (!main.isSyncActive) return; final item = videoList.getItem(i); + if (!item.isPlayable()) return; setSupportedPlayer(item.url, item.playerType); - removeActiveLabel(videoList.pos); videoList.setPos(i); - addActiveLabel(videoList.pos); + addActiveItemLabel(); canBePlayedSent = false; if (main.isVideoEnabled) { @@ -197,7 +232,7 @@ class Player { onCanBePlayed(); } JsApi.fireVideoChangeEvents(item); - getEl("#currenttitle").textContent = item.title; + updateTitle(); } function setExternalAudioTrack(item:VideoItem):Void { @@ -253,20 +288,36 @@ class Player { public function removeVideo():Void { JsApi.fireVideoRemoveEvents(videoList.currentItem); player.removeVideo(); - getEl("#currenttitle").textContent = Lang.get("nothingPlaying"); + updateTitle(); setPauseIndicator(false); } + public function updateTitle():Void { + final baseTitle = isListEmpty() ? Lang.get("nothingPlaying") : videoList.currentItem.title; + if (!main.lastState.paused) { + getEl("#currenttitle").textContent = baseTitle; + return; + } + var pauserName = Lang.get("server"); + if (!main.lastState.pausedByServer) { + final leader = main.getLeader(); + if (leader != null) pauserName = leader.name; + } + final prefix = Lang.get("pausedBy").replace("$NAME", pauserName); + final span = '<span class="paused-by">${prefix.htmlEscape()}</span>'; + getEl("#currenttitle").innerHTML = '$span ${baseTitle.htmlEscape()}'; + } + public function setPauseIndicator(isPause:Bool):Void { if (!main.isSyncActive) return; final state = isPause ? "pause" : "play"; - final el = getEl("#pause-indicator"); - el.setAttribute("name", state); - final el2 = getEl("#pause-indicator-portrait"); - el2.setAttribute("name", state); + final el = getEl("#pause-indicator-chat"); + el.setAttribute("name", state); var isVisible = isPause || main.hasLeader(); - el2.style.display = isVisible ? "" : "none"; + el.style.display = isVisible ? "" : "none"; + + updateTitle(); } public function onCanBePlayed():Void { @@ -415,10 +466,13 @@ class Player { public function addVideoItem(item:VideoItem, atEnd:Bool):Void { final url = item.url.htmlEscape(true); final duration = item.playerType == IframeType ? "" : duration(item.duration); - final author = item.author.htmlEscape(); + final author = item.author.htmlEscape(true); + final isIncomplete = item.isIncomplete == true; + final incompleteClass = isIncomplete ? " queue_incomplete" : ""; + final progressEl = isIncomplete ? '<div class="qe_progress"></div>' : ""; final itemEl = Utils.nodeFromString( - '<li class="queue_entry info" title="${Lang.get("addedBy")}: $author"> - <header> + '<li class="queue_entry info$incompleteClass" title="${Lang.get("addedBy")}: $author"> + $progressEl<header> <span class="qe_time">$duration</span> <h4><a class="qe_title" href="$url" target="_blank">${item.title.htmlEscape()}</a></h4> <small class="qe_author">${Lang.get("addedBy")}: $author</small> @@ -460,19 +514,44 @@ class Player { } } - function removeElementItem(url:String):Void { + function findItemElement(url:String):Null<Element> { for (child in videoItemsEl.children) { - if (child.querySelector(".qe_title").getAttribute("href") == url) { - videoItemsEl.removeChild(child); - break; - } + if (child.querySelector(".qe_title").getAttribute("href") == url) return child; + } + return null; + } + + function removeElementItem(url:String):Void { + final child = findItemElement(url) ?? return; + videoItemsEl.removeChild(child); + } + + public function setItemProgress(url:String, ratio:Float):Void { + final el = findItemElement(url) ?? return; + final bar = el.querySelector(".qe_progress") ?? return; + bar.style.width = '${ratio * 100}%'; + } + + public function completeItem(url:String):Void { + final index = videoList.findIndex(item -> item.url == url); + if (index == -1) return; + final item = videoList.getItem(index); + if (item.isIncomplete != true) return; + final wasPlayable = item.isPlayable(); + item.isIncomplete = false; + final el = findItemElement(url); + if (el != null) { + el.classList.remove("queue_incomplete"); + el.classList.add("queue_cached"); + final bar = el.querySelector(".qe_progress"); + if (bar != null) el.removeChild(bar); } + if (index == videoList.pos && !wasPlayable) setVideo(index); } public function skipItem(url:String):Void { final pos = videoList.findIndex(item -> item.url == url); if (pos == -1) return; - removeActiveLabel(videoList.pos); videoList.setPos(pos); if (videoList.currentItem.isTemp) removeElementItem(url); videoList.skipItem(); @@ -481,17 +560,17 @@ class Player { setVideo(videoList.pos); } - function addActiveLabel(pos:Int):Void { + function addActiveItemLabel():Void { final childs = videoItemsEl.children; - if (childs[videoList.pos] != null) { - childs[videoList.pos].classList.add("queue_active"); + final activeLabel = "queue_active"; + for (element in childs) { + if (element.classList.contains(activeLabel)) { + element.classList.remove(activeLabel); + break; + } } - } - - function removeActiveLabel(pos:Int):Void { - final childs = videoItemsEl.children; if (childs[videoList.pos] != null) { - childs[videoList.pos].classList.remove("queue_active"); + childs[videoList.pos].classList.add(activeLabel); } } @@ -513,7 +592,7 @@ class Player { } if (pos != null) videoList.setPos(pos); if (currentUrl != videoList.currentItem.url) setVideo(videoList.pos); - else addActiveLabel(videoList.pos); + else addActiveItemLabel(); } public function clearItems():Void { @@ -568,7 +647,7 @@ class Player { } public function hasVideo():Bool { - return playerEl.children.length != 0; + return playerEl.querySelector("video, iframe, embed, object") != null; } public function getDuration():Float { |
