aboutsummaryrefslogtreecommitdiffstats
path: root/src/client
diff options
context:
space:
mode:
Diffstat (limited to 'src/client')
-rw-r--r--src/client/Player.hx2
-rw-r--r--src/client/players/Vk.hx228
2 files changed, 230 insertions, 0 deletions
diff --git a/src/client/Player.hx b/src/client/Player.hx
index 70efcf9..f51d017 100644
--- a/src/client/Player.hx
+++ b/src/client/Player.hx
@@ -8,6 +8,7 @@ import client.Main.ge;
import client.players.Iframe;
import client.players.Raw;
import client.players.Streamable;
+import client.players.Vk;
import client.players.Youtube;
import haxe.Http;
import haxe.Json;
@@ -42,6 +43,7 @@ class Player {
streamable = new Streamable(main, this);
players = [
youtube,
+ new Vk(main, this),
streamable,
];
iframePlayer = new Iframe(main, this);
diff --git a/src/client/players/Vk.hx b/src/client/players/Vk.hx
new file mode 100644
index 0000000..a2af220
--- /dev/null
+++ b/src/client/players/Vk.hx
@@ -0,0 +1,228 @@
+package client.players;
+
+import Types.PlayerType;
+import Types.VideoData;
+import Types.VideoDataRequest;
+import Types.VideoItem;
+import client.Main.ge;
+import haxe.Constraints.Function;
+import js.Browser.document;
+import js.html.Element;
+import js.html.Node;
+
+private enum abstract VkPlayerState(String) {
+ var Uninited = "uninited";
+ var Unstarted = "unstarted";
+ var Playing = "playing";
+ var Paused = "paused";
+ var Ended = "ended";
+ var Error = "error";
+}
+
+private extern class VkPlayer {
+ function play():Void;
+ function pause():Void;
+ function seek(time:Float):Void;
+ function seekLive():Void;
+ function setVolume(volume:Float):Void;
+ function getVolume():Float;
+ function getCurrentTime():Float;
+ function getDuration():Int;
+ function getQuality():Int; // 480, etc
+ function mute():Void;
+ function unmute():Void;
+ function isMuted():Bool;
+ function getState():VkPlayerState;
+ function on(event:String, listener:Function):Void;
+ function off(event:String, listener:Function):Void;
+ function destroy():Void;
+}
+
+class Vk implements IPlayer {
+ final main:Main;
+ final player:Player;
+ final playerEl:Element = ge("#ytapiplayer");
+ var video:Element;
+ var vkPlayer:VkPlayer;
+ var isLoaded = false;
+ var isApiLoaded = false;
+
+ public function new(main:Main, player:Player) {
+ this.main = main;
+ this.player = player;
+ }
+
+ public function getPlayerType():PlayerType {
+ return VkType;
+ }
+
+ final matchVk = ~/(vk.com\/video|vkvideo)/g;
+ final matchIds = ~/video(-?[0-9]+)_([0-9]+)/g;
+
+ public function isSupportedLink(url:String):Bool {
+ return matchVk.match(url) && getVideoIds(url) != null;
+ }
+
+ function getVideoIds(url:String):Null<{oid:String, id:String}> {
+ if (!matchIds.match(url)) {
+ trace("Cannot extract /video-oid_id values from url:");
+ return null;
+ }
+ final oid = matchIds.matched(1);
+ final id = matchIds.matched(2);
+ return {oid: oid, id: id};
+ }
+
+ function loadApi(callback:() -> Void):Void {
+ final url = "https://vk.com/js/api/videoplayer.js";
+ JsApi.addScriptToHead(url, () -> {
+ isApiLoaded = true;
+ callback();
+ });
+ }
+
+ function createVkPlayer(iframe:Node):VkPlayer {
+ return untyped VK.VideoPlayer(iframe);
+ }
+
+ public function getVideoData(data:VideoDataRequest, callback:(data:VideoData) -> Void):Void {
+ if (!isApiLoaded) {
+ loadApi(() -> {
+ getVideoData(data, callback);
+ });
+ return;
+ }
+ final url = data.url;
+
+ final video = document.createDivElement();
+ video.id = "temp-videoplayer";
+ final ids = getVideoIds(url);
+ if (ids == null) {
+ callback({duration: 0});
+ return;
+ }
+ final oid = ids.oid;
+ final id = ids.id;
+ video.innerHTML = '
+ <iframe src="https://vk.com/video_ext.php?oid=$oid&id=$id&hd=1&js_api=1"
+ allow="autoplay; encrypted-media; fullscreen; picture-in-picture;"
+ frameborder="0" allowfullscreen>
+ </iframe>
+ '.trim();
+ Utils.prepend(playerEl, video);
+ final tempVkPlayer = createVkPlayer(video.firstChild);
+ tempVkPlayer.on("inited", () -> {
+ callback({
+ duration: tempVkPlayer.getDuration(),
+ title: "VK media",
+ url: url
+ });
+ tempVkPlayer.destroy();
+ if (playerEl.contains(video)) playerEl.removeChild(video);
+ });
+ }
+
+ public function loadVideo(item:VideoItem):Void {
+ if (!isApiLoaded) {
+ loadApi(() -> {
+ loadVideo(item);
+ });
+ return;
+ }
+
+ removeVideo();
+
+ final ids = getVideoIds(item.url) ?? return;
+ video = document.createDivElement();
+ video.id = "videoplayer";
+ final oid = ids.oid;
+ final id = ids.id;
+ video.innerHTML = '
+ <iframe src="https://vk.com/video_ext.php?oid=$oid&id=$id&hd=4&js_api=1"
+ allow="autoplay; encrypted-media; fullscreen; picture-in-picture;"
+ frameborder="0" allowfullscreen>
+ </iframe>
+ '.trim();
+ playerEl.appendChild(video);
+ vkPlayer = createVkPlayer(video.firstChild);
+ vkPlayer.on("inited", () -> {
+ if (!main.isAutoplayAllowed()) vkPlayer.mute();
+ isLoaded = true;
+ vkPlayer.pause();
+ setTime(0);
+ player.onCanBePlayed();
+ });
+
+ vkPlayer.on("started", () -> {
+ player.onPlay();
+ });
+ vkPlayer.on("resumed", () -> {
+ player.onPlay();
+ });
+ vkPlayer.on("paused", () -> {
+ player.onPause();
+ });
+ vkPlayer.on("error", e -> {
+ trace('Error $e');
+ });
+ var prevTime = 0.0;
+ vkPlayer.on("timeupdate", (e:{time:Float}) -> {
+ final diff = Math.abs(prevTime - e.time);
+ prevTime = e.time;
+ if (diff > 1) player.onSetTime();
+ });
+ }
+
+ public function removeVideo():Void {
+ if (video == null) return;
+ isLoaded = false;
+ vkPlayer.destroy();
+ vkPlayer = null;
+ if (playerEl.contains(video)) playerEl.removeChild(video);
+ video = null;
+ }
+
+ public function isVideoLoaded():Bool {
+ return isLoaded;
+ }
+
+ public function play():Void {
+ vkPlayer.play();
+ }
+
+ public function pause():Void {
+ vkPlayer.pause();
+ }
+
+ public function isPaused():Bool {
+ final state = vkPlayer.getState();
+ return state == Unstarted || state == Paused;
+ }
+
+ public function getTime():Float {
+ return vkPlayer.getCurrentTime();
+ }
+
+ public function setTime(time:Float):Void {
+ vkPlayer.seek(time);
+ }
+
+ public function getPlaybackRate():Float {
+ return 1;
+ }
+
+ public function setPlaybackRate(rate:Float):Void {}
+
+ public function getVolume():Float {
+ if (vkPlayer.isMuted()) return 0;
+ return vkPlayer.getVolume();
+ }
+
+ public function setVolume(volume:Float):Void {
+ vkPlayer.setVolume(volume);
+ }
+
+ public function unmute():Void {
+ vkPlayer.unmute();
+ }
+}
send patches to the email below
yukais@pinapelz.com
include the subject [PATCH repo_name]
pinapelz.com
homepage