aboutsummaryrefslogtreecommitdiffstats
path: root/src/client
diff options
context:
space:
mode:
Diffstat (limited to 'src/client')
-rw-r--r--src/client/IPlayer.hx12
-rw-r--r--src/client/Main.hx45
-rw-r--r--src/client/Player.hx218
-rw-r--r--src/client/players/Raw.hx72
4 files changed, 245 insertions, 102 deletions
diff --git a/src/client/IPlayer.hx b/src/client/IPlayer.hx
new file mode 100644
index 0000000..9f224a8
--- /dev/null
+++ b/src/client/IPlayer.hx
@@ -0,0 +1,12 @@
+package client;
+
+import Types.VideoItem;
+
+interface IPlayer {
+ function loadVideo(item:VideoItem):Void;
+ function removeVideo():Void;
+ function play():Void;
+ function pause():Void;
+ function getTime():Float;
+ function setTime(time:Float):Void;
+}
diff --git a/src/client/Main.hx b/src/client/Main.hx
index b2e224d..19ca44b 100644
--- a/src/client/Main.hx
+++ b/src/client/Main.hx
@@ -90,6 +90,18 @@ class Main {
}
});
}
+ final voteSkip = ge("#voteskip");
+ voteSkip.onclick = e -> {
+ if (player.isListEmpty()) return;
+ final items = player.getItems();
+ final pos = player.getItemPos();
+ send({
+ type: SkipVideo,
+ skipVideo: {
+ url: items[pos].url
+ }
+ });
+ }
ge("#queue_next").onclick = e -> addVideoUrl(false);
ge("#queue_end").onclick = e -> addVideoUrl(true);
@@ -112,23 +124,31 @@ class Main {
function addVideoUrl(atEnd:Bool):Void {
final mediaUrl:InputElement = cast ge("#mediaurl");
+ final checkbox:InputElement = cast ge("#addfromurl").querySelector(".add-temp");
+ final isTemp = checkbox.checked;
final url = mediaUrl.value;
if (url.length == 0) return;
mediaUrl.value = "";
final url = ~/,(https?)/g.replace(url, "|$1");
final links = url.split("|");
- // if videos added as next, we need to load it in reverse order
- final link = (atEnd || player.isListEmpty()) ? links.shift() : links.pop();
- addVideo(link, atEnd, () -> addVideoArray(links, atEnd));
+ // if videos added as next, we need to load them in reverse order
+ if (!atEnd) {
+ // except first item when list empty
+ var first:Null<String> = null;
+ if (player.isListEmpty()) first = links.shift();
+ links.reverse();
+ if (player.isListEmpty()) links.unshift(first);
+ }
+ addVideoArray(links, atEnd, isTemp);
}
- function addVideoArray(links:Array<String>, atEnd:Bool):Void {
+ function addVideoArray(links:Array<String>, atEnd:Bool, isTemp:Bool):Void {
if (links.length == 0) return;
- final link = atEnd ? links.shift() : links.pop();
- addVideo(link, atEnd, () -> addVideoArray(links, atEnd));
+ final link = links.shift();
+ addVideo(link, atEnd, isTemp, () -> addVideoArray(links, atEnd, isTemp));
}
- function addVideo(url:String, atEnd:Bool, callback:()->Void):Void {
+ function addVideo(url:String, atEnd:Bool, isTemp:Bool, callback:()->Void):Void {
final protocol = Browser.location.protocol;
if (url.startsWith("/")) {
final host = Browser.location.hostname;
@@ -153,6 +173,7 @@ class Main {
title: name,
author: personal.name,
duration: duration,
+ isTemp: isTemp
},
atEnd: atEnd
}});
@@ -163,7 +184,7 @@ class Main {
public function toggleVideoElement():Bool {
if (player.hasVideo()) player.removeVideo();
else if (!player.isListEmpty()) {
- player.setVideo(player.getItems()[0]);
+ player.setVideo(player.getItemPos());
}
return player.hasVideo();
}
@@ -231,8 +252,8 @@ class Main {
addMessage(data.message.clientName, data.message.text);
case AddVideo:
- if (player.isListEmpty()) player.setVideo(data.addVideo.item);
player.addVideoItem(data.addVideo.item, data.addVideo.atEnd);
+ if (player.itemsLength() == 1) player.setVideo(0);
case VideoLoaded:
player.setTime(0);
@@ -242,6 +263,10 @@ class Main {
player.removeItem(data.removeVideo.url);
if (player.isListEmpty()) player.pause();
+ case SkipVideo:
+ player.skipItem(data.skipVideo.url);
+ if (player.isListEmpty()) player.pause();
+
case Pause:
if (isLeader()) return;
player.pause();
@@ -318,7 +343,7 @@ class Main {
for (message in connected.history) {
addMessage(message.name, message.text, message.time);
}
- player.setItems(connected.videoList);
+ player.setItems(connected.videoList, connected.itemPos);
}
function setConfig(config:Config):Void {
diff --git a/src/client/Player.hx b/src/client/Player.hx
index d8e4cb4..2c8f62e 100644
--- a/src/client/Player.hx
+++ b/src/client/Player.hx
@@ -1,10 +1,9 @@
package client;
-import haxe.Timer;
import js.html.Element;
-import js.html.VideoElement;
import js.Browser.document;
import client.Main.ge;
+import client.players.Raw;
import Types.VideoItem;
using StringTools;
using Lambda;
@@ -14,76 +13,93 @@ class Player {
final main:Main;
final items:Array<VideoItem> = [];
final videoItemsEl = ge("#queue");
- final player:Element = ge("#ytapiplayer");
+ final playerEl:Element = ge("#ytapiplayer");
+ var player:Null<IPlayer>;
+ var currentSrc = "";
+ var itemPos = 0;
var isLoaded = false;
var skipSetTime = false;
- var video:VideoElement;
+ final matchYoutube = ~/v=([A-z0-9_-]+)/;
public function new(main:Main):Void {
this.main = main;
}
- public function setVideo(item:VideoItem):Void {
+ function setPlayer(player:IPlayer):Void {
+ this.player = player;
+ }
+
+ function isYoutube(url:String):Bool {
+ if (!url.contains("youtube.com/")) return false;
+ if (!url.contains("youtu.be/")) return false;
+ if (!matchYoutube.match(url)) return false;
+ return true;
+ }
+
+ public function setVideo(i:Int):Void {
+ final item = items[i];
+ if (isYoutube(item.url)) {} // setPlayer(new Youtube(main, this));
+ else setPlayer(new Raw(main, this));
+
+ final childs = videoItemsEl.children;
+ if (childs[itemPos] != null) {
+ childs[itemPos].classList.remove("queue_active");
+ }
+ itemPos = i;
+ childs[itemPos].classList.add("queue_active");
+
+ currentSrc = item.url;
+ playerEl.textContent = "";
isLoaded = false;
- video = document.createVideoElement();
- video.id = "videoplayer";
- item.url = main.tryLocalIp(item.url);
- video.src = item.url;
- video.controls = true;
- final isTouch = untyped __js__("'ontouchstart' in window");
- if (!isTouch) Timer.delay(() -> {
- video.controls = false;
- video.onmouseover = e -> {
- video.controls = true;
- video.onmouseover = null;
- video.onmousemove = null;
+ player.loadVideo(item);
+ ge("#currenttitle").textContent = item.title;
+ }
+
+ public function removeVideo():Void {
+ currentSrc = "";
+ player.removeVideo();
+ ge("#currenttitle").textContent = Lang.get("nothingPlaying");
+ }
+
+ public function onCanBePlayed():Void {
+ if (!isLoaded) main.send({type: VideoLoaded});
+ isLoaded = true;
+ }
+
+ public function onPlay():Void {
+ if (!main.isLeader()) return;
+ main.send({
+ type: Play, play: {
+ time: getTime()
}
- video.onmousemove = video.onmouseover;
- }, 3000);
- video.oncanplaythrough = e -> {
- if (!isLoaded) main.send({type: VideoLoaded});
- isLoaded = true;
- }
- video.onseeking = e -> {
- if (skipSetTime) {
- skipSetTime = false;
- return;
+ });
+ }
+
+ public function onPause():Void {
+ if (!main.isLeader()) return;
+ main.send({
+ type: Pause, pause: {
+ time: getTime()
}
- if (!main.isLeader()) return;
- main.send({
- type: SetTime,
- setTime: {
- time: video.currentTime
- }
- });
- }
- video.onpause = e -> {
- if (!main.isLeader()) return;
- main.send({
- type: Pause,
- pause: {
- time: video.currentTime
- }
- });
- }
- video.onplay = e -> {
- if (!main.isLeader()) return;
- main.send({
- type: Play,
- play: {
- time: video.currentTime
- }
- });
+ });
+ }
+
+ public function onSetTime():Void {
+ if (skipSetTime) {
+ skipSetTime = false;
+ return;
}
- player.textContent = "";
- player.appendChild(video);
- ge("#currenttitle").textContent = item.title;
+ if (!main.isLeader()) return;
+ main.send({
+ type: SetTime, setTime: {
+ time: getTime()
+ }
+ });
}
public function addVideoItem(item:VideoItem, atEnd:Bool):Void {
- items.push(item);
final itemEl = nodeFromString(
- '<li class="queue_entry pluid-0 queue_temp queue_active" title="${Lang.get("addedBy")}: ${item.author}">
+ '<li class="queue_entry pluid-0" title="${Lang.get("addedBy")}: ${item.author}">
<a class="qe_title" href="${item.url}" target="_blank">${item.title.htmlEscape()}</a>
<span class="qe_time">${duration(item.duration)}</span>
<div class="qe_clear"></div>
@@ -103,6 +119,7 @@ class Player {
</div>
</li>'
);
+ if (item.isTemp) itemEl.classList.add("queue_temp");
final deleteBtn = itemEl.querySelector("#btn-delete");
deleteBtn.onclick = e -> {
main.send({
@@ -112,18 +129,13 @@ class Player {
}
});
}
+ if (atEnd) items.push(item);
+ else items.insert(itemPos + 1, item);
if (atEnd) videoItemsEl.appendChild(itemEl);
- else Utils.insertAtIndex(videoItemsEl, itemEl, 1);
+ else Utils.insertAtIndex(videoItemsEl, itemEl, itemPos + 1);
updateCounters();
}
- public function removeVideo():Void {
- if (video == null) return;
- player.removeChild(video);
- video = null;
- ge("#currenttitle").textContent = Lang.get("nothingPlaying");
- }
-
public function removeItem(url:String):Void {
for (child in videoItemsEl.children) {
if (child.querySelector(".qe_title").getAttribute("href") == url) {
@@ -132,15 +144,32 @@ class Player {
}
}
- items.remove(
- items.find(item -> item.url == url)
- );
+ final item = items.find(item -> item.url == url);
+ if (item == null) return;
+ var index = items.indexOf(item);
+ items.remove(item);
updateCounters();
- if (video == null) return;
- if (video.src == url) {
- if (items.length > 0) setVideo(items[0]);
+ 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;
+ setVideo(index);
}
function updateCounters():Void {
@@ -152,15 +181,12 @@ class Player {
return items;
}
- public function setItems(list:Array<VideoItem>):Void {
+ public function setItems(list:Array<VideoItem>, ?pos:Int):Void {
clearItems();
+ if (pos != null) itemPos = pos;
if (list.length == 0) return;
- if (video == null || video.src != list[0].url) {
- setVideo(list[0]);
- }
- for (video in list) {
- addVideoItem(video, true);
- }
+ for (video in list) addVideoItem(video, true);
+ if (currentSrc != items[itemPos].url) setVideo(itemPos);
}
public function clearItems():Void {
@@ -172,7 +198,7 @@ class Player {
public function refresh():Void {
if (items.length == 0) return;
removeVideo();
- setVideo(items[0]);
+ setVideo(itemPos);
}
function duration(time:Float):String {
@@ -203,29 +229,37 @@ class Player {
return items.length == 0;
}
- public function hasVideo():Bool {
- return video != null;
+ public function itemsLength():Int {
+ return items.length;
}
- public function pause():Void {
- if (video == null) return;
- video.pause();
+ public function getItemPos():Int {
+ return itemPos;
+ }
+
+ public function hasVideo():Bool {
+ return player != null;
}
public function play():Void {
- if (video == null) return;
- video.play();
+ if (player == null) return;
+ player.play();
}
- public function setTime(time:Float, isLocal = true):Void {
- if (video == null) return;
- skipSetTime = isLocal;
- video.currentTime = time;
+ public function pause():Void {
+ if (player == null) return;
+ player.pause();
}
public function getTime():Float {
- if (video == null) return 0;
- return video.currentTime;
+ if (player == null) return 0;
+ return player.getTime();
+ }
+
+ public function setTime(time:Float, isLocal = true):Void {
+ if (player == null) return;
+ skipSetTime = isLocal;
+ player.setTime(time);
}
}
diff --git a/src/client/players/Raw.hx b/src/client/players/Raw.hx
new file mode 100644
index 0000000..41b421c
--- /dev/null
+++ b/src/client/players/Raw.hx
@@ -0,0 +1,72 @@
+package client.players;
+
+import haxe.Timer;
+import js.html.Element;
+import js.html.VideoElement;
+import js.Browser.document;
+import client.Main.ge;
+import Types.VideoItem;
+
+class Raw implements IPlayer {
+
+ final main:Main;
+ final player:Player;
+ var video:VideoElement;
+ final playerEl:Element = ge("#ytapiplayer");
+
+ public function new(main:Main, player:Player) {
+ this.main = main;
+ this.player = player;
+ }
+
+ public function loadVideo(item:VideoItem):Void {
+ video = document.createVideoElement();
+ video.id = "videoplayer";
+ final url = main.tryLocalIp(item.url);
+ video.src = url;
+ video.controls = true;
+ final isTouch = untyped __js__("'ontouchstart' in window");
+ if (!isTouch) Timer.delay(() -> {
+ video.controls = false;
+ video.onmouseover = e -> {
+ video.controls = true;
+ video.onmouseover = null;
+ video.onmousemove = null;
+ }
+ video.onmousemove = video.onmouseover;
+ }, 3000);
+ video.oncanplaythrough = player.onCanBePlayed;
+ video.onseeking = player.onSetTime;
+ video.onplay = player.onPlay;
+ video.onpause = player.onPause;
+ playerEl.appendChild(video);
+ video.pause();
+ }
+
+ public function removeVideo():Void {
+ if (video == null) return;
+ playerEl.removeChild(video);
+ video = null;
+ }
+
+ public function play():Void {
+ if (video == null) return;
+ video.play();
+ }
+
+ public function pause():Void {
+ if (video == null) return;
+ video.pause();
+ }
+
+ public function getTime():Float {
+ if (video == null) return 0;
+ return video.currentTime;
+ }
+
+ public function setTime(time:Float):Void {
+ if (video == null) return;
+ video.currentTime = time;
+ }
+
+}
send patches to the email below
yukais@pinapelz.com
include the subject [PATCH repo_name]
pinapelz.com
homepage