aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--README.md4
-rw-r--r--build-client.hxml1
-rw-r--r--build-server.hxml1
-rw-r--r--res/client.js53
-rw-r--r--src/client/JsApi.hx2
-rw-r--r--src/client/players/Raw.hx32
6 files changed, 85 insertions, 8 deletions
diff --git a/README.md b/README.md
index 6eaf05b..56558cb 100644
--- a/README.md
+++ b/README.md
@@ -15,8 +15,8 @@ Default channel example: http://synctube-example.herokuapp.com/
- Reworked Modern theme
### Supported players
-- Youtube (videos and playlists)
-- Raw mp4 videos (or any other media format supported in browser)
+- Youtube (videos, streams and playlists)
+- Raw mp4 videos and m3u8 playlists (or any other media format supported in browser)
- Iframes (without sync)
### Setup
diff --git a/build-client.hxml b/build-client.hxml
index 40a0df1..7d2e943 100644
--- a/build-client.hxml
+++ b/build-client.hxml
@@ -1,4 +1,5 @@
-lib youtubeIFramePlayer:git:https://github.com/okawa-h/youtubeIFramePlayer-externs.git
+-lib hls.js-extern:git:https://github.com/grosmar/hls.js-haxe-extern.git
-cp src
--main client.Main
-D analyzer-optimize
diff --git a/build-server.hxml b/build-server.hxml
index 1cd9607..abca82d 100644
--- a/build-server.hxml
+++ b/build-server.hxml
@@ -3,6 +3,7 @@
-lib json2object
# Client libs for completion
-lib youtubeIFramePlayer:git:https://github.com/okawa-h/youtubeIFramePlayer-externs.git
+-lib hls.js-extern:git:https://github.com/grosmar/hls.js-haxe-extern.git
-lib utest
-cp src
--main server.Main
diff --git a/res/client.js b/res/client.js
index 6d00cff..2093e37 100644
--- a/res/client.js
+++ b/res/client.js
@@ -2281,7 +2281,9 @@ client_players_Iframe.prototype = {
}
};
var client_players_Raw = function(main,player) {
+ this.isHlsLoaded = false;
this.playAllowed = true;
+ this.matchName = new EReg("^(.+)\\.(.+)","");
this.playerEl = window.document.querySelector("#ytapiplayer");
this.main = main;
this.player = player;
@@ -2293,13 +2295,21 @@ client_players_Raw.prototype = {
}
,getVideoData: function(url,callback) {
var _gthis = this;
- var title = HxOverrides.substr(url,url.lastIndexOf("/") + 1,null);
- var matchName = new EReg("^(.+)\\.","");
- if(matchName.match(title)) {
- title = matchName.matched(1);
+ var pos = url.lastIndexOf("/") + 1;
+ var title = HxOverrides.substr(url,pos,null);
+ if(this.matchName.match(title)) {
+ title = this.matchName.matched(1);
} else {
title = Lang.get("rawVideo");
}
+ var isHls = this.matchName.matched(2).indexOf("m3u8") != -1;
+ if(isHls && !this.isHlsLoaded) {
+ this.loadHlsPlugin(function() {
+ _gthis.getVideoData(url,callback);
+ return;
+ });
+ return;
+ }
var video = window.document.createElement("video");
video.src = url;
video.onerror = function(e) {
@@ -2317,12 +2327,42 @@ client_players_Raw.prototype = {
return;
};
client_Utils.prepend(this.playerEl,video);
+ if(isHls) {
+ this.initHlsSource(video,url);
+ }
+ }
+ ,loadHlsPlugin: function(callback) {
+ var _gthis = this;
+ client_JsApi.addScriptToHead("https://cdn.jsdelivr.net/npm/hls.js@latest",function() {
+ _gthis.isHlsLoaded = true;
+ callback();
+ return;
+ });
+ }
+ ,initHlsSource: function(video,url) {
+ if(!Hls.isSupported()) {
+ return;
+ }
+ var hls = new Hls();
+ hls.loadSource(url);
+ hls.attachMedia(video);
}
,loadVideo: function(item) {
var _gthis = this;
var url = this.main.tryLocalIp(item.url);
+ var isHls = item.url.indexOf("m3u8") != -1;
+ if(isHls && !this.isHlsLoaded) {
+ this.loadHlsPlugin(function() {
+ _gthis.loadVideo(item);
+ return;
+ });
+ return;
+ }
if(this.video != null) {
this.video.src = url;
+ if(isHls) {
+ this.initHlsSource(this.video,url);
+ }
this.restartControlsHider();
return;
}
@@ -2340,6 +2380,9 @@ client_players_Raw.prototype = {
this.video.onpause = ($_=this.player,$bind($_,$_.onPause));
this.video.onratechange = ($_=this.player,$bind($_,$_.onRateChange));
this.playerEl.appendChild(this.video);
+ if(isHls) {
+ this.initHlsSource(this.video,url);
+ }
}
,restartControlsHider: function() {
var _gthis = this;
@@ -3266,6 +3309,8 @@ js_Browser.createXMLHttpRequest = function() {
}
throw new js__$Boot_HaxeError("Unable to create XMLHttpRequest object.");
};
+var js_hlsjs_HlsConfig = function() { };
+js_hlsjs_HlsConfig.__name__ = true;
var js_youtube_Youtube = function() { };
js_youtube_Youtube.__name__ = true;
js_youtube_Youtube.init = function(onAPIReady) {
diff --git a/src/client/JsApi.hx b/src/client/JsApi.hx
index 8a6315c..071dbee 100644
--- a/src/client/JsApi.hx
+++ b/src/client/JsApi.hx
@@ -36,7 +36,7 @@ class JsApi {
}
@:expose
- static function addScriptToHead(url:String, ?onLoaded:()->Void):Void {
+ public static function addScriptToHead(url:String, ?onLoaded:()->Void):Void {
var script = document.createScriptElement();
script.type = "text/javascript";
script.onload = onLoaded;
diff --git a/src/client/players/Raw.hx b/src/client/players/Raw.hx
index 266f0a2..d8aa57b 100644
--- a/src/client/players/Raw.hx
+++ b/src/client/players/Raw.hx
@@ -1,5 +1,6 @@
package client.players;
+import js.hlsjs.Hls;
import haxe.Timer;
import js.html.Element;
import js.html.VideoElement;
@@ -7,15 +8,18 @@ import js.Browser.document;
import client.Main.ge;
import Types.VideoData;
import Types.VideoItem;
+using StringTools;
class Raw implements IPlayer {
final main:Main;
final player:Player;
final playerEl:Element = ge("#ytapiplayer");
+ final matchName = ~/^(.+)\.(.+)/;
var controlsHider:Timer;
var playAllowed = true;
var video:VideoElement;
+ var isHlsLoaded = false;
public function new(main:Main, player:Player) {
this.main = main;
@@ -28,9 +32,13 @@ class Raw implements IPlayer {
public function getVideoData(url:String, callback:(data:VideoData)->Void):Void {
var title = url.substr(url.lastIndexOf("/") + 1);
- final matchName = ~/^(.+)\./;
if (matchName.match(title)) title = matchName.matched(1);
else title = Lang.get("rawVideo");
+ final isHls = matchName.matched(2).contains("m3u8");
+ if (isHls && !isHlsLoaded) {
+ loadHlsPlugin(() -> getVideoData(url, callback));
+ return;
+ }
final video = document.createVideoElement();
video.src = url;
@@ -46,12 +54,33 @@ class Raw implements IPlayer {
});
}
Utils.prepend(playerEl, video);
+ if (isHls) initHlsSource(video, url);
+ }
+
+ function loadHlsPlugin(callback:()->Void):Void {
+ JsApi.addScriptToHead("https://cdn.jsdelivr.net/npm/hls.js@latest", () -> {
+ isHlsLoaded = true;
+ callback();
+ });
+ }
+
+ function initHlsSource(video:VideoElement, url:String):Void {
+ if (!Hls.isSupported()) return;
+ final hls = new Hls();
+ hls.loadSource(url);
+ hls.attachMedia(video);
}
public function loadVideo(item:VideoItem):Void {
final url = main.tryLocalIp(item.url);
+ final isHls = item.url.contains("m3u8");
+ if (isHls && !isHlsLoaded) {
+ loadHlsPlugin(() -> loadVideo(item));
+ return;
+ }
if (video != null) {
video.src = url;
+ if (isHls) initHlsSource(video, url);
restartControlsHider();
return;
}
@@ -68,6 +97,7 @@ class Raw implements IPlayer {
video.onpause = player.onPause;
video.onratechange = player.onRateChange;
playerEl.appendChild(video);
+ if (isHls) initHlsSource(video, url);
}
function restartControlsHider():Void {
send patches to the email below
yukais@pinapelz.com
include the subject [PATCH repo_name]
pinapelz.com
homepage