aboutsummaryrefslogtreecommitdiffstats
path: root/src/client/Player.hx
diff options
context:
space:
mode:
Diffstat (limited to 'src/client/Player.hx')
-rw-r--r--src/client/Player.hx153
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 {
send patches to the email below
yukais@pinapelz.com
include the subject [PATCH repo_name]
pinapelz.com
homepage