aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorRblSb <msrblsb@gmail.com>2021-01-24 13:12:58 +0300
committerRblSb <msrblsb@gmail.com>2021-01-24 13:12:58 +0300
commit35beab11cdccf09dc77917a795b033314e62a5b1 (patch)
tree23134d53f46ac678742f7fc4095b66dd68010617
parent3444b413ab12783c85ce73df9931142fea11b749 (diff)
Video title input
-rw-r--r--res/client.js117
-rw-r--r--res/css/des.css18
-rw-r--r--res/index.html9
-rw-r--r--src/client/Buttons.hx17
-rw-r--r--src/client/InputWithHistory.hx21
-rw-r--r--src/client/Main.hx13
-rw-r--r--src/client/Player.hx4
-rw-r--r--src/client/players/Raw.hx27
8 files changed, 191 insertions, 35 deletions
diff --git a/res/client.js b/res/client.js
index 1a0f9d3..071ad2c 100644
--- a/res/client.js
+++ b/res/client.js
@@ -99,6 +99,13 @@ HxOverrides.dateStr = function(date) {
var s = date.getSeconds();
return date.getFullYear() + "-" + (m < 10 ? "0" + m : "" + m) + "-" + (d < 10 ? "0" + d : "" + d) + " " + (h < 10 ? "0" + h : "" + h) + ":" + (mi < 10 ? "0" + mi : "" + mi) + ":" + (s < 10 ? "0" + s : "" + s);
};
+HxOverrides.cca = function(s,index) {
+ var x = s.charCodeAt(index);
+ if(x != x) {
+ return undefined;
+ }
+ return x;
+};
HxOverrides.substr = function(s,pos,len) {
if(len == null) {
len = s.length;
@@ -334,6 +341,37 @@ StringTools.endsWith = function(s,end) {
return false;
}
};
+StringTools.isSpace = function(s,pos) {
+ var c = HxOverrides.cca(s,pos);
+ if(!(c > 8 && c < 14)) {
+ return c == 32;
+ } else {
+ return true;
+ }
+};
+StringTools.ltrim = function(s) {
+ var l = s.length;
+ var r = 0;
+ while(r < l && StringTools.isSpace(s,r)) ++r;
+ if(r > 0) {
+ return HxOverrides.substr(s,r,l - r);
+ } else {
+ return s;
+ }
+};
+StringTools.rtrim = function(s) {
+ var l = s.length;
+ var r = 0;
+ while(r < l && StringTools.isSpace(s,l - r - 1)) ++r;
+ if(r > 0) {
+ return HxOverrides.substr(s,0,l - r);
+ } else {
+ return s;
+ }
+};
+StringTools.trim = function(s) {
+ return StringTools.ltrim(StringTools.rtrim(s));
+};
StringTools.replace = function(s,sub,by) {
return s.split(sub).join(by);
};
@@ -557,10 +595,19 @@ client_Buttons.init = function(main) {
showCustomEmbed.onclick = function(e) {
client_Buttons.showPlayerGroup(showCustomEmbed);
};
+ var mediaUrl = window.document.querySelector("#mediaurl");
+ mediaUrl.oninput = function() {
+ var value = mediaUrl.value;
+ if(value != "" && main.isRawPlayerLink(value) && main.isSingleVideoLink(value)) {
+ return window.document.querySelector("#mediatitleblock").style.display = "";
+ } else {
+ return window.document.querySelector("#mediatitleblock").style.display = "none";
+ }
+ };
+ mediaUrl.onfocus = mediaUrl.oninput;
window.document.querySelector("#insert_template").onclick = function(e) {
- var input = window.document.querySelector("#mediaurl");
- input.value = main.getTemplateUrl();
- input.focus();
+ mediaUrl.value = main.getTemplateUrl();
+ mediaUrl.focus();
};
var showOptions = window.document.querySelector("#showoptions");
showOptions.onclick = function(e) {
@@ -793,6 +840,7 @@ client_InputWithHistory.prototype = {
}
this.historyId = -1;
this.element.value = "";
+ this.onInput();
break;
case 38:
this.historyId--;
@@ -805,6 +853,7 @@ client_InputWithHistory.prototype = {
this.historyId++;
}
this.element.value = this.history[this.historyId];
+ this.onInput();
break;
case 40:
if(this.historyId == -1) {
@@ -814,10 +863,17 @@ client_InputWithHistory.prototype = {
if(this.historyId > this.history.length - 1) {
this.historyId = -1;
this.element.value = "";
- return;
+ } else {
+ this.element.value = this.history[this.historyId];
}
- this.element.value = this.history[this.historyId];
+ this.onInput();
break;
+ default:
+ }
+ }
+ ,onInput: function() {
+ if(this.element.oninput != null) {
+ this.element.oninput();
}
}
};
@@ -1025,6 +1081,11 @@ client_Main.prototype = {
_gthis.addVideoUrl(true);
return false;
});
+ window.document.querySelector("#mediatitle").onkeydown = function(e) {
+ if(e.keyCode == 13) {
+ _gthis.addVideoUrl(true);
+ }
+ };
window.document.querySelector("#ce_queue_next").onclick = function(e) {
_gthis.addIframe(false);
};
@@ -1080,6 +1141,18 @@ client_Main.prototype = {
}
this.addVideoArray(links,atEnd,isTemp);
}
+ ,isRawPlayerLink: function(url) {
+ return this.player.isRawPlayerLink(url);
+ }
+ ,isSingleVideoLink: function(url) {
+ if(new EReg(", ?(https?)","g").match(url)) {
+ return false;
+ }
+ if(this.mask.match(url)) {
+ return false;
+ }
+ return true;
+ }
,sortItemsForQueueNext: function(items) {
if(items.length == 0) {
return;
@@ -1186,7 +1259,7 @@ client_Main.prototype = {
var data = JSON.parse(e.data);
if(this.config != null && this.config.isVerbose) {
var t = data.type;
- haxe_Log.trace("Event: " + data.type,{ fileName : "src/client/Main.hx", lineNumber : 334, className : "client.Main", methodName : "onMessage", customParams : [Reflect.field(data,t.charAt(0).toLowerCase() + HxOverrides.substr(t,1,null))]});
+ haxe_Log.trace("Event: " + data.type,{ fileName : "src/client/Main.hx", lineNumber : 347, className : "client.Main", methodName : "onMessage", customParams : [Reflect.field(data,t.charAt(0).toLowerCase() + HxOverrides.substr(t,1,null))]});
}
client_JsApi.fireOnceEvent(data);
switch(data.type) {
@@ -1803,6 +1876,11 @@ client_Player.prototype = {
}
player.getVideoData(data,callback);
}
+ ,isRawPlayerLink: function(url) {
+ return !Lambda.exists(this.players,function(player) {
+ return player.isSupportedLink(url);
+ });
+ }
,getIframeData: function(data,callback) {
this.iframePlayer.getVideoData(data,callback);
}
@@ -2351,9 +2429,12 @@ client_players_Raw.prototype = {
var _gthis = this;
var url = data.url;
var decodedUrl = decodeURIComponent(url.split("+").join(" "));
+ var optTitle = this.cutOptionalTitle();
var title = HxOverrides.substr(decodedUrl,decodedUrl.lastIndexOf("/") + 1,null);
var isNameMatched = this.matchName.match(title);
- if(isNameMatched) {
+ if(optTitle != "") {
+ title = optTitle;
+ } else if(isNameMatched) {
title = this.matchName.matched(1);
} else {
title = Lang.get("rawVideo");
@@ -2361,12 +2442,14 @@ client_players_Raw.prototype = {
var isHls = false;
if(isNameMatched) {
isHls = this.matchName.matched(2).indexOf("m3u8") != -1;
- if(isHls && !this.isHlsLoaded) {
- this.loadHlsPlugin(function() {
- _gthis.getVideoData(data,callback);
- });
- return;
- }
+ } else {
+ isHls = StringTools.endsWith(title,"m3u8");
+ }
+ if(isHls && !this.isHlsLoaded) {
+ this.loadHlsPlugin(function() {
+ _gthis.getVideoData(data,callback);
+ });
+ return;
}
var video = window.document.createElement("video");
video.src = url;
@@ -2387,6 +2470,12 @@ client_players_Raw.prototype = {
this.initHlsSource(video,url);
}
}
+ ,cutOptionalTitle: function() {
+ var titleInput = window.document.querySelector("#mediatitle");
+ var optTitle = StringTools.trim(titleInput.value);
+ titleInput.value = "";
+ return optTitle;
+ }
,loadHlsPlugin: function(callback) {
var _gthis = this;
client_JsApi.addScriptToHead("https://cdn.jsdelivr.net/npm/hls.js@latest",function() {
@@ -2405,7 +2494,7 @@ client_players_Raw.prototype = {
,loadVideo: function(item) {
var _gthis = this;
var url = this.main.tryLocalIp(item.url);
- var isHls = item.url.indexOf("m3u8") != -1;
+ var isHls = item.url.indexOf("m3u8") != -1 || StringTools.endsWith(item.title,"m3u8");
if(isHls && !this.isHlsLoaded) {
this.loadHlsPlugin(function() {
_gthis.loadVideo(item);
diff --git a/res/css/des.css b/res/css/des.css
index 70a5019..aa423bd 100644
--- a/res/css/des.css
+++ b/res/css/des.css
@@ -223,6 +223,10 @@ button.danger-bg:focus {
visibility: visible;
}
+.display-flex {
+ display: flex;
+}
+
/* Info */
.info {
@@ -342,6 +346,15 @@ header h4 {
/* Add video */
+#insert_template {
+ min-width: 2rem;
+}
+
+#insert_template > div:first-child {
+ text-align: center;
+ flex-grow: 1;
+}
+
#addfromurl,
#customembed {
padding: 1rem;
@@ -354,8 +367,9 @@ header h4 {
margin-bottom: 1rem;
}
-#addfromurl > div:first-child {
- display: flex;
+#mediatitle {
+ margin-left: 2rem;
+ flex-grow: 1;
}
#mediaurl {
diff --git a/res/index.html b/res/index.html
index d901198..753a9a5 100644
--- a/res/index.html
+++ b/res/index.html
@@ -55,10 +55,15 @@
</div>
<!-- Add video -->
<div class="collapse" id="addfromurl" aria-expanded="false">
- <div>
- <button id="insert_template" title="${addTemplateUrl}">&gt;</button>
+ <div class="display-flex">
+ <button id="insert_template" title="${addTemplateUrl}">
+ <div>&gt;</div>
+ </button>
<input id="mediaurl" type="text" placeholder="${addVideoFromUrl}">
</div>
+ <div id="mediatitleblock" class="display-flex" style="display: none;">
+ <input id="mediatitle" type="text" placeholder="${optionalTitle}">
+ </div>
<div>
<button id="queue_next">${queueNext}</button>
<button id="queue_end">${queueLast}</button>
diff --git a/src/client/Buttons.hx b/src/client/Buttons.hx
index cdc9780..538aaa0 100644
--- a/src/client/Buttons.hx
+++ b/src/client/Buttons.hx
@@ -8,6 +8,7 @@ import js.html.Element;
import client.Main.ge;
import js.Browser.window;
import js.Browser.document;
+using StringTools;
class Buttons {
@@ -150,10 +151,20 @@ class Buttons {
final showCustomEmbed = ge("#showcustomembed");
showCustomEmbed.onclick = e -> showPlayerGroup(showCustomEmbed);
+ final mediaUrl:InputElement = cast ge("#mediaurl");
+ mediaUrl.oninput = () -> {
+ final value = mediaUrl.value;
+ if (value != "" && main.isRawPlayerLink(value) && main.isSingleVideoLink(value)) {
+ ge("#mediatitleblock").style.display = "";
+ } else {
+ ge("#mediatitleblock").style.display = "none";
+ }
+ }
+ mediaUrl.onfocus = mediaUrl.oninput;
+
ge("#insert_template").onclick = e -> {
- final input:InputElement = cast ge("#mediaurl");
- input.value = main.getTemplateUrl();
- input.focus();
+ mediaUrl.value = main.getTemplateUrl();
+ mediaUrl.focus();
}
final showOptions = ge("#showoptions");
diff --git a/src/client/InputWithHistory.hx b/src/client/InputWithHistory.hx
index ecba43a..c4e8bf4 100644
--- a/src/client/InputWithHistory.hx
+++ b/src/client/InputWithHistory.hx
@@ -29,8 +29,9 @@ class InputWithHistory {
}
function onKeyDown(e:KeyboardEvent) {
- switch (e.keyCode) {
- case 13: // Enter
+ final key:KeyCode = cast e.keyCode;
+ switch (key) {
+ case Return:
final value = element.value;
if (value.length == 0) return;
final isAdd = onEnter(value);
@@ -38,23 +39,31 @@ class InputWithHistory {
if (history.length > maxItems) history.shift();
historyId = -1;
element.value = "";
- case 38: // Up
+ onInput();
+ case Up:
historyId--;
if (historyId == -2) {
historyId = history.length - 1;
if (historyId == -1) return;
} else if (historyId == -1) historyId++;
element.value = history[historyId];
- case 40: // Down
+ onInput();
+ case Down:
if (historyId == -1) return;
historyId++;
if (historyId > history.length - 1) {
historyId = -1;
element.value = "";
- return;
+ } else {
+ element.value = history[historyId];
}
- element.value = history[historyId];
+ onInput();
+ default:
}
}
+ function onInput():Void {
+ if (element.oninput != null) element.oninput();
+ }
+
}
diff --git a/src/client/Main.hx b/src/client/Main.hx
index 5c29d29..31558eb 100644
--- a/src/client/Main.hx
+++ b/src/client/Main.hx
@@ -146,6 +146,9 @@ class Main {
addVideoUrl(true);
return false;
});
+ ge("#mediatitle").onkeydown = (e:KeyboardEvent) -> {
+ if (e.keyCode == KeyCode.Return) addVideoUrl(true);
+ }
ge("#ce_queue_next").onclick = e -> addIframe(false);
ge("#ce_queue_end").onclick = e -> addIframe(true);
@@ -210,6 +213,16 @@ class Main {
addVideoArray(links, atEnd, isTemp);
}
+ public function isRawPlayerLink(url:String):Bool {
+ return player.isRawPlayerLink(url);
+ }
+
+ public function isSingleVideoLink(url:String):Bool {
+ if (~/, ?(https?)/g.match(url)) return false;
+ if (mask.match(url)) return false;
+ return true;
+ }
+
public function sortItemsForQueueNext<T>(items:Array<T>):Void {
if (items.length == 0) return;
// except first item when list empty
diff --git a/src/client/Player.hx b/src/client/Player.hx
index 59ca11f..9ee3ead 100644
--- a/src/client/Player.hx
+++ b/src/client/Player.hx
@@ -104,6 +104,10 @@ class Player {
player.getVideoData(data, callback);
}
+ public function isRawPlayerLink(url:String):Bool {
+ return !players.exists(player -> player.isSupportedLink(url));
+ }
+
public function getIframeData(data:VideoDataRequest, callback:(data:VideoData)->Void):Void {
iframePlayer.getVideoData(data, callback);
}
diff --git a/src/client/players/Raw.hx b/src/client/players/Raw.hx
index 9a9d52e..fdb5e73 100644
--- a/src/client/players/Raw.hx
+++ b/src/client/players/Raw.hx
@@ -3,6 +3,7 @@ package client.players;
import js.hlsjs.Hls;
import haxe.Timer;
import js.html.Element;
+import js.html.InputElement;
import js.html.VideoElement;
import js.Browser.document;
import client.Main.ge;
@@ -34,17 +35,20 @@ class Raw implements IPlayer {
public function getVideoData(data:VideoDataRequest, callback:(data:VideoData)->Void):Void {
final url = data.url;
final decodedUrl = url.urlDecode();
+
+ final optTitle = cutOptionalTitle();
var title = decodedUrl.substr(decodedUrl.lastIndexOf("/") + 1);
final isNameMatched = matchName.match(title);
- if (isNameMatched) title = matchName.matched(1);
+ if (optTitle != "") title = optTitle;
+ else if (isNameMatched) title = matchName.matched(1);
else title = Lang.get("rawVideo");
+
var isHls = false;
- if (isNameMatched) {
- isHls = matchName.matched(2).contains("m3u8");
- if (isHls && !isHlsLoaded) {
- loadHlsPlugin(() -> getVideoData(data, callback));
- return;
- }
+ if (isNameMatched) isHls = matchName.matched(2).contains("m3u8");
+ else isHls = title.endsWith("m3u8");
+ if (isHls && !isHlsLoaded) {
+ loadHlsPlugin(() -> getVideoData(data, callback));
+ return;
}
final video = document.createVideoElement();
@@ -64,6 +68,13 @@ class Raw implements IPlayer {
if (isHls) initHlsSource(video, url);
}
+ function cutOptionalTitle():String {
+ final titleInput:InputElement = cast ge("#mediatitle");
+ final optTitle = titleInput.value.trim();
+ titleInput.value = "";
+ return optTitle;
+ }
+
function loadHlsPlugin(callback:()->Void):Void {
final url = "https://cdn.jsdelivr.net/npm/hls.js@latest";
JsApi.addScriptToHead(url, () -> {
@@ -81,7 +92,7 @@ class Raw implements IPlayer {
public function loadVideo(item:VideoItem):Void {
final url = main.tryLocalIp(item.url);
- final isHls = item.url.contains("m3u8");
+ final isHls = item.url.contains("m3u8") || item.title.endsWith("m3u8");
if (isHls && !isHlsLoaded) {
loadHlsPlugin(() -> loadVideo(item));
return;
send patches to the email below
yukais@pinapelz.com
include the subject [PATCH repo_name]
pinapelz.com
homepage