aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--res/client.js249
-rw-r--r--res/css/des.css188
-rw-r--r--res/index.html14
-rw-r--r--src/client/Buttons.hx64
-rw-r--r--src/client/Main.hx88
-rw-r--r--src/client/Player.hx17
-rw-r--r--src/client/Utils.hx22
-rw-r--r--src/client/players/Raw.hx2
-rw-r--r--src/client/players/RawSubs.hx2
-rw-r--r--src/client/players/Youtube.hx2
10 files changed, 393 insertions, 255 deletions
diff --git a/res/client.js b/res/client.js
index e641be7..c7651cf 100644
--- a/res/client.js
+++ b/res/client.js
@@ -558,7 +558,7 @@ client_Buttons.init = function(main) {
}
client_Buttons.initSplit();
client_Buttons.setSplitSize(client_Buttons.settings.chatSize);
- client_Buttons.initChatInput(main);
+ client_Buttons.initChatInputs(main);
var _g = 0;
var _g1 = client_Buttons.settings.checkboxes;
while(_g < _g1.length) {
@@ -596,7 +596,7 @@ client_Buttons.init = function(main) {
}
var isActive = smilesBtn.classList.toggle("active");
if(isActive) {
- wrap.style.display = "block";
+ wrap.style.display = "";
var tmp = client_Buttons.outerHeight(list);
wrap.style.height = tmp + "px";
} else {
@@ -617,26 +617,15 @@ client_Buttons.init = function(main) {
child.removeAttribute("data-src");
}
};
- var scrollToChatEndBtn = window.document.querySelector("#scroll-to-chat-end");
- var scrollToChatEndBtnAnim = function() {
- if(scrollToChatEndBtn.style.opacity == "0") {
- return;
- }
- scrollToChatEndBtn.style.opacity = "0";
- scrollToChatEndBtn.addEventListener("transitionend",function(e) {
- return scrollToChatEndBtn.style.display = "none";
- },{ once : true});
- };
- scrollToChatEndBtn.onclick = function(e) {
+ window.document.querySelector("#scroll-to-chat-end").onclick = function(e) {
main.scrollChatToEnd();
- scrollToChatEndBtnAnim();
+ main.hideScrollToChatEndBtn();
};
- var msgBuf = window.document.querySelector("#messagebuffer");
- msgBuf.onscroll = function(e) {
- if(msgBuf.offsetHeight + msgBuf.scrollTop < msgBuf.scrollHeight - 1) {
+ window.document.querySelector("#messagebuffer").onscroll = function(e) {
+ if(!main.isInChatEnd(1)) {
return;
}
- scrollToChatEndBtnAnim();
+ main.hideScrollToChatEndBtn();
};
window.document.querySelector("#clearchatbtn").onclick = function(e) {
if((main.personal.group & 8) != 0) {
@@ -669,7 +658,7 @@ client_Buttons.init = function(main) {
var style = window.document.querySelector("#userlist").style;
if(isHidden) {
icon.setAttribute("name","chevron-down");
- style.display = "block";
+ style.display = "";
wrap.style.height = "15vh";
wrap.style.marginBottom = "1rem";
} else {
@@ -712,6 +701,7 @@ client_Buttons.init = function(main) {
};
window.document.querySelector("#fullscreenbtn").onclick = function(e) {
if((client_Utils.isTouch() || main.isVerbose()) && !client_Utils.hasFullscreen()) {
+ window.scrollTo(0,0);
return client_Utils.requestFullscreen(window.document.documentElement);
} else {
return client_Utils.requestFullscreen(window.document.querySelector("#ytapiplayer"));
@@ -807,12 +797,12 @@ client_Buttons.init = function(main) {
},isActive ? 0 : 200);
};
window.document.querySelector("#exitBtn").onclick = function(e) {
+ showOptions.onclick();
if((main.personal.group & 2) != 0) {
main.send({ type : "Logout"});
} else {
window.document.querySelector("#guestname").focus();
}
- return client_Buttons.toggleGroup(showOptions);
};
window.document.querySelector("#swapLayoutBtn").onclick = function(e) {
client_Buttons.swapPlayerAndChat();
@@ -991,7 +981,7 @@ client_Buttons.updateHotkeysBtn = function() {
var state = client_Buttons.settings.hotkeysEnabled ? Lang.get("on") : Lang.get("off");
window.document.querySelector("#hotkeysBtn").innerText = "" + text + ": " + state;
};
-client_Buttons.initChatInput = function(main) {
+client_Buttons.initChatInputs = function(main) {
var guestName = window.document.querySelector("#guestname");
guestName.onkeydown = function(e) {
if(e.keyCode == 13) {
@@ -1011,42 +1001,26 @@ client_Buttons.initChatInput = function(main) {
}
}
};
- if(client_Utils.isIOS()) {
- window.document.ontouchmove = function(e) {
- return e.preventDefault();
- };
- window.document.body.style.height = "-webkit-fill-available";
- window.document.querySelector("#chat").style.height = "-webkit-fill-available";
- }
var chatline = window.document.querySelector("#chatline");
chatline.onfocus = function(e) {
if(client_Utils.isIOS()) {
- var startY = window.scrollY;
+ var startY = 0;
haxe_Timer.delay(function() {
window.scrollBy(0,-(window.scrollY - startY));
window.document.querySelector("#video").scrollTop = 0;
main.scrollChatToEnd();
- if(window.visualViewport == null) {
- var tmp = "" + Std.string(window.innerHeight);
- window.document.querySelector("#chat").style.height = tmp + "px";
- }
},100);
} else if(client_Utils.isTouch()) {
main.scrollChatToEnd();
}
};
- if(client_Utils.isIOS() && window.visualViewport != null) {
- var viewport = window.visualViewport;
+ var viewport = window.visualViewport;
+ if(viewport != null) {
viewport.addEventListener("resize",function(e) {
- var tmp = "" + Std.string(window.innerHeight);
- return window.document.querySelector("#chat").style.height = tmp + "px";
+ client_Buttons.onViewportResize();
});
+ client_Buttons.onViewportResize();
}
- chatline.onblur = function(e) {
- if(client_Utils.isIOS() && window.visualViewport == null) {
- window.document.querySelector("#chat").style.height = "-webkit-fill-available";
- }
- };
new client_InputWithHistory(chatline,null,50,function(value) {
if(main.handleCommands(value)) {
return true;
@@ -1077,6 +1051,19 @@ client_Buttons.initChatInput = function(main) {
})(checkbox));
}
};
+client_Buttons.onViewportResize = function() {
+ var tmp = window.visualViewport;
+ if(tmp == null) {
+ return;
+ }
+ var isPortrait = window.innerHeight > window.innerWidth;
+ var playerH = window.document.querySelector("#ytapiplayer").offsetHeight;
+ var h = tmp.height - playerH;
+ if(!isPortrait) {
+ h = tmp.height;
+ }
+ window.document.querySelector("#chat").style.height = "" + h + "px";
+};
client_Buttons.initPageFullscreen = function() {
window.document.onfullscreenchange = function(e) {
var el = window.document.documentElement;
@@ -1291,6 +1278,7 @@ client_JsApi.fireVideoRemoveEvents = function(item) {
var client_Main = function() {
this.matchSimpleDate = new EReg("^-?([0-9]+d)?([0-9]+h)?([0-9]+m)?([0-9]+s?)?$","");
this.urlMask = new EReg("\\${([0-9]+)-([0-9]+)}","g");
+ this.msgBuf = window.document.querySelector("#messagebuffer");
this.gotFirstPageInteraction = false;
this.disabledReconnection = false;
this.gotInitialConnection = false;
@@ -1334,28 +1322,7 @@ var client_Main = function() {
};
client_Main.__name__ = true;
client_Main.main = function() {
- new client_Main();
-};
-client_Main.serverMessage = function(text,isText,withTimestamp) {
- if(withTimestamp == null) {
- withTimestamp = true;
- }
- if(isText == null) {
- isText = true;
- }
- var div = window.document.createElement("div");
- var time = HxOverrides.dateStr(new Date()).split(" ")[1];
- div.className = "server-whisper";
- div.innerHTML = "<div class=\"head\">\n\t\t\t<div class=\"server-whisper\"></div>\n\t\t\t<span class=\"timestamp\">" + (withTimestamp ? time : "") + "</span>\n\t\t</div>";
- var textDiv = div.querySelector(".server-whisper");
- if(isText) {
- textDiv.textContent = text;
- } else {
- textDiv.innerHTML = text;
- }
- var msgBuf = window.document.querySelector("#messagebuffer");
- msgBuf.appendChild(div);
- msgBuf.scrollTop = msgBuf.scrollHeight;
+ client_Main.instance = new client_Main();
};
client_Main.prototype = {
onFirstInteraction: function() {
@@ -1589,7 +1556,7 @@ client_Main.prototype = {
}
this.player.getVideoData({ url : url, atEnd : atEnd},function(data) {
if(data.duration == 0) {
- client_Main.serverMessage(Lang.get("addVideoError"));
+ _gthis.serverMessage(Lang.get("addVideoError"));
return;
}
data.title = data.title != null ? data.title : Lang.get("rawVideo");
@@ -1614,7 +1581,7 @@ client_Main.prototype = {
var isTemp = window.document.querySelector("#customembed .add-temp").checked;
this.player.getIframeData({ url : iframe, atEnd : atEnd},function(data) {
if(data.duration == 0) {
- client_Main.serverMessage(Lang.get("addVideoError"));
+ _gthis.serverMessage(Lang.get("addVideoError"));
return;
}
if(title.length > 0) {
@@ -1663,7 +1630,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 : 443, 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 : 445, 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) {
@@ -1800,7 +1767,7 @@ client_Main.prototype = {
break;
case "ServerMessage":
var id = data.serverMessage.textId;
- client_Main.serverMessage(id == "usernameError" ? StringTools.replace(Lang.get(id),"$MAX","" + this.config.maxLoginLength) : Lang.get(id));
+ this.serverMessage(id == "usernameError" ? StringTools.replace(Lang.get(id),"$MAX","" + this.config.maxLoginLength) : Lang.get(id));
break;
case "SetLeader":
ClientTools.setLeader(this.clients,data.setLeader.clientName);
@@ -1921,7 +1888,7 @@ client_Main.prototype = {
}
var hideThisMessage = "<button id=\"hideHintList\">" + Lang.get("hideThisMessage") + "</button>";
text += "</br>" + StringTools.replace(Lang.get("hintListHide"),"$hideThisMessage",hideThisMessage);
- client_Main.serverMessage(text,false,false);
+ this.serverMessage(text,false,false);
window.document.querySelector("#addVideosHintButton").onclick = function(e) {
var addBtn = window.document.querySelector("#showmediaurl");
addBtn.scrollIntoView();
@@ -1983,7 +1950,7 @@ client_Main.prototype = {
}
var adminMenu = window.document.querySelector("#adminMenu");
if((this.personal.group & 8) != 0) {
- adminMenu.style.display = "block";
+ adminMenu.style.display = "";
} else {
adminMenu.style.display = "none";
}
@@ -2075,7 +2042,7 @@ client_Main.prototype = {
this.hideGuestLoginPanel();
}
,showGuestLoginPanel: function() {
- window.document.querySelector("#guestlogin").style.display = "flex";
+ window.document.querySelector("#guestlogin").style.display = "";
window.document.querySelector("#guestpassword").style.display = "none";
window.document.querySelector("#chatbox").style.display = "none";
window.document.querySelector("#exitBtn").textContent = Lang.get("login");
@@ -2083,13 +2050,13 @@ client_Main.prototype = {
,hideGuestLoginPanel: function() {
window.document.querySelector("#guestlogin").style.display = "none";
window.document.querySelector("#guestpassword").style.display = "none";
- window.document.querySelector("#chatbox").style.display = "flex";
+ window.document.querySelector("#chatbox").style.display = "";
window.document.querySelector("#exitBtn").textContent = Lang.get("exit");
}
,showGuestPasswordPanel: function() {
window.document.querySelector("#guestlogin").style.display = "none";
window.document.querySelector("#chatbox").style.display = "none";
- window.document.querySelector("#guestpassword").style.display = "flex";
+ window.document.querySelector("#guestpassword").style.display = "";
window.document.querySelector("#guestpass").type = "password";
window.document.querySelector("#guestpass_icon").setAttribute("name","eye");
}
@@ -2106,35 +2073,53 @@ client_Main.prototype = {
this.ws.send(JSON.stringify(data));
}
,chatMessageConnected: function() {
- var msgBuf = window.document.querySelector("#messagebuffer");
if(this.isLastMessageConnectionStatus()) {
- msgBuf.removeChild(msgBuf.lastChild);
+ this.msgBuf.removeChild(this.msgBuf.lastChild);
}
var div = window.document.createElement("div");
div.className = "server-msg-reconnect";
div.textContent = Lang.get("msgConnected");
- msgBuf.appendChild(div);
+ this.addMessageDiv(div);
this.scrollChatToEnd();
}
,chatMessageDisconnected: function() {
- var msgBuf = window.document.querySelector("#messagebuffer");
if(this.isLastMessageConnectionStatus()) {
- msgBuf.removeChild(msgBuf.lastChild);
+ this.msgBuf.removeChild(this.msgBuf.lastChild);
}
var div = window.document.createElement("div");
div.className = "server-msg-disconnect";
div.textContent = Lang.get("msgDisconnected");
- msgBuf.appendChild(div);
+ this.addMessageDiv(div);
this.scrollChatToEnd();
}
,isLastMessageConnectionStatus: function() {
- var tmp = window.document.querySelector("#messagebuffer").lastElementChild;
+ var tmp = this.msgBuf.lastElementChild;
if(tmp != null) {
return StringTools.startsWith(tmp.className,"server-msg");
} else {
return null;
}
}
+ ,serverMessage: function(text,isText,withTimestamp) {
+ if(withTimestamp == null) {
+ withTimestamp = true;
+ }
+ if(isText == null) {
+ isText = true;
+ }
+ var div = window.document.createElement("div");
+ var time = HxOverrides.dateStr(new Date()).split(" ")[1];
+ div.className = "server-whisper";
+ div.innerHTML = "<div class=\"head\">\n\t\t\t<div class=\"server-whisper\"></div>\n\t\t\t<span class=\"timestamp\">" + (withTimestamp ? time : "") + "</span>\n\t\t</div>";
+ var textDiv = div.querySelector(".server-whisper");
+ if(isText) {
+ textDiv.textContent = text;
+ } else {
+ textDiv.innerHTML = text;
+ }
+ this.addMessageDiv(div);
+ this.scrollChatToEnd();
+ }
,updateUserList: function() {
window.document.querySelector("#usercount").textContent = this.clients.length + " " + Lang.get("online");
window.document.title = this.getPageTitle();
@@ -2161,14 +2146,13 @@ client_Main.prototype = {
return "" + this.pageTitle + " (" + this.clients.length + ")";
}
,clearChat: function() {
- window.document.querySelector("#messagebuffer").textContent = "";
+ this.msgBuf.textContent = "";
}
,getLocalDateFromUtc: function(utcDate) {
var date = HxOverrides.strDate(utcDate);
return HxOverrides.dateStr(new Date(date.getTime() - date.getTimezoneOffset() * 60 * 1000));
}
,addMessage: function(name,text,date) {
- var msgBuf = window.document.querySelector("#messagebuffer");
var userDiv = window.document.createElement("div");
userDiv.className = "chat-msg-" + name;
var headDiv = window.document.createElement("div");
@@ -2197,8 +2181,8 @@ client_Main.prototype = {
text = text.replace(filter.regex.r,filter.replace);
}
textDiv.innerHTML = text;
- var isInChatEnd = msgBuf.scrollTop + msgBuf.clientHeight >= msgBuf.scrollHeight - 50;
- if(isInChatEnd) {
+ var inChatEnd = this.isInChatEnd();
+ if(inChatEnd) {
var _g = 0;
var _g1 = textDiv.getElementsByTagName("img");
while(_g < _g1.length) _g1[_g++].onload = $bind(this,this.onChatImageLoaded);
@@ -2210,11 +2194,11 @@ client_Main.prototype = {
headDiv.appendChild(nameDiv);
headDiv.appendChild(tstamp);
userDiv.appendChild(textDiv);
- msgBuf.appendChild(userDiv);
- if(isInChatEnd) {
- while(msgBuf.children.length > 200) msgBuf.removeChild(msgBuf.firstChild);
+ this.addMessageDiv(userDiv);
+ if(inChatEnd) {
+ while(this.msgBuf.children.length > 200) this.msgBuf.removeChild(this.msgBuf.firstChild);
}
- if(isInChatEnd || name == this.personal.name) {
+ if(inChatEnd || name == this.personal.name) {
this.scrollChatToEnd();
} else {
this.showScrollToChatEndBtn();
@@ -2223,13 +2207,30 @@ client_Main.prototype = {
this.blinkTabWithTitle("*" + Lang.get("chat") + "*");
}
}
+ ,addMessageDiv: function(userDiv) {
+ if(this.isMessageBufferReversed()) {
+ this.msgBuf.prepend(userDiv);
+ } else {
+ this.msgBuf.appendChild(userDiv);
+ }
+ }
,showScrollToChatEndBtn: function() {
var btn = window.document.querySelector("#scroll-to-chat-end");
- btn.style.display = "block";
+ btn.style.display = "";
haxe_Timer.delay(function() {
btn.style.opacity = "1";
},0);
}
+ ,hideScrollToChatEndBtn: function() {
+ var btn = window.document.querySelector("#scroll-to-chat-end");
+ if(btn.style.opacity == "0") {
+ return;
+ }
+ btn.style.opacity = "0";
+ btn.addEventListener("transitionend",function(e) {
+ return btn.style.display = "none";
+ },{ once : true});
+ }
,onChatImageLoaded: function(e) {
this.scrollChatToEnd();
e.target.onload = null;
@@ -2247,9 +2248,32 @@ client_Main.prototype = {
this.scrollChatToEnd();
el.onloadedmetadata = null;
}
+ ,isMessageBufferReversed: function() {
+ return this.msgBuf.style.flexDirection == "column-reverse";
+ }
+ ,isInChatEnd: function(ignoreOffset) {
+ if(ignoreOffset == null) {
+ ignoreOffset = 50;
+ }
+ var isReverse = this.isMessageBufferReversed();
+ var scrollTop = this.msgBuf.scrollTop;
+ if(isReverse) {
+ scrollTop = -scrollTop;
+ }
+ if(isReverse) {
+ return scrollTop <= ignoreOffset;
+ }
+ return scrollTop + this.msgBuf.clientHeight >= this.msgBuf.scrollHeight - ignoreOffset;
+ }
,scrollChatToEnd: function() {
- var msgBuf = window.document.querySelector("#messagebuffer");
- msgBuf.scrollTop = msgBuf.scrollHeight;
+ if(this.isMessageBufferReversed()) {
+ if(client_Utils.isMacSafari) {
+ this.msgBuf.scrollTop = -1;
+ }
+ this.msgBuf.scrollTop = 0;
+ } else {
+ this.msgBuf.scrollTop = this.msgBuf.scrollHeight;
+ }
}
,handleCommands: function(command) {
if(!StringTools.startsWith(command,"/")) {
@@ -2445,6 +2469,7 @@ var client_Player = function(main) {
this.playerEl = window.document.querySelector("#ytapiplayer");
this.videoItemsEl = window.document.querySelector("#queue");
this.videoList = new VideoList();
+ var _gthis = this;
this.main = main;
this.youtube = new client_players_Youtube(main,this);
this.streamable = new client_players_Streamable(main,this);
@@ -2452,6 +2477,22 @@ var client_Player = function(main) {
this.iframePlayer = new client_players_Iframe(main,this);
this.rawPlayer = new client_players_Raw(main,this);
this.initItemButtons();
+ var resizeObserver = client_Utils.createResizeObserver(function(entries) {
+ if(_gthis.isLoaded) {
+ return;
+ }
+ client_Buttons.onViewportResize();
+ });
+ if(resizeObserver != null) {
+ resizeObserver.observe(this.playerEl);
+ } else {
+ new haxe_Timer(50).run = function() {
+ if(_gthis.isLoaded) {
+ return;
+ }
+ client_Buttons.onViewportResize();
+ };
+ }
};
client_Player.__name__ = true;
client_Player.prototype = {
@@ -2582,7 +2623,7 @@ client_Player.prototype = {
return _gthis.isAudioTrackLoaded = true;
};
this.audioTrack.onerror = function(e) {
- haxe_Log.trace(e,{ fileName : "src/client/Player.hx", lineNumber : 191, className : "client.Player", methodName : "setExternalAudioTrack"});
+ haxe_Log.trace(e,{ fileName : "src/client/Player.hx", lineNumber : 205, className : "client.Player", methodName : "setExternalAudioTrack"});
_gthis.audioTrack.oncanplay = null;
_gthis.audioTrack.onerror = null;
_gthis.isAudioTrackLoaded = false;
@@ -2651,6 +2692,7 @@ client_Player.prototype = {
this.main.send({ type : "VideoLoaded"});
}
this.isLoaded = true;
+ client_Buttons.onViewportResize();
}
,onPlay: function() {
var tmp = this.audioTrack;
@@ -3035,7 +3077,7 @@ client_Player.prototype = {
}
};
http.onError = function(msg) {
- haxe_Log.trace(msg,{ fileName : "src/client/Player.hx", lineNumber : 577, className : "client.Player", methodName : "skipAd"});
+ haxe_Log.trace(msg,{ fileName : "src/client/Player.hx", lineNumber : 592, className : "client.Player", methodName : "skipAd"});
};
http.request();
}
@@ -3156,6 +3198,15 @@ client_Utils.isIOS = function() {
return true;
}
};
+client_Utils._isMacSafari = function() {
+ var isMac = $global.navigator.userAgent.indexOf("Macintosh") != -1;
+ var isSafari = $global.navigator.userAgent.indexOf("Safari") != -1 && $global.navigator.userAgent.indexOf("Chrom") == -1 && $global.navigator.userAgent.indexOf("Edg") == -1;
+ if(isMac) {
+ return isSafari;
+ } else {
+ return false;
+ }
+};
client_Utils.isAndroid = function() {
return $global.navigator.userAgent.toLowerCase().indexOf("android") > -1;
};
@@ -3202,8 +3253,6 @@ client_Utils.requestFullscreen = function(el) {
var el2 = el;
if(el.requestFullscreen != null) {
el.requestFullscreen();
- } else if(el2.mozRequestFullScreen != null) {
- el2.mozRequestFullScreen();
} else if(el2.webkitRequestFullscreen != null) {
el2.webkitRequestFullscreen(HTMLElement.ALLOW_KEYBOARD_INPUT);
} else {
@@ -3271,6 +3320,9 @@ client_Utils.saveFile = function(name,mime,data) {
window.document.body.removeChild(a);
URL.revokeObjectURL(url);
};
+client_Utils.createResizeObserver = function(callback) {
+ return null;
+};
var client_players_Iframe = function(main,player) {
this.playerEl = window.document.querySelector("#ytapiplayer");
this.main = main;
@@ -3500,7 +3552,7 @@ client_players_Raw.prototype = {
try {
subsUri = new URL(subsUrl);
} catch( _g ) {
- client_Main.serverMessage("Failed to add subs: bad url (" + subsUrl + ")");
+ client_Main.instance.serverMessage("Failed to add subs: bad url (" + subsUrl + ")");
return;
}
if(subsUri.hostname == this.main.host || subsUri.hostname == this.main.globalIp) {
@@ -3782,7 +3834,7 @@ client_players_RawSubs.convertAssTime = function(time) {
};
client_players_RawSubs.isProxyError = function(text) {
if(StringTools.startsWith(text,"Proxy error:")) {
- client_Main.serverMessage("Failed to add subs: proxy error");
+ client_Main.instance.serverMessage("Failed to add subs: proxy error");
haxe_Log.trace("Failed to add subs: " + text,{ fileName : "src/client/players/RawSubs.hx", lineNumber : 219, className : "client.players.RawSubs", methodName : "isProxyError"});
return true;
}
@@ -4161,7 +4213,7 @@ client_players_Youtube.prototype = {
loadJson(dataUrl);
}
,youtubeApiError: function(error) {
- client_Main.serverMessage("Error " + error.code + ": " + error.message,false);
+ client_Main.instance.serverMessage("Error " + error.code + ": " + error.message,false);
}
,getRemoteDataFallback: function(url,callback) {
var _gthis = this;
@@ -5108,6 +5160,7 @@ client_JsApi.videoChange = [];
client_JsApi.videoRemove = [];
client_JsApi.onceListeners = [];
client_Settings.isSupported = false;
+client_Utils.isMacSafari = client_Utils._isMacSafari();
client_players_RawSubs.assTimeStamp = new EReg("([0-9]+):([0-9][0-9]):([0-9][0-9]).([0-9][0-9])","");
haxe_crypto_Base64.CHARS = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/";
haxe_crypto_Base64.BYTES = haxe_io_Bytes.ofString(haxe_crypto_Base64.CHARS);
diff --git a/res/css/des.css b/res/css/des.css
index a6fd43d..7fb2d26 100644
--- a/res/css/des.css
+++ b/res/css/des.css
@@ -31,14 +31,37 @@ html {
body {
font-family: system-ui, -apple-system, BlinkMacSystemFont, "Segoe UI", Roboto, Oxygen-Sans, Ubuntu, Cantarell, "Helvetica Neue", Arial, sans-serif, "Apple Color Emoji", "Segoe UI Emoji", "Segoe UI Symbol";
- font-size: .875rem;
+ font-size: 1rem;
line-height: 1.4;
color: var(--foreground);
- background-color: var(--background-chat);
+ background: var(--background-video);
margin: 0;
padding: 0;
- display: flex;
- flex-direction: column;
+ display: grid;
+ grid-template-areas: "video gutter chat";
+ overflow-y: hidden;
+ width: 100%;
+ height: 100vh;
+}
+
+body.swap {
+ grid-template-areas: "chat gutter video";
+}
+
+
+@media only screen and (orientation: portrait) {
+ body {
+ font-size: .875rem;
+ grid-template-areas: none;
+ overflow-y: auto;
+ height: auto;
+ display: flex;
+ flex-direction: column;
+ }
+
+ body.swap {
+ grid-template-areas: none;
+ }
}
h1,
@@ -305,7 +328,18 @@ button.danger-bg:focus {
display: flex;
justify-content: space-between;
align-items: center;
- flex-wrap: wrap;
+ flex-wrap: nowrap;
+}
+
+@media only screen and (orientation: portrait) {
+ .info {
+ flex-wrap: wrap;
+ }
+}
+
+#currenttitle {
+ text-overflow: ellipsis;
+ overflow: hidden;
}
.info header {
@@ -358,6 +392,44 @@ header h4 {
background: var(--background-video);
}
+@media only screen and (orientation: landscape) {
+ #video {
+ grid-area: video;
+ width: 100%;
+ height: 100%;
+ /* Breaks subs after viewport overflow on FF+Linux (SyncTube#28) */
+ /* overflow: auto; */
+ overflow: scroll;
+ background: var(--background-video);
+ }
+}
+
+@media only screen and (orientation: portrait) {
+ #video {
+ display: contents;
+ }
+
+ #player {
+ display: contents;
+ }
+
+ #ytapiplayer {
+ background: var(--background-video);
+ }
+
+ .info {
+ order: 2;
+ }
+
+ #playlist {
+ order: 3;
+ }
+
+ #footer {
+ order: 4;
+ }
+}
+
/* Embed responsive */
.embed-responsive:empty {
@@ -391,11 +463,11 @@ iframe#videoplayer {
}
.embed-responsive {
- max-height: 50vh;
+ max-height: 30vh;
}
#videoplayer {
- max-height: 50vh;
+ max-height: 30vh;
}
}
@@ -455,7 +527,7 @@ iframe#videoplayer {
#customembed>*>input,
#customembed>*>textarea {
- display: block;
+ display: flex;
width: 100%;
}
@@ -509,11 +581,26 @@ footer#footer {
display: none;
}
+@media only screen and (orientation: landscape) {
+ .gutter {
+ grid-area: gutter;
+ display: flex;
+ cursor: col-resize;
+ background-color: var(--border);
+ transition: background-color ease-in-out .15s;
+ }
+
+ .gutter:hover {
+ background-color: var(--accent);
+ }
+}
+
/*
* Start chat
*/
#chat {
+ background: var(--background-chat);
position: relative;
display: flex;
order: 0;
@@ -523,6 +610,13 @@ footer#footer {
height: 40vh;
}
+@media only screen and (orientation: landscape) {
+ #chat {
+ grid-area: chat;
+ height: 100vh;
+ }
+}
+
#chat header {
display: flex;
align-items: center;
@@ -550,6 +644,8 @@ footer#footer {
}
#userlist {
+ display: flex;
+ flex-direction: column;
padding: 1rem;
}
@@ -611,6 +707,8 @@ footer#footer {
}
#optionsList div {
+ display: flex;
+ flex-direction: column;
margin-bottom: .5rem;
}
@@ -636,6 +734,8 @@ footer#footer {
/* Message buffer */
#messagebuffer {
+ display: flex;
+ flex-direction: column;
flex-grow: 2;
flex-shrink: 8;
overflow: auto;
@@ -655,7 +755,7 @@ footer#footer {
}
.username {
- display: block;
+ display: flex;
}
.timestamp {
@@ -715,7 +815,7 @@ footer#footer {
/* Emotes */
#smiles-wrap {
- display: none;
+ display: flex;
height: 0;
width: 100%;
background: rgba(0, 0, 0, 0.7);
@@ -726,6 +826,7 @@ footer#footer {
#smiles-list {
display: grid;
+ width: 100%;
height: 12rem;
padding: 1rem;
grid-template-columns: repeat(auto-fit, minmax(4rem, 1fr));
@@ -763,7 +864,7 @@ footer#footer {
#guestlogin label,
#guestpassword label {
- display: block;
+ display: flex;
margin-bottom: 1em;
}
@@ -814,71 +915,6 @@ html {
background: rgba(255, 255, 255, 0.2);
}
-/*
- * Media queries
- */
-
-@media only screen and (orientation: landscape) {
- body {
- display: grid;
- grid-template-areas: "video gutter chat";
- overflow-y: hidden;
- font-size: 1rem;
- width: 100%;
- height: 100vh;
- }
-
- body.swap {
- grid-template-areas: "chat gutter video";
- }
-
- .info {
- flex-wrap: nowrap;
- }
-
- #video {
- grid-area: video;
- width: 100%;
- height: 100%;
- /* Breaks subs after viewport overflow on FF+Linux (SyncTube#28) */
- /* overflow: auto; */
- overflow: scroll;
- background: var(--background-video);
- }
-
- #header {
- display: flex;
- flex: 1;
- flex-wrap: nowrap;
- overflow: hidden;
- white-space: nowrap;
- text-overflow: ellipsis;
- font-size: 1.953rem;
- }
-
- #currenttitle {
- text-overflow: ellipsis;
- overflow: hidden;
- }
-
- .gutter {
- grid-area: gutter;
- display: block;
- cursor: col-resize;
- background-color: var(--border);
- transition: background-color ease-in-out .15s;
- }
-
- .gutter:hover {
- background-color: var(--accent);
- }
-
- #chat {
- grid-area: chat;
- height: 100vh;
- }
-}
-
/* Mobile page fullscreen */
.mobile-view #chatbox {
diff --git a/res/index.html b/res/index.html
index 0d7c797..fa4acde 100644
--- a/res/index.html
+++ b/res/index.html
@@ -4,13 +4,13 @@
<head>
<meta http-equiv="content-type" content="text/html; charset=UTF-8">
<meta charset="utf-8">
- <meta name="viewport" content="width=device-width, initial-scale=1.0, maximum-scale=1">
+ <meta name="viewport" content="width=device-width, initial-scale=1, maximum-scale=1">
<title>SyncTube</title>
<link rel="icon" type="image/png" href="img/favicon.png" />
<link id="usertheme" href="css/des.css" rel="stylesheet">
<link id="customcss" href="css/custom.css" rel="stylesheet">
- <script type="module" src="https://cdn.jsdelivr.net/npm/ionicons@5.0.0/dist/ionicons/ionicons.esm.js"></script>
- <script nomodule="" src="https://cdn.jsdelivr.net/npm/ionicons@5.0.0/dist/ionicons/ionicons.js"></script>
+ <script type="module" src="https://cdn.jsdelivr.net/npm/ionicons@7.4.0/dist/ionicons/ionicons.esm.js"></script>
+ <script nomodule="" src="https://cdn.jsdelivr.net/npm/ionicons@7.4.0/dist/ionicons/ionicons.js"></script>
</head>
<body style="grid-template-columns: 1fr 4px 300px;">
@@ -193,10 +193,10 @@
</div>
</ul>
<!-- Messages -->
- <div id="messagebuffer"></div>
+ <div id="messagebuffer" style="flex-direction: column-reverse;"></div>
<div id="chat-inputs-wrapper">
<button id="scroll-to-chat-end" style="display: none; opacity: 0;" class="active">
- <ion-icon name="arrow-down" role="img" class="md hydrated" aria-label="arrow down"></ion-icon>
+ <ion-icon name="arrow-down" role="img" class="md hydrated"></ion-icon>
</button>
<!-- Message input -->
<div id="chatbox">
@@ -205,7 +205,7 @@
<ion-icon name="happy"></ion-icon>
</button>
</div>
- <div id="smiles-wrap" class="collapsible">
+ <div id="smiles-wrap" class="collapsible" style="display: none;">
<div id="smiles-list"></div>
</div>
<!-- Guest login -->
@@ -225,7 +225,7 @@
</div>
</aside>
- <script src="https://cdn.jsdelivr.net/npm/split-grid@1.0.9/dist/split-grid.js"></script>
+ <script src="https://cdn.jsdelivr.net/npm/split-grid@1.0.11/dist/split-grid.min.js"></script>
<script src="client.js"></script>
<script src="js/custom.js"></script>
</body>
diff --git a/src/client/Buttons.hx b/src/client/Buttons.hx
index dbcf759..36f5729 100644
--- a/src/client/Buttons.hx
+++ b/src/client/Buttons.hx
@@ -20,7 +20,7 @@ class Buttons {
if (settings.isSwapped) swapPlayerAndChat();
initSplit();
setSplitSize(settings.chatSize);
- initChatInput(main);
+ initChatInputs(main);
for (item in settings.checkboxes) {
if (item.checked == null) continue;
@@ -49,7 +49,7 @@ class Buttons {
if (list.children.length == 0) return;
final isActive = smilesBtn.classList.toggle("active");
if (isActive) {
- wrap.style.display = "block";
+ wrap.style.display = "";
wrap.style.height = outerHeight(list) + "px";
} else {
wrap.style.height = "0";
@@ -65,22 +65,15 @@ class Buttons {
}
final scrollToChatEndBtn = ge("#scroll-to-chat-end");
- function scrollToChatEndBtnAnim():Void {
- if (scrollToChatEndBtn.style.opacity == "0") return;
- scrollToChatEndBtn.style.opacity = "0";
- scrollToChatEndBtn.addEventListener("transitionend", e -> {
- scrollToChatEndBtn.style.display = "none";
- }, {once: true});
- }
scrollToChatEndBtn.onclick = e -> {
main.scrollChatToEnd();
- scrollToChatEndBtnAnim();
+ main.hideScrollToChatEndBtn();
}
// hide scroll button when chat is scrolled to the end
final msgBuf = ge("#messagebuffer");
msgBuf.onscroll = e -> {
- if (msgBuf.offsetHeight + msgBuf.scrollTop < msgBuf.scrollHeight - 1) return;
- scrollToChatEndBtnAnim();
+ if (!main.isInChatEnd(1)) return;
+ main.hideScrollToChatEndBtn();
}
ge("#clearchatbtn").onclick = e -> {
@@ -114,7 +107,7 @@ class Buttons {
final style = ge("#userlist").style;
if (isHidden) {
icon.setAttribute("name", "chevron-down");
- style.display = "block";
+ style.display = "";
final list = wrap.firstElementChild;
wrap.style.height = "15vh";
wrap.style.marginBottom = "1rem";
@@ -161,6 +154,7 @@ class Buttons {
final fullscreenBtn = ge("#fullscreenbtn");
fullscreenBtn.onclick = e -> {
if ((Utils.isTouch() || main.isVerbose()) && !Utils.hasFullscreen()) {
+ window.scrollTo(0, 0);
Utils.requestFullscreen(document.documentElement);
} else {
Utils.requestFullscreen(ge("#ytapiplayer"));
@@ -254,9 +248,9 @@ class Buttons {
final exitBtn = ge("#exitBtn");
exitBtn.onclick = e -> {
+ showOptions.onclick();
if (main.isUser()) main.send({type: Logout});
else ge("#guestname").focus();
- toggleGroup(showOptions);
}
final swapLayoutBtn = ge("#swapLayoutBtn");
@@ -429,7 +423,7 @@ class Buttons {
ge("#hotkeysBtn").innerText = '$text: $state';
}
- static function initChatInput(main:Main):Void {
+ static function initChatInputs(main:Main):Void {
final guestName:InputElement = cast ge("#guestname");
guestName.onkeydown = e -> {
if (e.keyCode == KeyCode.Return) {
@@ -447,38 +441,25 @@ class Buttons {
}
}
- if (Utils.isIOS()) {
- document.ontouchmove = e -> {
- e.preventDefault();
- }
- document.body.style.height = "-webkit-fill-available";
- ge("#chat").style.height = "-webkit-fill-available";
- }
final chatline:InputElement = cast ge("#chatline");
chatline.onfocus = e -> {
if (Utils.isIOS()) {
- final startY = window.scrollY;
+ // final startY = window.scrollY;
+ final startY = 0;
Timer.delay(() -> {
window.scrollBy(0, -(window.scrollY - startY));
ge("#video").scrollTop = 0;
main.scrollChatToEnd();
- if (getVisualViewport() == null) { // ios < 13
- ge("#chat").style.height = '${window.innerHeight}px';
- }
}, 100);
- } else if (Utils.isTouch()) main.scrollChatToEnd();
- }
- if (Utils.isIOS() && getVisualViewport() != null) {
- final viewport = getVisualViewport();
- viewport.addEventListener("resize", e -> {
- ge("#chat").style.height = '${window.innerHeight}px';
- });
- }
- chatline.onblur = e -> {
- if (Utils.isIOS() && getVisualViewport() == null) { // ios < 13
- ge("#chat").style.height = "-webkit-fill-available";
+ } else if (Utils.isTouch()) {
+ main.scrollChatToEnd();
}
}
+ final viewport = getVisualViewport();
+ if (viewport != null) {
+ viewport.addEventListener("resize", e -> onViewportResize());
+ onViewportResize();
+ }
new InputWithHistory(chatline, 50, value -> {
if (main.handleCommands(value)) return true;
main.send({
@@ -506,6 +487,15 @@ class Buttons {
}
}
+ public static function onViewportResize():Void {
+ final viewport = getVisualViewport() ?? return;
+ final isPortrait = window.innerHeight > window.innerWidth;
+ final playerH = ge("#ytapiplayer").offsetHeight;
+ var h = viewport.height - playerH;
+ if (!isPortrait) h = viewport.height;
+ ge("#chat").style.height = '${h}px';
+ }
+
static inline function getVisualViewport():Null<VisualViewport> {
return (window : Dynamic).visualViewport;
}
diff --git a/src/client/Main.hx b/src/client/Main.hx
index 72dbf8e..9a4b426 100644
--- a/src/client/Main.hx
+++ b/src/client/Main.hx
@@ -26,6 +26,7 @@ import js.html.WebSocket;
using ClientTools;
class Main {
+ public static var instance(default, null):Main;
static inline var SETTINGS_VERSION = 5;
public final settings:ClientSettings;
@@ -51,9 +52,10 @@ class Main {
var onTimeGet:Timer;
var onBlinkTab:Null<Timer>;
var gotFirstPageInteraction = false;
+ var msgBuf = ge("#messagebuffer");
static function main():Void {
- new Main();
+ instance = new Main();
}
function new() {
@@ -723,7 +725,7 @@ class Main {
button.disabled = true;
}
final adminMenu = ge("#adminMenu");
- if (isAdmin()) adminMenu.style.display = "block";
+ if (isAdmin()) adminMenu.style.display = "";
else adminMenu.style.display = "none";
}
@@ -815,7 +817,7 @@ class Main {
}
function showGuestLoginPanel():Void {
- ge("#guestlogin").style.display = "flex";
+ ge("#guestlogin").style.display = "";
ge("#guestpassword").style.display = "none";
ge("#chatbox").style.display = "none";
ge("#exitBtn").textContent = Lang.get("login");
@@ -824,14 +826,14 @@ class Main {
function hideGuestLoginPanel():Void {
ge("#guestlogin").style.display = "none";
ge("#guestpassword").style.display = "none";
- ge("#chatbox").style.display = "flex";
+ ge("#chatbox").style.display = "";
ge("#exitBtn").textContent = Lang.get("exit");
}
function showGuestPasswordPanel():Void {
ge("#guestlogin").style.display = "none";
ge("#chatbox").style.display = "none";
- ge("#guestpassword").style.display = "flex";
+ ge("#guestpassword").style.display = "";
(cast ge("#guestpass") : InputElement).type = "password";
ge("#guestpass_icon").setAttribute("name", "eye");
}
@@ -850,35 +852,32 @@ class Main {
}
function chatMessageConnected():Void {
- final msgBuf = ge("#messagebuffer");
if (isLastMessageConnectionStatus()) {
msgBuf.removeChild(msgBuf.lastChild);
}
final div = document.createDivElement();
div.className = "server-msg-reconnect";
div.textContent = Lang.get("msgConnected");
- msgBuf.appendChild(div);
+ addMessageDiv(div);
scrollChatToEnd();
}
function chatMessageDisconnected():Void {
- final msgBuf = ge("#messagebuffer");
if (isLastMessageConnectionStatus()) {
msgBuf.removeChild(msgBuf.lastChild);
}
final div = document.createDivElement();
div.className = "server-msg-disconnect";
div.textContent = Lang.get("msgDisconnected");
- msgBuf.appendChild(div);
+ addMessageDiv(div);
scrollChatToEnd();
}
function isLastMessageConnectionStatus():Bool {
- final msgBuf = ge("#messagebuffer");
return msgBuf.lastElementChild?.className.startsWith("server-msg");
}
- public static function serverMessage(text:String, isText = true, withTimestamp = true):Void {
+ public function serverMessage(text:String, isText = true, withTimestamp = true):Void {
final div = document.createDivElement();
final time = Date.now().toString().split(" ")[1];
div.className = "server-whisper";
@@ -889,12 +888,11 @@ class Main {
final textDiv = div.querySelector(".server-whisper");
if (isText) textDiv.textContent = text;
else textDiv.innerHTML = text;
- final msgBuf = ge("#messagebuffer");
- msgBuf.appendChild(div);
- msgBuf.scrollTop = msgBuf.scrollHeight;
+ addMessageDiv(div);
+ scrollChatToEnd();
}
- public static function serverHtmlMessage(el:Element):Void {
+ public function serverHtmlMessage(el:Element):Void {
final div = document.createDivElement();
final time = Date.now().toString().split(" ")[1];
div.className = "server-whisper";
@@ -903,9 +901,8 @@ class Main {
<span class="timestamp">$time</span>
</div>';
div.querySelector(".server-whisper").appendChild(el);
- final msgBuf = ge("#messagebuffer");
- msgBuf.appendChild(div);
- msgBuf.scrollTop = msgBuf.scrollHeight;
+ addMessageDiv(div);
+ scrollChatToEnd();
}
function updateUserList():Void {
@@ -931,7 +928,7 @@ class Main {
}
function clearChat():Void {
- ge("#messagebuffer").textContent = "";
+ msgBuf.textContent = "";
}
function getLocalDateFromUtc(utcDate:String):String {
@@ -941,7 +938,6 @@ class Main {
}
function addMessage(name:String, text:String, ?date:String):Void {
- final msgBuf = ge("#messagebuffer");
final userDiv = document.createDivElement();
userDiv.className = 'chat-msg-$name';
@@ -968,10 +964,9 @@ class Main {
text = filter.regex.replace(text, filter.replace);
}
textDiv.innerHTML = text;
- final isInChatEnd = msgBuf.scrollTop
- + msgBuf.clientHeight >= msgBuf.scrollHeight - 50;
+ final inChatEnd = isInChatEnd();
- if (isInChatEnd) { // scroll chat to end after images loaded
+ if (inChatEnd) { // scroll chat to end after images loaded
for (img in textDiv.getElementsByTagName("img")) {
img.onload = onChatImageLoaded;
}
@@ -984,13 +979,14 @@ class Main {
headDiv.appendChild(nameDiv);
headDiv.appendChild(tstamp);
userDiv.appendChild(textDiv);
- msgBuf.appendChild(userDiv);
- if (isInChatEnd) {
+ addMessageDiv(userDiv);
+
+ if (inChatEnd) {
while (msgBuf.children.length > 200) {
msgBuf.removeChild(msgBuf.firstChild);
}
}
- if (isInChatEnd || name == personal.name) {
+ if (inChatEnd || name == personal.name) {
scrollChatToEnd();
} else {
showScrollToChatEndBtn();
@@ -998,12 +994,26 @@ class Main {
if (onBlinkTab == null) blinkTabWithTitle('*${Lang.get("chat")}*');
}
- function showScrollToChatEndBtn() {
+ function addMessageDiv(userDiv:Element):Void {
+ if (isMessageBufferReversed()) msgBuf.prepend(userDiv);
+ else msgBuf.appendChild(userDiv);
+ }
+
+ public function showScrollToChatEndBtn():Void {
final btn = ge("#scroll-to-chat-end");
- btn.style.display = "block";
+ btn.style.display = "";
Timer.delay(() -> btn.style.opacity = "1", 0);
}
+ public function hideScrollToChatEndBtn():Void {
+ final btn = ge("#scroll-to-chat-end");
+ if (btn.style.opacity == "0") return;
+ btn.style.opacity = "0";
+ btn.addEventListener("transitionend", e -> {
+ btn.style.display = "none";
+ }, {once: true});
+ }
+
function onChatImageLoaded(e:Event):Void {
scrollChatToEnd();
(cast e.target : Element).onload = null;
@@ -1028,9 +1038,27 @@ class Main {
el.onloadedmetadata = null;
}
+ public function isMessageBufferReversed():Bool {
+ return msgBuf.style.flexDirection == "column-reverse";
+ }
+
+ public function isInChatEnd(ignoreOffset = 50):Bool {
+ final isReverse = isMessageBufferReversed();
+ var scrollTop = msgBuf.scrollTop;
+ // zero to negative in column-reverse
+ if (isReverse) scrollTop = -scrollTop;
+ if (isReverse) return scrollTop <= ignoreOffset;
+ return scrollTop + msgBuf.clientHeight >= msgBuf.scrollHeight - ignoreOffset;
+ }
+
public function scrollChatToEnd():Void {
- final msgBuf = ge("#messagebuffer");
- msgBuf.scrollTop = msgBuf.scrollHeight;
+ final isReverse = isMessageBufferReversed();
+ if (isReverse) {
+ if (Utils.isMacSafari) msgBuf.scrollTop = -1;
+ msgBuf.scrollTop = 0;
+ } else {
+ msgBuf.scrollTop = msgBuf.scrollHeight;
+ }
}
/* Returns `true` if text should not be sent to chat */
diff --git a/src/client/Player.hx b/src/client/Player.hx
index f51d017..0efa2e3 100644
--- a/src/client/Player.hx
+++ b/src/client/Player.hx
@@ -24,7 +24,7 @@ class Player {
final rawPlayer:IPlayer;
final videoList = new VideoList();
final videoItemsEl = ge("#queue");
- final playerEl:Element = ge("#ytapiplayer");
+ final playerEl = ge("#ytapiplayer");
var player:Null<IPlayer>;
var isLoaded = false;
var skipSetTime = false;
@@ -49,6 +49,20 @@ class Player {
iframePlayer = new Iframe(main, this);
rawPlayer = new Raw(main, this);
initItemButtons();
+
+ final resizeObserver = Utils.createResizeObserver(entries -> {
+ if (isLoaded) return;
+ Buttons.onViewportResize();
+ });
+ if (resizeObserver != null) {
+ resizeObserver.observe(playerEl);
+ } else {
+ final timer = new haxe.Timer(50);
+ timer.run = () -> {
+ if (isLoaded) return;
+ Buttons.onViewportResize();
+ }
+ }
}
function initItemButtons():Void {
@@ -239,6 +253,7 @@ class Player {
public function onCanBePlayed():Void {
if (!isLoaded) main.send({type: VideoLoaded});
isLoaded = true;
+ Buttons.onViewportResize();
}
public function onPlay():Void {
diff --git a/src/client/Utils.hx b/src/client/Utils.hx
index a0e19f7..155292f 100644
--- a/src/client/Utils.hx
+++ b/src/client/Utils.hx
@@ -26,6 +26,16 @@ class Utils {
|| (~/^Mac/.match(navigator.platform) && navigator.maxTouchPoints > 4);
}
+ public static var isMacSafari = _isMacSafari();
+
+ static function _isMacSafari():Bool {
+ final isMac = navigator.userAgent.contains("Macintosh");
+ final isSafari = navigator.userAgent.contains("Safari")
+ && !navigator.userAgent.contains("Chrom")
+ && !navigator.userAgent.contains("Edg");
+ return isMac && isSafari;
+ }
+
public static function isAndroid():Bool {
final ua = navigator.userAgent.toLowerCase();
return ua.indexOf("android") > -1;
@@ -66,8 +76,6 @@ class Utils {
final el2:Dynamic = el;
if (el.requestFullscreen != null) {
el.requestFullscreen();
- } else if (el2.mozRequestFullScreen != null) {
- el2.mozRequestFullScreen();
} else if (el2.webkitRequestFullscreen != null) {
el2.webkitRequestFullscreen(untyped Element.ALLOW_KEYBOARD_INPUT);
} else return false;
@@ -77,7 +85,6 @@ class Utils {
public static function cancelFullscreen(el:Element):Void {
final doc:Dynamic = document;
if (doc.cancelFullScreen != null) doc.cancelFullScreen();
- else if (doc.mozCancelFullScreen != null) doc.mozCancelFullScreen();
else if (doc.webkitCancelFullScreen != null) doc.webkitCancelFullScreen();
}
@@ -159,4 +166,13 @@ class Utils {
document.body.removeChild(a);
URL.revokeObjectURL(url);
}
+
+ public static function createResizeObserver(callback:(entries:Array<Dynamic>) -> Void):Null<{
+ observe:(el:Element) -> Void
+ }> {
+ return null;
+ final window = js.Browser.window;
+ final observer = (window : Dynamic).ResizeObserver ?? return null;
+ return js.Syntax.code("new ResizeObserver({0})", callback);
+ }
}
diff --git a/src/client/players/Raw.hx b/src/client/players/Raw.hx
index eb93c84..01752e7 100644
--- a/src/client/players/Raw.hx
+++ b/src/client/players/Raw.hx
@@ -140,7 +140,7 @@ class Raw implements IPlayer {
final subsUri = try {
new URL(subsUrl);
} catch (e) {
- Main.serverMessage('Failed to add subs: bad url ($subsUrl)');
+ Main.instance.serverMessage('Failed to add subs: bad url ($subsUrl)');
return;
}
// make local url as relative path to skip proxy
diff --git a/src/client/players/RawSubs.hx b/src/client/players/RawSubs.hx
index a4404b0..e9b2203 100644
--- a/src/client/players/RawSubs.hx
+++ b/src/client/players/RawSubs.hx
@@ -215,7 +215,7 @@ class RawSubs {
static function isProxyError(text:String):Bool {
if (text.startsWith("Proxy error:")) {
- Main.serverMessage("Failed to add subs: proxy error");
+ Main.instance.serverMessage("Failed to add subs: proxy error");
trace('Failed to add subs: $text');
return true;
}
diff --git a/src/client/players/Youtube.hx b/src/client/players/Youtube.hx
index 5a8921a..b30dfb3 100644
--- a/src/client/players/Youtube.hx
+++ b/src/client/players/Youtube.hx
@@ -165,7 +165,7 @@ class Youtube implements IPlayer {
function youtubeApiError(error:Dynamic):Void {
final code:Int = error.code;
final msg:String = error.message;
- Main.serverMessage('Error $code: $msg', false);
+ Main.instance.serverMessage('Error $code: $msg', false);
}
function getRemoteDataFallback(url:String, callback:(data:VideoData) -> Void):Void {
send patches to the email below
yukais@pinapelz.com
include the subject [PATCH repo_name]
pinapelz.com
homepage