aboutsummaryrefslogtreecommitdiffstats
path: root/src/client
diff options
context:
space:
mode:
authorRblSb <msrblsb@gmail.com>2020-02-28 19:55:32 +0300
committerRblSb <msrblsb@gmail.com>2020-02-28 19:55:32 +0300
commitec7e4b5ad120828f1464cf4186287d4928b462a8 (patch)
tree6ea0accbe62983f3f174df9bf9ebc89bec17977a /src/client
parentc5903d5670dad72c840c30a302f8238c8cff9f8a (diff)
Youtube player support
Diffstat (limited to 'src/client')
-rw-r--r--src/client/IPlayer.hx1
-rw-r--r--src/client/Main.hx18
-rw-r--r--src/client/Player.hx21
-rw-r--r--src/client/players/Raw.hx17
-rw-r--r--src/client/players/Youtube.hx145
5 files changed, 175 insertions, 27 deletions
diff --git a/src/client/IPlayer.hx b/src/client/IPlayer.hx
index 9f224a8..a20b22b 100644
--- a/src/client/IPlayer.hx
+++ b/src/client/IPlayer.hx
@@ -3,6 +3,7 @@ package client;
import Types.VideoItem;
interface IPlayer {
+ function getRemoteDuration(url:String, callback:(duration:Float)->Void):Void;
function loadVideo(item:VideoItem):Void;
function removeVideo():Void;
function play():Void;
diff --git a/src/client/Main.hx b/src/client/Main.hx
index 1804ca1..d3271e9 100644
--- a/src/client/Main.hx
+++ b/src/client/Main.hx
@@ -161,7 +161,7 @@ class Main {
if (matchName.match(name)) name = matchName.matched(1);
else name = Lang.get("rawVideo");
- getRemoteVideoDuration(url, (duration:Float) -> {
+ player.getRemoteDuration(url, (duration:Float) -> {
if (duration == 0) {
serverMessage(4, Lang.get("addVideoError"));
return;
@@ -205,22 +205,6 @@ class Main {
return url.replace(globalIp, host);
}
- function getRemoteVideoDuration(src:String, callback:(duration:Float)->Void):Void {
- final player:Element = ge("#ytapiplayer");
- final video = document.createVideoElement();
- video.src = src;
- // TODO catch errors on AddVideo and getRemoteVideoDuration
- video.onerror = e -> {
- if (player.contains(video)) player.removeChild(video);
- callback(0);
- }
- video.onloadedmetadata = () -> {
- if (player.contains(video)) player.removeChild(video);
- callback(video.duration);
- }
- Utils.prepend(player, video);
- }
-
function onMessage(e):Void {
final data:WsEvent = Json.parse(e.data);
final t:String = cast data.type;
diff --git a/src/client/Player.hx b/src/client/Player.hx
index 3941bdb..7bd2f4e 100644
--- a/src/client/Player.hx
+++ b/src/client/Player.hx
@@ -4,9 +4,9 @@ import js.html.Element;
import js.Browser.document;
import client.Main.ge;
import client.players.Raw;
+import client.players.Youtube;
import Types.VideoItem;
using StringTools;
-using Lambda;
class Player {
@@ -19,7 +19,6 @@ class Player {
var itemPos = 0;
var isLoaded = false;
var skipSetTime = false;
- final matchYoutube = ~/v=([A-z0-9_-]+)/;
public function new(main:Main):Void {
this.main = main;
@@ -81,17 +80,21 @@ class Player {
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 getRemoteDuration(url:String, callback:(duration:Float)->Void):Void {
+ if (Youtube.isYoutube(url)) {
+ new Youtube(main, this).getRemoteDuration(url, callback);
+ } else {
+ new Raw(main, this).getRemoteDuration(url, callback);
+ }
}
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));
+ if (Youtube.isYoutube(item.url)) {
+ setPlayer(new Youtube(main, this));
+ } else {
+ setPlayer(new Raw(main, this));
+ }
final childs = videoItemsEl.children;
if (childs[itemPos] != null) {
diff --git a/src/client/players/Raw.hx b/src/client/players/Raw.hx
index 41b421c..1e5d245 100644
--- a/src/client/players/Raw.hx
+++ b/src/client/players/Raw.hx
@@ -11,14 +11,29 @@ class Raw implements IPlayer {
final main:Main;
final player:Player;
- var video:VideoElement;
final playerEl:Element = ge("#ytapiplayer");
+ var video:VideoElement;
public function new(main:Main, player:Player) {
this.main = main;
this.player = player;
}
+ public function getRemoteDuration(src:String, callback:(duration:Float)->Void):Void {
+ final video = document.createVideoElement();
+ video.src = src;
+ // TODO catch errors on AddVideo and getRemoteVideoDuration
+ video.onerror = e -> {
+ if (playerEl.contains(video)) playerEl.removeChild(video);
+ callback(0);
+ }
+ video.onloadedmetadata = () -> {
+ if (playerEl.contains(video)) playerEl.removeChild(video);
+ callback(video.duration);
+ }
+ Utils.prepend(playerEl, video);
+ }
+
public function loadVideo(item:VideoItem):Void {
video = document.createVideoElement();
video.id = "videoplayer";
diff --git a/src/client/players/Youtube.hx b/src/client/players/Youtube.hx
new file mode 100644
index 0000000..cba3fc4
--- /dev/null
+++ b/src/client/players/Youtube.hx
@@ -0,0 +1,145 @@
+package client.players;
+
+import js.html.Element;
+import js.Browser.document;
+import client.Main.ge;
+import js.youtube.Youtube as YtInit;
+import js.youtube.YoutubePlayer;
+import Types.VideoItem;
+using StringTools;
+
+class Youtube implements IPlayer {
+
+ static final matchId = ~/v=([A-z0-9_-]+)/;
+ static final matchShort = ~/youtu.be\/([A-z0-9_-]+)/;
+ static final matchEmbed = ~/embed\/([A-z0-9_-]+)/;
+ final main:Main;
+ final player:Player;
+ final playerEl:Element = ge("#ytapiplayer");
+ var video:Element;
+ var youtube:YoutubePlayer;
+ var isLoaded = false;
+
+ public function new(main:Main, player:Player) {
+ this.main = main;
+ this.player = player;
+ }
+
+ public static function isYoutube(url:String):Bool {
+ if (url.contains("youtu.be/")) {
+ return matchShort.match(url);
+ }
+ if (url.contains("youtube.com/embed/")) {
+ return matchEmbed.match(url);
+ }
+ if (!url.contains("youtube.com/")) return false;
+ return matchId.match(url);
+ }
+
+ function extractVideoId(url:String):String {
+ if (url.contains("youtu.be/")) {
+ matchShort.match(url);
+ return matchShort.matched(1);
+ }
+ if (url.contains("youtube.com/embed/")) {
+ matchEmbed.match(url);
+ return matchEmbed.matched(1);
+ }
+ matchId.match(url);
+ return matchId.matched(1);
+ }
+
+ public function getRemoteDuration(url:String, callback:(duration:Float)->Void):Void {
+ if (!YtInit.isLoadedAPI) {
+ YtInit.init(() -> getRemoteDuration(url, callback));
+ return;
+ }
+ final video = document.createDivElement();
+ video.id = "temp-videoplayer";
+ Utils.prepend(playerEl, video);
+ youtube = new YoutubePlayer(video.id, {
+ videoId: extractVideoId(url),
+ playerVars: {
+ modestbranding: 1,
+ rel: 0,
+ showinfo: 0
+ },
+ events: {
+ onReady: e -> {
+ if (playerEl.contains(video)) playerEl.removeChild(video);
+ callback(youtube.getDuration());
+ },
+ onError: e -> {
+ trace('Error ${e.data}');
+ if (playerEl.contains(video)) playerEl.removeChild(video);
+ callback(0);
+ }
+ }
+ });
+ }
+
+ public function loadVideo(item:VideoItem):Void {
+ if (!YtInit.isLoadedAPI) {
+ YtInit.init(() -> loadVideo(item));
+ return;
+ }
+ video = document.createDivElement();
+ video.id = "videoplayer";
+ playerEl.appendChild(video);
+
+ youtube = new YoutubePlayer(video.id, {
+ videoId: extractVideoId(item.url),
+ playerVars: {
+ autoplay: 1,
+ modestbranding: 1,
+ rel: 0,
+ showinfo: 0,
+ },
+ events: {
+ // onReady: e -> player.onCanBePlayed(),
+ onStateChange: e -> {
+ switch (e.data) {
+ case UNSTARTED:
+ isLoaded = true;
+ player.onCanBePlayed();
+ case ENDED:
+ case PLAYING:
+ player.onPlay();
+ case PAUSED:
+ player.onPause();
+ case BUFFERING:
+ player.onSetTime();
+ case CUED:
+ }
+ }
+ }
+ });
+ }
+
+ public function removeVideo():Void {
+ if (video == null) return;
+ playerEl.removeChild(video);
+ video = null;
+ }
+
+ public function play():Void {
+ if (!isLoaded) return;
+ youtube.playVideo();
+ }
+
+ public function pause():Void {
+ if (!isLoaded) return;
+ youtube.pauseVideo();
+ }
+
+ public function getTime():Float {
+ if (!isLoaded) return 0;
+ return youtube.getCurrentTime();
+ }
+
+ public function setTime(time:Float):Void {
+ if (!isLoaded) return;
+ youtube.seekTo((time : Any), true);
+ }
+
+}
send patches to the email below
yukais@pinapelz.com
include the subject [PATCH repo_name]
pinapelz.com
homepage