Advertisement
Guest User

chatbelowv2.0

a guest
Jul 19th, 2018
142
0
Never
Not a member of Pastebin yet? Sign Up, it unlocks many cool features!
text 82.51 KB | None | 0 0
  1. // ==UserScript==
  2. // @name Tinychat Enhancement Suite (TES)
  3. // @namespace https://greasyfork.org/en/users/27283-mutationobserver
  4. // @version 2018.07.19v50
  5. // @description Fixes some Tinychat room shortcomings and adds useful features.
  6. // @author MutationObserver
  7. // @match https://tinychat.com/room/*
  8. // @exclude https://tinychat.com/room/*?1
  9. // @grant GM_setValue
  10. // @grant GM_getValue
  11. // @grant GM_listValues
  12.  
  13. // ==/UserScript==
  14. /* jshint -W097 */
  15.  
  16. TESwsParser``;
  17. var initInterval = setInterval(function (){
  18. if (document.querySelector("tinychat-webrtc-app").shadowRoot) TESapp = runTES``;
  19. else tcl("Waiting for DOM...");
  20. }, 500);
  21.  
  22. function runTES() {
  23. clearInterval(initInterval);
  24. try {
  25. /* Begin main function */
  26.  
  27. var bodyElem = document.querySelector("body");
  28.  
  29. var webappOuter = document.querySelector("tinychat-webrtc-app");
  30. var webappElem = webappOuter.shadowRoot;
  31. var chatlogOuter = webappElem.children[2].children[1];
  32. var chatlogElem = webappElem.querySelector("tinychat-chatlog").shadowRoot;
  33. var titleElem = webappElem.querySelector("tinychat-title").shadowRoot;
  34. var sidemenuElem = webappElem.querySelector("tinychat-sidemenu").shadowRoot;
  35. var videomoderationElem = sidemenuElem.querySelector("tc-video-moderation").shadowRoot;
  36. var videolistElem = webappElem.querySelector("tinychat-videolist").shadowRoot;
  37.  
  38. var chatlistElem = sidemenuElem.querySelector("tinychat-chatlist").shadowRoot;
  39. var userlistElem = sidemenuElem.querySelector("tinychat-userlist").shadowRoot;
  40. var userContextmenuElem = userlistElem.querySelector("tinychat-user-contextmenu").shadowRoot;
  41.  
  42. var chatlogCSS = chatlogElem.querySelector("#chat-wrapper");
  43. var sidemenuCSS = sidemenuElem.querySelector("#sidemenu");
  44. var videomoderationCSS = videomoderationElem.querySelector("#moderatorlist");
  45. var webappCSS = webappElem.querySelector("#room");
  46. var chatlistCSS = chatlistElem.querySelector("#chatlist");
  47. var userlistCSS = userlistElem.querySelector("#userlist");
  48. var userContextmenuCSS = userContextmenuElem.querySelector("#main");
  49. var titleCSS = titleElem.querySelector("#room-header");
  50. var videolistCSS = videolistElem.querySelector("#videolist");
  51. var bodyCSS = document.querySelector("body");
  52.  
  53. var userinfoCont = sidemenuElem.querySelector("#user-info > div");
  54. var scrollbox = chatlogElem.querySelector("#chat");
  55. var unreadbubble = chatlogElem.querySelector("#input-unread");
  56.  
  57. var resourceDirectory = document.querySelector('link[rel="manifest"]').getAttribute("href").split("manifest")[0]; // \/([\d\.\-])+\/
  58. var audioPop = new Audio(resourceDirectory + 'sound/pop.mp3');
  59. var settingMentions = [];
  60. var giftsElemWidth = 127;
  61. var freshInstall = (GM_listValues().length == 0);
  62. var isModerator = (!userlistElem.querySelector("#button-banlist").classList.contains("hidden"));
  63. var isPaidAccount = (sidemenuElem.querySelector("#sidemenu-wider"));
  64.  
  65. var browserFirefox = navigator.userAgent.includes("Firefox/");
  66. var urlAddress = new URL(window.location.href);
  67. var urlPars = urlAddress.searchParams;
  68.  
  69. var messageQueryString = "#chat-content .message";
  70. var camQueryString = ".videos-items:last-child > .js-video";
  71.  
  72. var userCount = 0;
  73. var messageCount = 0;
  74. var camMaxedCurrent = null;
  75. var autoScrollStatus = true;
  76. var roomName = webappOuter.getAttribute("roomname");
  77. var joinTime = getFormattedDateTime(new Date(), "time");
  78. var joinDate = getFormattedDateTime(new Date());
  79.  
  80. document.title = roomName + " - Tinychat";
  81. declareGlobalVars();
  82. var settingsWaitInterval = setInterval(waitForSettings,1000);
  83.  
  84. if (!browserFirefox) {
  85. injectCSS();
  86. injectElements();
  87. }
  88.  
  89. var scrollboxEvent = scrollbox.addEventListener("wheel", userHasScrolled);
  90. var unreadbubbleEvent = unreadbubble.addEventListener("click", function(){autoScrollStatus = true;} );
  91.  
  92. if (userinfoCont.hasAttribute("title")) {
  93. bodyCSS.classList.add("logged-in");
  94. sidemenuElem.querySelector("#sidemenu").classList.add("logged-in");
  95. }
  96. if (isModerator) {
  97. userlistElem.querySelector("#userlist").classList.add("tes-mod");
  98. chatlistElem.querySelector("#chatlist").classList.add("tes-mod");
  99. }
  100.  
  101. var settingsQuick = {
  102. "Autoscroll" : (GM_getValue("tes-Autoscroll") == "true" || GM_getValue("tes-Autoscroll") == undefined),
  103. "MentionsMonitor" : (GM_getValue("tes-MentionsMonitor") == "true" || GM_getValue("tes-MentionsMonitor") == undefined),
  104. "NotificationsOff" : (GM_getValue("tes-NotificationsOff") == "true"),
  105. "ChangeFont" : (GM_getValue("tes-ChangeFont") == "true" || GM_getValue("tes-ChangeFont") == undefined),
  106. "NightMode" : (GM_getValue("tes-NightMode") == "true"),
  107. "NightModeBlack" : (GM_getValue("tes-NightModeBlack") == "true" || GM_getValue("tes-NightModeBlack") == undefined),
  108. "MaxedCamLeft" : (GM_getValue("tes-MaxedCamLeft") == "true" || GM_getValue("tes-MaxedCamLeft") == undefined),
  109. "BorderlessCams" : (GM_getValue("tes-BorderlessCams") == "true"),
  110. "ChatBelow" : (GM_getValue("tes-ChatBelow") == "true")
  111. };
  112. if (settingsQuick["ChangeFont"]) bodyElem.classList.add("tes-changefont");
  113. if (settingsQuick["NightMode"]) nightmodeToggle(true);
  114. if (settingsQuick["MaxedCamLeft"]) videolistCSS.classList.add("tes-leftcam");
  115. if (settingsQuick["BorderlessCams"]) borderlessCamsToggle(true);
  116.  
  117. if (browserFirefox) {
  118. titleElem.querySelector("#room-header-info").insertAdjacentHTML("afterend", `
  119. <div id="tes-firefoxwarning" class="style-scope tinychat-title"
  120. style="font-size: .75em; background: white; color: grey; width: 200px; padding: 5px; line-height: 13px;vertical-align: middle;border: #ddd 1px solid;border-width: 0px 1px 0px 1px;">
  121. <div class="style-scope tinychat-title" style="display: table;height: 100%;">
  122. <span style="display: table-cell; vertical-align: middle;top: 16%;" class="style-scope tinychat-title">
  123. Tinychat Enhancement Suite requires Chrome. Other browsers only have autoscroll & cam maxing.
  124. </span>
  125. </div>
  126. </div>
  127. `);
  128. }
  129.  
  130. function waitForSettings() {
  131. try{
  132. if (browserFirefox) {
  133. clearInterval(settingsWaitInterval);
  134. return;
  135. }
  136. settingsVisible = false;
  137. if (titleElem.querySelector("#room-header-gifts") != null) {
  138. clearInterval(settingsWaitInterval);
  139. newCamAdded();
  140. newUserAdded();
  141. newMessageAdded();
  142. setTimeout(messageParserCheckCSS, 3000);
  143.  
  144. giftsElemWidth = titleElem.querySelector("#room-header-gifts").offsetWidth;
  145. if (titleElem.querySelector("#room-header-gifts-items") == null) {
  146. giftsElemWidth1000 = giftsElemWidth + 45;
  147. }
  148. else { giftsElemWidth1000 = giftsElemWidth; }
  149. if (titleCSS.querySelector("#titleCSS")) {
  150. titleCSS.querySelector("#titleCSS").innerHTML += `
  151. #tes-settings {
  152. right: ` + giftsElemWidth + `px;
  153. }
  154. `;
  155. }
  156.  
  157. settingsElem = titleElem.querySelector("#room-header-gifts").insertAdjacentHTML("beforebegin", `
  158. <div id="tes-settings">
  159. <div id="tes-settingsBox" class="hidden">
  160. <p id="title"><a href="https://greasyfork.org/en/scripts/32964-tinychat-enhancement-suite" target="_blank">Tinychat Enhancement Suite</a></p>
  161. <div id="tes-settings-mentions" class="tes-setting-container">
  162. <input type="checkbox">
  163. <span class="label">
  164. Alert phrases
  165. <span class="info" data-title='A comma-separated list of phrases to alert/highlight for. Example of 3 phrases: "hello,Google Chrome,sky"'>?</span>
  166. </span>
  167. <div class="inputcontainer">
  168. <input class="text"><button class="save blue-button">save</button>
  169. </div>
  170. </div>
  171. <div id="tes-settings-autoscroll" class="tes-setting-container">
  172. <input type="checkbox">
  173. <span class="label">
  174. Autoscroll
  175. </span>
  176. </div>
  177. <div id="tes-settings-notifications" class="tes-setting-container">
  178. <input type="checkbox">
  179. <span class="label">
  180. Hide notifications
  181. </span>
  182. </div>
  183. <div id="tes-settings-changefont" class="tes-setting-container">
  184. <input type="checkbox">
  185. <span class="label">
  186. Improve font
  187. <span class="info" data-title='The default font is too thin in some browsers'>?</span>
  188. </span>
  189. </div>
  190. <div id="tes-settings-nightmode" class="tes-setting-container">
  191. <input type="checkbox">
  192. <span class="label">
  193. Night mode
  194. </span>
  195. <span id="black"><input type="checkbox" class="nightmode-colors"><span class="sublabel">Black</span></span>
  196. <span id="gray"><input type="checkbox" class="nightmode-colors"><span class="sublabel">Gray</span></span>
  197. </div>
  198. <div id="tes-settings-maxcamposition" class="tes-setting-container right">
  199. <input type="checkbox">
  200. <span class="label">Maxed cam on left
  201. </span>
  202. </div>
  203. <div id="tes-settings-borderlesscams" class="tes-setting-container right">
  204. <input type="checkbox">
  205. <span class="label">Remove cam spacing
  206. </span>
  207. </div>
  208. <div id="tes-settings-chatbelow" class="tes-setting-container right">
  209. <input type="checkbox">
  210. <span class="label">force textchat below
  211. </span>
  212. </div>
  213. <!--
  214. <div id="tes-settings-messageanim" class="tes-setting-container">
  215. <input type="checkbox">
  216. <span class="label">
  217. Disable message animation
  218. </span>
  219. </div>
  220. -->
  221. </div>
  222. <div id="tes-updateNotifier"><a class="tes-closeButtonSmall">✕</a><span>New feature: night mode!</span></div>
  223. <div id="tes-settingsGear" title="Tinychat Enhancement Suite settings"><span>✱</span></div>
  224. </div>
  225. `);
  226.  
  227. titleElem.getElementById("tes-settingsGear").addEventListener("click", toggleSettingsDisplay);
  228. titleElem.getElementById("tes-updateNotifier").addEventListener("click", function(){toggleSettingsDisplay("updateNotifier");} );
  229. if (!freshInstall && GM_getValue("tes-updateNotifSeen") != "2018.05.30v29") titleElem.getElementById("tes-updateNotifier").classList.add("visible");
  230. titleElem.querySelector("#tes-settings #tes-settings-mentions button.save").addEventListener("click", function(){mentionsManager("save");} );
  231. !browserFirefox ? mentionsManager("load") : void(0);
  232.  
  233. settingsCheckboxUpdate();
  234. titleElem.querySelector("#tes-settings-autoscroll input").addEventListener("click", function(){settingsCheckboxUpdate("tes-settings-autoscroll");});
  235. titleElem.querySelector("#tes-settings-mentions input:first-of-type").addEventListener("click", function(){settingsCheckboxUpdate("tes-settings-mentions");});
  236. titleElem.querySelector("#tes-settings-notifications input:first-of-type").addEventListener("click", function(){settingsCheckboxUpdate("tes-settings-notifications");});
  237. titleElem.querySelector("#tes-settings-changefont input").addEventListener("click", function(){settingsCheckboxUpdate("tes-settings-changefont");});
  238. titleElem.querySelector("#tes-settings-nightmode input").addEventListener("click", function(){settingsCheckboxUpdate("tes-settings-nightmode");});
  239. titleElem.querySelector("#tes-settings-nightmode #black").addEventListener("click", function(){settingsCheckboxUpdate("tes-settings-nightmode-black");});
  240. titleElem.querySelector("#tes-settings-nightmode #gray").addEventListener("click", function(){settingsCheckboxUpdate("tes-settings-nightmode-gray");});
  241. titleElem.querySelector("#tes-settings-maxcamposition input").addEventListener("click", function(){settingsCheckboxUpdate("tes-settings-maxcamposition");});
  242. titleElem.querySelector("#tes-settings-borderlesscams input").addEventListener("click", function(){settingsCheckboxUpdate("tes-settings-borderlesscams");});
  243. titleElem.querySelector("#tes-settings-chatbelow input").addEventListener("click", function(){settingsCheckboxUpdate("tes-settings-chatbelow");});
  244. notificationHider();
  245. }
  246. }catch(e){tcl("error waitForSettings: " + e.message);}
  247. }
  248.  
  249. function nightmodeToggle(arg) {
  250. try{
  251. var nightmodeClasses = ["tes-nightmode"];
  252.  
  253. if (settingsQuick["NightModeBlack"]) nightmodeClasses.push("blacknight");
  254.  
  255. if (arg == true) {
  256. bodyElem.classList.add(...nightmodeClasses);
  257. titleCSS.classList.add(...nightmodeClasses);
  258. sidemenuCSS.classList.add(...nightmodeClasses);
  259. userlistCSS.classList.add(...nightmodeClasses);
  260. webappCSS.classList.add(...nightmodeClasses);
  261. videolistCSS.classList.add(...nightmodeClasses);
  262. videomoderationCSS.classList.add(...nightmodeClasses);
  263. chatlistCSS.classList.add(...nightmodeClasses);
  264. chatlogCSS.classList.add(...nightmodeClasses);
  265. chatlogElem.querySelector("#chat-wider").classList.add(...nightmodeClasses);
  266. // Messages:
  267. if (chatlogElem.querySelector(messageQueryString) != null) {
  268. var messageElems = chatlogElem.querySelectorAll(messageQueryString);
  269. for (i=0; i < messageElems.length; i++) {
  270. var messageItem = messageElems[i].querySelector("tc-message-html").shadowRoot;
  271. var messageItemCSS = messageItem.querySelector(".message");
  272. messageItemCSS.classList.add(...nightmodeClasses);
  273. }
  274. }
  275. // Cams:
  276. if (videolistElem.querySelector(camQueryString) != null) {
  277. var camElems = videolistElem.querySelectorAll(camQueryString);
  278. for (i=0; i < camElems.length; i++) {
  279. var camItem = camElems[i].querySelector("tc-video-item").shadowRoot;
  280. var camItemCSS = camItem.querySelector(".video");
  281. camItemCSS.classList.add(...nightmodeClasses);
  282.  
  283. if (camItemCSS.querySelector("#camItemCSS") == null) camItemCSS.insertAdjacentHTML("afterbegin", camItemCSShtml);
  284. }
  285. }
  286. }
  287. if (arg == false) {
  288. if (!settingsQuick["NightModeBlack"] && settingsQuick["NightMode"]) nightmodeClasses = ["blacknight"];
  289.  
  290. bodyElem.classList.remove(...nightmodeClasses);
  291. titleCSS.classList.remove(...nightmodeClasses);
  292. sidemenuCSS.classList.remove(...nightmodeClasses);
  293. userlistCSS.classList.remove(...nightmodeClasses);
  294. webappCSS.classList.remove(...nightmodeClasses);
  295. videolistCSS.classList.remove(...nightmodeClasses);
  296. videomoderationCSS.classList.remove(...nightmodeClasses);
  297. chatlistCSS.classList.remove(...nightmodeClasses);
  298. chatlogCSS.classList.remove(...nightmodeClasses);
  299. chatlogElem.querySelector("#chat-wider").classList.remove(...nightmodeClasses);
  300. // Messages:
  301. if (chatlogElem.querySelector(messageQueryString) != null) {
  302. var messageElems = chatlogElem.querySelectorAll(messageQueryString);
  303. for (i=0; i < messageElems.length; i++) {
  304. var messageItem = messageElems[i].querySelector("tc-message-html").shadowRoot;
  305. var messageItemCSS = messageItem.querySelector(".message");
  306. messageItemCSS.classList.remove(...nightmodeClasses);
  307. }
  308. }
  309. // Cams:
  310. if (videolistElem.querySelector(camQueryString) != null) {
  311. var camElems = videolistElem.querySelectorAll(camQueryString);
  312. for (i=0; i < camElems.length; i++) {
  313. var camItem = camElems[i].querySelector("tc-video-item").shadowRoot;
  314. var camItemCSS = camItem.querySelector(".video");
  315. camItemCSS.classList.remove(...nightmodeClasses);
  316. }
  317. }
  318. }
  319. }catch(e){tcl("error nightmodeToggle: " + e.message);}
  320. }
  321.  
  322. function toggleSettingsDisplay(arg) {
  323. try{
  324. if (arg == "updateNotifier") {
  325. titleElem.querySelector("#tes-updateNotifier").classList.remove("visible");
  326. GM_setValue("tes-updateNotifSeen", "2018.05.30v29");
  327. }
  328.  
  329. if (settingsVisible == true) {
  330. titleElem.getElementById("tes-settingsBox").classList.add("hidden");
  331. titleElem.getElementById("tes-settings").classList.remove("tes-open");
  332. settingsVisible = false;
  333. }
  334.  
  335. else {
  336. titleElem.getElementById("tes-settingsBox").classList.remove("hidden");
  337. titleElem.getElementById("tes-settings").classList.add("tes-open");
  338. settingsVisible = true;
  339. }
  340. }catch(e){tcl("error toggleSettingsDisplay: " + e.message);}
  341. }
  342.  
  343. function settingsCheckboxUpdate(settingName=null, value=null) {
  344. try{
  345. if (settingName == null && value == null) {
  346. titleElem.getElementById("tes-settings-autoscroll").querySelector("input").checked = settingsQuick["Autoscroll"];
  347. titleElem.getElementById("tes-settings-mentions").querySelector("input").checked = settingsQuick["MentionsMonitor"];
  348. titleElem.getElementById("tes-settings-notifications").querySelector("input").checked = settingsQuick["NotificationsOff"];
  349. titleElem.getElementById("tes-settings-changefont").querySelector("input").checked = settingsQuick["ChangeFont"];
  350. titleElem.getElementById("tes-settings-nightmode").querySelector("input").checked = settingsQuick["NightMode"];
  351. titleElem.getElementById("tes-settings-maxcamposition").querySelector("input").checked = settingsQuick["MaxedCamLeft"];
  352. titleElem.getElementById("tes-settings-borderlesscams").querySelector("input").checked = settingsQuick["BorderlessCams"];
  353. titleElem.getElementById("tes-settings-chatbelow").querySelector("input").checked = settingsQuick["ChatBelow"];
  354. titleElem.querySelector("#tes-settings-nightmode #black input").checked = settingsQuick["NightModeBlack"];
  355. titleElem.querySelector("#tes-settings-nightmode #gray input").checked = (settingsQuick["NightModeBlack"] == false);
  356.  
  357. return;
  358. }
  359. if (settingName == "tes-settings-autoscroll") {
  360. if (value == null) {
  361. var newValue = titleElem.getElementById("tes-settings-autoscroll").querySelector("input").checked;
  362. settingsQuick["Autoscroll"] = newValue;
  363. GM_setValue("tes-Autoscroll", newValue.toString());
  364. }
  365. }
  366. if (settingName == "tes-settings-mentions") {
  367. if (value == null) {
  368. var newValue = titleElem.getElementById("tes-settings-mentions").querySelector("input:first-of-type").checked;
  369. // if (newValue) {
  370. // titleElem.getElementById("tes-settings-mentions").getAttribute("class").includes("setting-disabled");
  371. // }
  372. settingsQuick["MentionsMonitor"] = newValue;
  373. GM_setValue("tes-MentionsMonitor", newValue.toString());
  374. }
  375. }
  376. if (settingName == "tes-settings-notifications") {
  377. if (value == null) {
  378. var newValue = titleElem.getElementById("tes-settings-notifications").querySelector("input").checked;
  379. settingsQuick["NotificationsOff"] = newValue;
  380. GM_setValue("tes-NotificationsOff", newValue.toString());
  381. notificationHider();
  382. }
  383. }
  384. if (settingName == "tes-settings-changefont") {
  385. if (value == null) {
  386. var newValue = titleElem.getElementById("tes-settings-changefont").querySelector("input").checked;
  387. settingsQuick["ChangeFont"] = newValue;
  388. GM_setValue("tes-ChangeFont", newValue.toString());
  389. fontToggle(newValue);
  390. }
  391. }
  392. if (settingName == "tes-settings-nightmode") {
  393. if (value == null) {
  394. var newValue = titleElem.getElementById("tes-settings-nightmode").querySelector("input").checked;
  395. settingsQuick["NightMode"] = newValue;
  396. GM_setValue("tes-NightMode", newValue.toString());
  397. nightmodeToggle(newValue);
  398. }
  399. }
  400. if (settingName == "tes-settings-nightmode-black") {
  401. if (value == null) {
  402. var newValue = titleElem.querySelector("#tes-settings-nightmode #black input").checked;
  403. titleElem.querySelector("#tes-settings-nightmode #gray input").checked = (!newValue);
  404. settingsQuick["NightModeBlack"] = newValue;
  405. GM_setValue("tes-NightModeBlack", newValue.toString());
  406. nightmodeToggle(newValue);
  407. nightmodeToggle(true);
  408.  
  409. if (titleElem.querySelector("#tes-settings-nightmode #black input").checked || titleElem.querySelector("#tes-settings-nightmode #gray input").checked) {
  410. titleElem.querySelector("#tes-settings-nightmode > input").checked = true;
  411. GM_setValue("tes-NightMode", true.toString());
  412. settingsQuick["NightMode"] = true;
  413. }
  414. }
  415. }
  416. if (settingName == "tes-settings-nightmode-gray") {
  417. if (value == null) {
  418. var newValue = (!titleElem.querySelector("#tes-settings-nightmode #gray input").checked);
  419. titleElem.querySelector("#tes-settings-nightmode #black input").checked = newValue;
  420. settingsQuick["NightModeBlack"] = newValue;
  421. GM_setValue("tes-NightModeBlack", newValue.toString());
  422. nightmodeToggle(newValue);
  423. nightmodeToggle(true);
  424.  
  425. if (titleElem.querySelector("#tes-settings-nightmode #black input").checked || titleElem.querySelector("#tes-settings-nightmode #gray input").checked) {
  426. titleElem.querySelector("#tes-settings-nightmode > input").checked = true;
  427. GM_setValue("tes-NightMode", true.toString());
  428. settingsQuick["NightMode"] = true;
  429. }
  430. }
  431. }
  432. if (settingName == "tes-settings-maxcamposition") {
  433. if (value == null) {
  434. var newValue = titleElem.getElementById("tes-settings-maxcamposition").querySelector("input").checked;
  435. settingsQuick["MaxedCamLeft"] = newValue;
  436. GM_setValue("tes-MaxedCamLeft", newValue.toString());
  437. maxCamPositionToggle(newValue);
  438. }
  439. }
  440. if (settingName == "tes-settings-borderlesscams") {
  441. if (value == null) {
  442. var newValue = titleElem.getElementById("tes-settings-borderlesscams").querySelector("input").checked;
  443. settingsQuick["BorderlessCams"] = newValue;
  444. GM_setValue("tes-BorderlessCams", newValue.toString());
  445. borderlessCamsToggle(newValue);
  446. }
  447. }
  448. if (settingName == "tes-settings-chatbelow") {
  449. if (value == null) {
  450. var newValue = titleElem.getElementById("tes-settings-chatbelow").querySelector("input").checked;
  451. settingsQuick["ChatBelow"] = newValue;
  452. GM_setValue("tes-ChatBelow", newValue.toString());
  453. chatBelowToggle(newValue);
  454. }
  455. }
  456. }catch(e){tcl("error settingsCheckboxUpdate: " + e.message);}
  457. }
  458.  
  459. function fontToggle(arg) {
  460. arg ? bodyElem.classList.add("tes-changefont") : bodyElem.classList.remove("tes-changefont");
  461. }
  462.  
  463. function borderlessCamsToggle(arg) {
  464. try{
  465. if (videolistElem.querySelector(camQueryString) != null) {
  466. var camElems = videolistElem.querySelectorAll(camQueryString);
  467. for (i=0; i < camElems.length; i++) {
  468. var camItem = camElems[i].querySelector("tc-video-item").shadowRoot;
  469. var camElem = camItem.querySelector(".video");
  470. arg ? camElem.classList.add("tes-borderlesscams") : camElem.classList.remove("tes-borderlesscams");
  471. }
  472. }
  473. arg ? videolistCSS.classList.add("tes-borderlesscams") : videolistCSS.classList.remove("tes-borderlesscams");
  474. }catch(e){tcl("error borderlessCamsToggle: " + e.message);}
  475. }
  476. function maxCamPositionToggle(arg) {
  477. try{
  478. arg ? videolistCSS.classList.add("tes-leftcam") : videolistCSS.classList.remove("tes-leftcam");
  479. }catch(e){tcl("error maxCamPositionToggle: " + e.message);}
  480. }
  481.  
  482. function notificationHider() {
  483. try{
  484. chatlogContainer = chatlogElem.querySelector("#chat-content");
  485. settingsQuick["NotificationsOff"] ? chatlogContainer.classList.add("tes-notif-off") : chatlogContainer.classList.remove("tes-notif-off");
  486. }catch(e){tcl("error notificationHider: " + e.message);}
  487. }
  488.  
  489.  
  490.  
  491. function chatBelowToggle(arg) {
  492. try{
  493. var chatlogOuter = webappElem.children[2].children[1];
  494. arg ? chatlogOuter.classList.add("tes-chatbelow") : chatlogOuter.classList.remove("tes-chatbelow");
  495.  
  496. }catch(e){tcl("error chatBelow: " + e.message);}
  497. }
  498. function copyChatlog(opt=null) {
  499. try{
  500. if (opt == "close") {
  501. chatlogDisplayElem.classList.remove("show");
  502. chatlogDisplayClose.classList.remove("show");
  503. setTimeout(function(){chatlogDisplayCont.classList.remove("show");}, 300);
  504. return;
  505. }
  506.  
  507. var filename = "tinychat_" + roomName + "_" + joinDate + "_" + joinTime.replace(/:/g, ".") + "-chatlog.log";
  508. var chatlogText = "Tinychat room " + roomName + " on " + joinDate + " " + joinTime + newline + chatlogMain;
  509.  
  510. var downloadLink = 'data:text/plain;charset=utf-8,' + encodeURIComponent(chatlogText);
  511. var downloadElem = document.createElement('a');
  512. downloadElem.setAttribute("href", downloadLink);
  513.  
  514. downloadElem.setAttribute("download", filename);
  515.  
  516. if (opt == "download") downloadElem.click();
  517. if (opt == "view" || opt == null) {
  518. if (typeof chatlogDisplayCont == "undefined") {
  519. chatlogDisplayCont = chatlogElem.querySelector("#tes-chatlogDisplay");
  520. chatlogDisplayElem = chatlogDisplayCont.querySelector("textarea");
  521. chatlogDisplayClose = chatlogDisplayCont.querySelector("#close");
  522. }
  523. chatlogDisplayElem.value = chatlogText;
  524. chatlogDisplayCont.classList.add("show");
  525. setTimeout(function(){
  526. chatlogDisplayElem.classList.add("show");
  527. chatlogDisplayClose.classList.add("show");
  528. }, 50);
  529. chatlogDisplayElem.scrollTop = chatlogDisplayElem.scrollHeight;
  530. }
  531. }catch(e){tcl("error copyChatlog: " + e.message);}
  532. }
  533.  
  534. function getFormattedDateTime(d, opt=null) {
  535. try{
  536. if (opt == "time") return d.toLocaleTimeString('en-US', { hour12: false });
  537. else return d.toLocaleDateString('zh-CN', {'year':'numeric', 'month':'2-digit', 'day':'2-digit'}).replace(/\//g, "-");
  538. }catch(e){tcl("error getFormattedDateTime: " + e.message);}
  539. }
  540.  
  541. function mentionsManager(mode) {
  542. try{
  543. var inputElem = titleElem.querySelector("#tes-settings #tes-settings-mentions input.text");
  544. // phrases = inputElem.value.split(",");
  545. var phrase = inputElem.value;
  546. if (phrase.endsWith(",")) { phrase = phrase.slice(0, -1); }
  547. if (phrase.startsWith(",")) { phrase = phrase.slice(1); }
  548.  
  549. if (mode == "save") {
  550. GM_setValue("tes-Mentions", phrase);
  551. settingMentions = phrase.split(",");
  552. inputElem.value = phrase;
  553. }
  554. if (mode == "load") {
  555. var loadedMentions = GM_getValue("tes-Mentions");
  556. if (loadedMentions != undefined) {
  557. inputElem.value = loadedMentions;
  558. settingMentions = loadedMentions.split(",");
  559. }
  560. }
  561. return;
  562.  
  563. var phrase = phrase.toString();
  564. if (mode == "save") {
  565. settingMentions.push(phrases);
  566. GM_setValue("tes-Mentions", JSON.stringify(setting_Mentions));
  567. }
  568. if (mode == "load") {
  569. var mentions = JSON.parse(GM_getValue("tes-Mentions"));
  570. settingMentions = mentions;
  571. inputElem.value = settingMentions.join();
  572. }
  573. }catch(e){tcl("error mentionsManager: " + e.message);}
  574. }
  575.  
  576. function declareGlobalVars() {
  577. try{
  578. globalCSS = `:root {
  579. --textcolor: black;
  580.  
  581. --nightmode-bgcolor: #2d373a;
  582. --nightmode-trimcolor: #3c4a4e;
  583. --nightmode-textcolor: #9faaad;
  584. --nightmode-textSecondarycolor: #4e5f65;
  585. --nightmode-headerButtonscolor: #3986a7;
  586.  
  587. --nightmodeBlack-bgcolor: black;
  588.  
  589. }`;
  590.  
  591. camItemCSShtml = `
  592. <style id="camItemCSS">` + globalCSS + `
  593. .icon-tes-max {
  594. position: absolute;
  595. top: -40%;
  596. right: 0;
  597. z-index: 9;
  598. background: none;
  599. border: 0;
  600. }
  601. .icon-tes-max:hover { cursor: pointer; }
  602. .icon-tes-max path { fill: #04caff; }
  603.  
  604. .video:hover .icon-tes-max {
  605. top: 40%;
  606. transition: top .2s ease .2s,
  607. left .2s ease .2s,
  608. right .2s ease .2s,
  609. opacity .2s;
  610. }
  611.  
  612. /* Disable cam border
  613. .video:after { border: none; }
  614. .video > div { background-color: unset; }
  615. video,
  616. .video > div > .overlay {
  617. border-radius: 10px;
  618. }
  619. */
  620. .video { transition: .4s; }
  621. .tes-borderlesscams.video { padding: 0; }
  622. .tes-borderlesscams.video:after { display: none; }
  623. .tes-nightmode.video:after { border-color: var(--nightmode-bgcolor); }
  624. .tes-nightmode.blacknight.video:after { border-color: var(--nightmodeBlack-bgcolor); }
  625. .tes-nightmode.blacknight.video > div > .waiting { background: #111; }
  626. .tes-nightmode.blacknight.video > div { background-color: #111; }
  627. </style>
  628. `;
  629. camMaxCSShtml = `
  630. <style id="camMaxCSS">` + globalCSS + `
  631. .tes-max .js-video {
  632. width: 15%!important;
  633. z-index: 1;
  634. }
  635. .tes-leftcam .tes-max .js-video {
  636. float: right;
  637. order: 2;
  638. }
  639. .tes-leftcam .tes-max .tes-maxedCam {
  640. float: left;
  641. order: 1;
  642. }
  643.  
  644. .tes-max.tes-camCount2 .js-video { width: 30%!important; }
  645. .tes-max.tes-camCount10-11 .js-video { width: 14%!important; }
  646. .tes-max.tes-camCount12 .js-video { width: 12%!important; }
  647.  
  648. :not(.hidden) + .tes-max.tes-camCount12 .js-video,
  649. :not(.hidden) + .tes-max.tes-camCount10-11 .js-video,
  650. :not(.hidden) + .tes-max .js-video
  651. { width: 30%!important; }
  652. :not(.hidden) + .tes-max.tes-camCount2 .js-video { width: 60%!important; }
  653.  
  654. .tes-max .js-video.tes-maxedCam,
  655. :not(.hidden) + .tes-max .js-video.tes-maxedCam { width: 70%!important; }
  656. </style>
  657. `;
  658.  
  659. camMaxButtonHtml = `
  660. <button class="icon-tes-max" id="maxbutton-camName">
  661. <svg width="18" height="18" viewBox="0 0 18 18" xmlns="http://www.w3.org/2000/svg">
  662. <path d="M14.37 12.95l3.335 3.336a1.003 1.003 0 1 1-1.42 1.42L12.95 14.37a8.028 8.028 0 1 1 1.42-1.42zm-6.342 1.1a6.02 6.02 0 1 0 0-12.042 6.02 6.02 0 0 0 0 12.042zM6.012 9.032a.996.996
  663. 0 0 1-.994-1.004c0-.554.452-1.003.994-1.003h4.033c.55 0 .994.445.994 1.003 0 .555-.454 1.004-.995 1.004H6.012z" fill-rule="evenodd"></path>
  664. <path d="M0 .99C0 .445.444 0 1 0a1 1 0 0 1 1 .99v4.02C2 5.555 1.556 6 1 6a1 1 0 0 1-1-.99V.99z" transform="translate(7 5)" fill-rule="evenodd"></path>
  665. </svg>
  666. </button>
  667. `;
  668. }catch(e){tcl("error declareGlobalVars: " + e.message);}
  669. }
  670.  
  671. function injectCSS(cssName=null) {
  672. try{
  673. // Indenting is purposely wrong, for readability
  674. var insertPosition = "beforeend";
  675. headElem = document.querySelector("head");
  676. if (browserFirefox) {
  677. titleCSS = videolistCSS = chatlistCSS = userlistCSS = userContextmenuCSS = bodyCSS = chatlogCSS = sidemenuCSS = videomoderationCSS = webappCSS = headElem;
  678. headElem.querySelector('[scope="tinychat-title"]').innerHTML += ` #room-header { min-height: 10%; max-height: 10%; } `;
  679. }
  680. browserSpoofedChrome = (headElem.innerHTML.includes("Shady DOM styles for") ? true : false);
  681. if (browserSpoofedChrome) tcl("browserSpoofedChrome");
  682.  
  683. { // titleCSS
  684. titleCSShtml = `
  685. <style id="titleCSS" scope="tinychat-title">` + globalCSS + `
  686. @keyframes ease-to-left {
  687. 0% {right: -50px; opacity: 0;}
  688. 100% {right: 0; opacity: 1;}
  689. }
  690. @keyframes ease-to-right {
  691. 0% {right:auto;}
  692. 100% {right:0;}
  693. }
  694. @keyframes ease-to-bottom-21px {
  695. 0% {top:-300px; opacity: 0;}
  696. 100% {top:0; opacity: 1;}
  697. }
  698. #tes-header-grabber {
  699. position: absolute;
  700. top: 88px;
  701. right: 50%;
  702. background: white;
  703. width: 60px;
  704. height: 20px;
  705. border: #ddd 1px solid;
  706. border-radius: 19px;
  707. text-align: center;
  708. color: #b4c1c5;
  709. cursor: pointer;
  710. transition: .4s;
  711. }
  712. #tes-header-grabber:hover {
  713. background: #e9eaea;
  714. z-index: 1;
  715. border-bottom: 0px;
  716. }
  717. .tes-headerCollapsed #tes-header-grabber {
  718. top: 9px;
  719. background: #f6f6f6;
  720. border-top: 0;
  721. z-index: 9;
  722. border-radius: 11px;
  723. line-height: 11px;
  724. border-top-left-radius: 0;
  725. border-top-right-radius: 0;
  726. height: 12px;
  727. }
  728. .tes-headerCollapsed:hover #tes-header-grabber {
  729. height: 29px;
  730. line-height: 43px;
  731. }
  732. input {
  733. border: 1px solid #c4d4dc;
  734. line-height: 16px;
  735. padding-left: 3px;
  736. }
  737. .label ~ input {
  738. border-bottom-left-radius: 6px;
  739. border-top-left-radius: 6px;
  740. }
  741. input ~ button {
  742. border-bottom-right-radius: 6px;
  743. border-top-right-radius: 6px;
  744. }
  745. input[type="button"], button {
  746. display: inline;
  747. padding: 0 15px;
  748. border: 0;
  749. box-sizing: border-box;
  750. letter-spacing: 1px;
  751. font-size: 12px;
  752. font-weight: bold;
  753. line-height: 20px;
  754. text-align: center;
  755. transition: .2s;
  756. outline: none;
  757. }
  758. .blue-button {
  759. color: #fff;
  760. background-color: #41b7ef;
  761. }
  762. .blue-button:hover {
  763. background-color: #54ccf3;
  764. }
  765. .blue-button:active {
  766. background-color: #38a8dd;
  767. }
  768. .tes-setting-container {
  769. line-height: initial;
  770. }
  771. #tes-settings { color: var(--textcolor); }
  772. #tes-settings > div {
  773. /*animation: ease-to-bottom-21px .2s ease 0s 1;*/
  774. position: relative;
  775. top: 0;
  776. height: 100px;
  777. }
  778. @media screen and (max-width: 1000px) {
  779. #tes-settings > div {
  780. height: 92px;
  781. }
  782. }
  783. #tes-settings .hidden { display: none; }
  784. #tes-settings #title { font-weight: bold; }
  785. #tes-settings {
  786. transition: all .4s ease-in-out;
  787. animation: ease-to-bottom-21px .2s ease 0s 1;
  788. /*max-height: 10%;*/
  789. font-size: 11px;
  790. flex: none;
  791. overflow: hidden;
  792. z-index: 7;
  793. position: absolute;
  794. top: -2px;
  795. right: ` + (giftsElemWidth + 10).toString() + `px;
  796. }
  797. @media screen and (max-width: 1000px) {
  798. #tes-settings {
  799. right: 37px!important;
  800. top: -20px;
  801. }
  802. #tes-settings.tes-open {
  803. top: 6px;
  804. }
  805. #tes-settingsGear {
  806. font-size: 52px!important;
  807. }
  808. #room-header-gifts-buttons > #give-gift {
  809. width: 102px;
  810. }
  811. }
  812. @media screen and (max-width: 600px) {
  813. #tes-settings {
  814. right: -4px!important;
  815. top: 19px;
  816. }
  817. }
  818. #tes-settings:hover {
  819. overflow: visible;
  820. }
  821. #tes-settings-mentions .inputcontainer {
  822. float: right;
  823. position: relative;
  824. top: -3px;
  825. }
  826. #tes-settingsGear {
  827. font-size: 70px;
  828. color: #38cd57;
  829. color: #53b6ef;
  830. float: right;
  831. }
  832. #tes-settingsGear:hover {
  833. cursor: pointer;
  834. color: #7ccefe;
  835. }
  836. .tes-open #tes-settingsGear {
  837. background: white;
  838. border-bottom-right-radius: 15px;
  839. border-top-right-radius: 15px;
  840. border: #ddd 1px solid;
  841. border-left: 0;
  842. /*transition: all .2s linear;*/
  843. }
  844. #tes-settingsGear span {
  845. display: block;
  846. transition: transform 0.4s ease-in-out;
  847. }
  848. .tes-open #tes-settingsGear span {
  849. transform: rotate(-90deg);
  850. }
  851. #tes-settingsBox {
  852. background: white;
  853. padding: 0px 10px 0px 10px;
  854. float: left;
  855. border: #53b6ef 1px solid;
  856. border-top-left-radius: 12px;
  857. border-bottom-left-radius: 12px;
  858. animation: ease-to-left .2s ease 0s 1;
  859. right: 0;
  860. }
  861. #tes-settingsBox.hidden {
  862. animation: ease-to-right .2s ease 0s 1;
  863. display: visible;
  864. /*position: relative; right: -1000px;*/
  865. }
  866. #tes-settings-nightmode .nightmode-colors {
  867. width: 0px;
  868. height: 0px;
  869. }
  870. #tes-settings-nightmode .nightmode-colors:after {
  871. content: " ";
  872. border-radius: 3px;
  873. height: 11px;
  874. width: 11px;
  875. margin-left: 3px;
  876. top: -9px;
  877. position: relative;
  878. display: block;
  879. }
  880. #tes-settings-nightmode .nightmode-colors:checked:after {
  881. border: #41a9c1 1px solid;
  882. }
  883. #black .nightmode-colors:after { background: black; }
  884. #gray .nightmode-colors:after { background: #575e60; }
  885. #tes-settings-nightmode .sublabel { margin-left: 15px; }
  886.  
  887. /*** Inline with header ***/
  888. #tes-settingsBox {
  889. border-bottom-width: 0;
  890. border-top-left-radius: 0px;
  891. border-bottom-left-radius: 0px;
  892. }
  893. #tes-settingsGear {
  894. display: table;
  895. }
  896. #tes-settingsGear span {
  897. display: table-cell;
  898. vertical-align: middle;
  899. }
  900. /*** ************* ***/
  901.  
  902. #tes-settings .tes-setting-container > input[type=checkbox]:first-child {
  903. margin: 0;
  904. margin-right: 1px;
  905. float: left;
  906. position: absolute;
  907. left: 8px;
  908. }
  909. #tes-settings .right {
  910. position: absolute;
  911. left: 189px;
  912. }
  913. #tes-settings-maxcamposition { top: 54px; }
  914. #tes-settings-borderlesscams { top: 67px; }
  915. #tes-settings .label {
  916. margin-right: 4px;
  917. margin-left: 16px;
  918. }
  919. #tes-settings .right .label {
  920. margin-left: 24px;
  921. }
  922. #tes-settings .info{
  923. margin-left: 3px;
  924. color: #0d94e3;
  925. font-weight: bold;
  926. font-family: Arial;
  927. border: #0d94e3 1px solid;
  928. border-radius: 16px;
  929. height: 1em;
  930. width: 1em;
  931. text-align: center;
  932. display: inline-block;
  933. }
  934. #tes-settings .info:hover:after{
  935. font-weight: normal;
  936. padding: 4px 7px 4px 7px;
  937. border-radius: 7px;
  938. color: white;
  939. background: #61787f;
  940. content: attr(data-title);
  941. display: inline-block;
  942. position: absolute;
  943. top: 52px;
  944. left: 0;
  945. z-index: 9;
  946. }
  947. /*#tes-settings .label:hover:before{
  948. border: solid;
  949. border-color: #61787f transparent;
  950. border-width: 0px 6px 6px 6px;
  951. top: 10px;
  952. content: "";
  953. left: 8%;
  954. position: relative;
  955. display: inline-block;
  956. }*/
  957.  
  958. #tes-settings a:visited, #tes-settings a:link {
  959. text-decoration: none;
  960. color: inherit;
  961. }
  962. #tes-settings a:hover {
  963. color: #53b6ef;
  964. }
  965.  
  966. #room-header {
  967. height: 100px;
  968. max-height: unset;
  969. min-height: unset;
  970. transition: all .4s ease-in-out;
  971. }
  972. #room-header.tes-headerCollapsed {
  973. height: 10px;
  974. }
  975. #room-header.tes-headerCollapsed:hover {
  976. height: 27px;
  977. }
  978. @media screen and (max-width: 600px) {
  979. #room-header {
  980. min-height: inherit;
  981. max-height: inherit;
  982. }
  983. }
  984. #room-header-info {
  985. padding: 0;
  986. padding-right: 45px;
  987. }
  988. #room-header-info-text {
  989. height: auto;
  990. }
  991. @media screen and (max-width: 600px) {
  992. #room-header-info-text {
  993. height: inherit;
  994. }
  995. }
  996. #room-header-avatar {
  997. margin: 2px 10px 0 35px;
  998. height: 90px;
  999. min-width: 90px;
  1000. max-width: 90px;
  1001. transition: all .5s linear;
  1002. }
  1003. #room-header-avatar:hover {
  1004. border-radius: unset;
  1005. }
  1006. .tes-headerCollapsed:hover #room-header-avatar:hover {
  1007. z-index: 9;
  1008. }
  1009. #room-header-gifts {
  1010. padding: 10px 10px;
  1011. }
  1012.  
  1013. .tes-headerCollapsed #tes-settingsGear {
  1014. font-size: 33px;
  1015. }
  1016. .tes-headerCollapsed #tes-settings > div {
  1017. height: fit-content;
  1018. }
  1019. .tes-headerCollapsed #tes-settingsBox {
  1020. border-width: 1px;
  1021. border-radius: 7px;
  1022. border-top-right-radius: 0;
  1023. padding-bottom: 7px;
  1024. }
  1025. .tes-headerCollapsed #tes-settings {
  1026. top: 13px;
  1027. right: 0;
  1028. }
  1029. #tes-settings > div#tes-updateNotifier {
  1030. top: -200px;
  1031. margin-right: -33px;
  1032. float: left;
  1033. border: #53b6ef 1px solid;
  1034. border-radius: 8px 0 0px 8px;
  1035. padding: 5px;
  1036. padding-right: 32px;
  1037. height: auto;
  1038. transition: visibility 0s, opacity 0.5s linear;
  1039. background: white;
  1040. }
  1041. #tes-settings.tes-open > div#tes-updateNotifier {
  1042. visibility: hidden;
  1043. opacity: 0;
  1044. width: 0;
  1045. height: 0;
  1046. padding: 0;
  1047. }
  1048. #tes-settings > div#tes-updateNotifier:hover { cursor: pointer; }
  1049. .tes-closeButtonSmall {
  1050. float: left;
  1051. padding-right: 5px;
  1052. color: #41b7ef;
  1053. padding-left: 5px;
  1054. }
  1055. #tes-settings > div#tes-updateNotifier.visible { top: 38px; }
  1056. .tes-closeButtonSmall:hover { color: #7ccefe; }
  1057.  
  1058. #room-header.tes-nightmode,
  1059. .tes-nightmode #tes-header-grabber {
  1060. background-color: var(--nightmode-bgcolor);
  1061. border-color: var(--nightmode-trimcolor);
  1062. }
  1063. #room-header.tes-nightmode.blacknight,
  1064. .tes-nightmode.blacknight #tes-header-grabber {
  1065. background-color: var(--nightmodeBlack-bgcolor);
  1066. border-color: #222;
  1067. border-bottom-color: #222;
  1068. }
  1069. .tes-nightmode #tes-header-grabber:hover { background-color: var(--nightmode-trimcolor); }
  1070. .tes-nightmode.blacknight #tes-header-grabber:hover { background-color: #141414; }
  1071. .tes-nightmode #room-header-info-details > span:after { background-color: var(--nightmode-bgcolor); }
  1072. .tes-nightmode.blacknight #room-header-info-details > span:after { background-color: var(--nightmodeBlack-bgcolor); }
  1073. .tes-nightmode #tes-header-grabber { color: #565e61; }
  1074. .tes-nightmode #room-header-info > h1 { color: var(--nightmode-textcolor); }
  1075. .tes-nightmode #room-header-info > h1:after,
  1076. .tes-nightmode #room-header-info-text:after {
  1077. opacity: 0;
  1078. }
  1079. .tes-nightmode #room-header-gifts-items { background-color: #313c3f; }
  1080. .tes-nightmode #room-header-gifts-items > a > img { mix-blend-mode: multiply; }
  1081. .tes-nightmode #room-header-gifts-items:hover > a > img { mix-blend-mode: unset; }
  1082. .tes-nightmode #room-header-info-details > a { color: #417186; }
  1083. .tes-nightmode #tes-settings { color: #98a1a4; }
  1084. .tes-nightmode #tes-settingsGear { color: #145876; }
  1085. .tes-nightmode #tes-settingsGear:hover { color: #1c7ca6; }
  1086. .tes-nightmode #tes-settingsBox,
  1087. .tes-nightmode .tes-open #tes-settingsGear {
  1088. background-color: #354245;
  1089. border-color: var(--nightmode-trimcolor);
  1090. }
  1091. .tes-nightmode.blacknight #tes-settingsBox,
  1092. .tes-nightmode.blacknight .tes-open #tes-settingsGear {
  1093. background-color: #222;
  1094. border-color: #333;
  1095. }
  1096. .tes-nightmode #tes-settings > div#tes-updateNotifier { border-color: #5d7883; }
  1097. .tes-nightmode #tes-settings > div#tes-updateNotifier {
  1098. background-color: #354245;
  1099. border-color: #145876;
  1100. }
  1101. .tes-nightmode input {
  1102. background: #626b6f;
  1103. color: #c4c8ca;
  1104. border-color: #79868b;
  1105. }
  1106. .tes-nightmode.blacknight input {
  1107. background: #444;
  1108. border-color: #666;
  1109. }
  1110. .tes-nightmode #tes-settings .info {
  1111. color: var(--nightmode-headerButtonscolor);
  1112. border-color: var(--nightmode-headerButtonscolor);
  1113. }
  1114. .tes-nightmode path { fill: var(--nightmode-headerButtonscolor); }
  1115. .tes-nightmode circle { stroke: var(--nightmode-headerButtonscolor); }
  1116. @media screen and (max-width: 800px) {
  1117. .tes-nightmode #room-header-gifts { background-color: var(--nightmode-bgcolor); }
  1118. .tes-nightmode.blacknight #room-header-gifts { background-color: var(--nightmodeBlack-bgcolor); }
  1119. }
  1120. .tes-nightmode #room-header-gifts-buttons > #upgrade { background-color: #6d551d; }
  1121. .tes-nightmode #room-header-gifts-buttons > #upgrade:hover { background-color: #776231; }
  1122. .tes-nightmode #room-header-gifts-buttons > #get-coins {
  1123. background-color: #3a474b;
  1124. border-color: #275b72;
  1125. color: #317490;
  1126. }
  1127. .tes-nightmode.blacknight #room-header-gifts-buttons > #get-coins { background-color: #222; }
  1128. .tes-nightmode #room-header-gifts-buttons > #get-coins:hover {
  1129. background-color: #48626a;
  1130. color: #5fa9c8;
  1131. }
  1132. .tes-nightmode #room-header-gifts-buttons > a {
  1133. background-color: #275b72;
  1134. color: #788f97;
  1135. }
  1136. .tes-nightmode #room-header-gifts-buttons > #give-gift:hover {
  1137. background-color: #1a80a2;
  1138. color: #a3b5d2;
  1139. }
  1140. </style>
  1141. `;
  1142. titleCSS.insertAdjacentHTML(insertPosition, titleCSShtml);
  1143. }
  1144.  
  1145. { // videolistCSS
  1146. videolistCSShtml = `
  1147. <style id="videolistCSS" scope="tinychat-videolist">` + globalCSS + `
  1148. #videos-header {
  1149. height: 10px;
  1150. min-height: 10px;
  1151. background: none!important;
  1152. z-index: 5;
  1153. }
  1154. #videolist.tes-sidemenuCollapsed { width: 93%; }
  1155. #Fvideolist * {
  1156. width: 75%!important;
  1157. display: contents;
  1158. float: right;
  1159. flex-direction: column;
  1160. }
  1161. #Fvideos {
  1162. flex-direction: unset;
  1163. flex-wrap: unset;
  1164. }
  1165. #videos-header > span {
  1166. line-height: initial;
  1167. position: relative;
  1168. top: 1px;
  1169. background: none;
  1170. }
  1171. #videos-header > span > svg {
  1172. height: 16px;
  1173. padding: 0;
  1174. }
  1175. .js-video { transition: all .4s ease-in-out; }
  1176. .tes-max-noAnim .js-video { transition: unset; }
  1177. .tes-max.videos-items:last-child { edisplay: block; }
  1178.  
  1179. #videolist.tes-nightmode { background: var(--nightmode-bgcolor); }
  1180. #videolist.tes-nightmode.blacknight { background: var(--nightmodeBlack-bgcolor); }
  1181. .tes-nightmode #videos-footer-youtube { background-color: #723e3c; }
  1182. .tes-nightmode.blacknight #videos-footer-youtube { background-color: #4e1f1d; }
  1183. .tes-nightmode #videos-footer-youtube:hover { background-color: #a83c38; }
  1184. .tes-nightmode.blacknight #videos-footer-youtube:hover { background-color: #742825; }
  1185.  
  1186. .tes-nightmode #videos-footer-broadcast,
  1187. .tes-nightmode #videos-footer-broadcast-wrapper > #videos-footer-submenu-button {
  1188. background-color: #31684c;
  1189. color: #519472;
  1190. }
  1191. .tes-nightmode.blacknight #videos-footer-broadcast,
  1192. .tes-nightmode.blacknight #videos-footer-broadcast-wrapper > #videos-footer-submenu-button {
  1193. background-color: #12261c;
  1194. color: #2d5240;
  1195. }
  1196. .tes-nightmode #videos-footer-broadcast:hover,
  1197. .tes-nightmode #videos-footer-broadcast-wrapper > #videos-footer-submenu-button:hover {
  1198. background-color: #338e5f;
  1199. color: #82d9ad;
  1200. }
  1201. .tes-nightmode.blacknight #videos-footer-broadcast:hover,
  1202. .tes-nightmode.blacknight #videos-footer-broadcast-wrapper > #videos-footer-submenu-button:hover {
  1203. background-color: #17402b;
  1204. color: #41956b;
  1205. }
  1206. .tes-nightmode #videos-footer-broadcast-wrapper > #videos-footer-submenu-button:before { border-color: #519472 transparent; }
  1207. .tes-nightmode.blacknight #videos-footer-broadcast-wrapper > #videos-footer-submenu-button:before { border-color: #41956b transparent; }
  1208. .tes-nightmode #videos-footer-broadcast-wrapper > #videos-footer-submenu-button:hover:before { border-color: #82d9ad transparent; }
  1209.  
  1210. .tes-nightmode #videos-footer-push-to-talk { background-color: #31684c; }
  1211. .tes-nightmode #videos-footer-push-to-talk path { fill: #82d9ad; }
  1212. .tes-nightmode #videos-footer-push-to-talk:hover { background-color: #338e5f; }
  1213.  
  1214. #videos-footer-broadcast-wrapper.active-ptt > #videos-footer-push-to-talk { background-color: #404f54; }
  1215. #videos-footer-broadcast-wrapper.active-ptt > #videos-footer-push-to-talk path { fill: #74817a; }
  1216.  
  1217. .tes-nightmode #videos-footer-broadcast-wrapper.active > #videos-footer-broadcast,
  1218. .tes-nightmode #videos-footer-broadcast-wrapper.active > #videos-footer-submenu-button {
  1219. background-color: #404f54;
  1220. color: #74817a;
  1221. }
  1222. .tes-nightmode.blacknight #videos-footer-broadcast-wrapper.active > #videos-footer-broadcast,
  1223. .tes-nightmode.blacknight #videos-footer-broadcast-wrapper.active > #videos-footer-submenu-button {
  1224. background-color: #222;
  1225. color: #555;
  1226. }
  1227. .tes-nightmode #videos-footer-broadcast-wrapper.active > #videos-footer-submenu-button:before { border-color: #74817a transparent; }
  1228. .tes-nightmode #videos-header path { fill: var(--nightmode-headerButtonscolor); }
  1229. .tes-nightmode #videos-header path[fill="none"] { stroke: var(--nightmode-headerButtonscolor); fill: none; }
  1230. .tes-nightmode .videos-header-volume { border-color: #3a474b; }
  1231. .tes-nightmode.blacknight .videos-header-volume { border-color: #222; }
  1232. .tes-nightmode #videos-footer-youtube path { fill: #996d6c; }
  1233. .tes-nightmode.blacknight #videos-footer-youtube path { fill: #634645; }
  1234. </style>
  1235. `;
  1236. videolistCSS.insertAdjacentHTML(insertPosition, videolistCSShtml);
  1237. }
  1238.  
  1239. { // chatlistCSS
  1240. chatlistCSShtml = `
  1241. <style id="chatlistCSS" scope="tinychat-chatlist">` + globalCSS + `
  1242. #chatlist.tes-mod { margin-top: 22px; }
  1243. #chatlist > div > span {
  1244. padding-left: 1px;
  1245. }
  1246. #chatlist > #header {
  1247. top: 3px;
  1248. height: auto;
  1249. }
  1250.  
  1251. /*** --- this block is in chatlistCSS & userlistCSS --- ***/
  1252. .list-item > span > img {
  1253. right: 13px;
  1254. left: auto;
  1255. }
  1256. .list-item > span[data-status]:before {
  1257. left: auto;
  1258. right: 0;
  1259. }
  1260. .list-item > span > span {
  1261. background: none!important;
  1262. box-shadow: none!important;
  1263. }
  1264. /*** --- --- ***/
  1265.  
  1266. .close-instant > path {
  1267. fill: white;
  1268. }
  1269. .list-item > span > span { /* gift and close buttons */
  1270. right: 16px;
  1271. }
  1272. .list-item > span:hover > span { /* gift and close buttons */
  1273. right: 16px;
  1274. background: var(--nightmode-bgcolor);
  1275. }
  1276.  
  1277. /*** --- this block is in chatlistCSS & userlistCSS --- ***/
  1278. .tes-nightmode.blacknight .list-item > span,
  1279. .tes-nightmode.blacknight .list-item > span> span {
  1280. background: var(--nightmodeBlack-bgcolor);
  1281. }
  1282. .tes-nightmode.blacknight .list-item > span > span { box-shadow: 0 0 3px 3px var(--nightmodeBlack-bgcolor); }
  1283. .tes-nightmode.blacknight .list-item > span:hover,
  1284. .tes-nightmode.blacknight .list-item > span:hover > span,
  1285. .tes-nightmode.blacknight .list-item + .list-item > span:hover,
  1286. #chatlist.tes-nightmode.blacknight > #header ~ .list-item > span.active {
  1287. background: #222;
  1288. }
  1289. /*** --- --- ***/
  1290.  
  1291. </style>
  1292. `;
  1293. chatlistCSS.insertAdjacentHTML(insertPosition, chatlistCSShtml);
  1294. }
  1295.  
  1296. { // userlistCSS
  1297. userlistCSShtml = `
  1298. <style id="userlistCSS" scope="tinychat-userlist">` + globalCSS + `
  1299. #userlist > div > span {
  1300. padding-left: 1px;
  1301. }
  1302. .list-item > span > span {
  1303. right: auto;
  1304. padding: 0 5px;
  1305. }
  1306. .list-item > span > .nickname {
  1307. padding-right: 3px;
  1308. transition: .5s;
  1309. }
  1310. .nickname.tes-myNick { color: #b3b3b3; }
  1311.  
  1312. /*** --- this block is in chatlistCSS & userlistCSS --- ***/
  1313. .list-item > span > img {
  1314. right: 13px;
  1315. left: auto;
  1316. }
  1317. .list-item > span[data-status]:before {
  1318. left: auto;
  1319. right: 0;
  1320. }
  1321. .list-item > span > span {
  1322. background: none;
  1323. box-shadow: none;
  1324. }
  1325. /*** --- --- ***/
  1326.  
  1327. .list-item > span > span[data-moderator="1"]:before {
  1328. filter: hue-rotate(226deg) saturate(4000%);
  1329. }
  1330. #userlist > #header {
  1331. top: auto;
  1332. height: auto;
  1333. overflow: unset;
  1334. }
  1335. #header > span {
  1336. width: unset!important;
  1337. overflow: unset!important;
  1338. }
  1339. #button-banlist {
  1340. right: -34px;
  1341. position: fixed;
  1342. top: 74px;
  1343. left: 1px;
  1344. width: 147px;
  1345. transition: 1s;
  1346. z-index: 8;
  1347. }
  1348. @media screen and (max-width: 1000px) {
  1349. #button-banlist {
  1350. top: -80px;
  1351. left: 5px;
  1352. width: 115px;
  1353. position: absolute;
  1354. }
  1355. }
  1356. .tes-sidemenuCollapsed #button-banlist {
  1357. left: -100px;
  1358. width: 10px;
  1359. opacity: 0;
  1360. }
  1361. #contextmenu { z-index: 6; }
  1362. #userlist .yourname, span[data-user-id="840113"] {
  1363. color: white!important;
  1364. }
  1365.  
  1366. /*** --- this block is in chatlistCSS & userlistCSS --- ***/
  1367. .tes-nightmode.blacknight .list-item > span,
  1368. .tes-nightmode.blacknight .list-item > span> span {
  1369. background: var(--nightmodeBlack-bgcolor);
  1370. }
  1371. .tes-nightmode.blacknight .list-item > span > span { box-shadow: 0 0 3px 3px var(--nightmodeBlack-bgcolor); }
  1372. .tes-nightmode.blacknight .list-item > span:hover,
  1373. .tes-nightmode.blacknight .list-item > span:hover > span,
  1374. .tes-nightmode.blacknight .list-item + .list-item > span:hover,
  1375. #chatlist.tes-nightmode.blacknight > #header ~ .list-item > span.active {
  1376. background: #222;
  1377. }
  1378. /*** --- --- ***/
  1379. .tes-nightmode.blacknight .list-item > span:hover > span { box-shadow: 0 0 3px 3px #222; }
  1380. .tes-nightmode.blacknight #button-banlist { background: #222; }
  1381. .tes-nightmode.blacknight #button-banlist:hover { background: #00708f; }
  1382. </style>
  1383. `;
  1384. userlistCSS.insertAdjacentHTML(insertPosition, userlistCSShtml);
  1385. }
  1386.  
  1387. { // userContextmenuCSS
  1388. userContextmenuCSShtml = `
  1389. <style id="userContextmenuCSS" scope="tinychat-user-contextmenu">` + globalCSS + `
  1390. #main {
  1391. border: 1px solid rgba(0, 0, 0, .1);
  1392. }
  1393. </style>
  1394. `;
  1395. userContextmenuCSS.insertAdjacentHTML(insertPosition, userContextmenuCSShtml);
  1396. }
  1397.  
  1398. { // bodyCSS
  1399. bodyCSShtml = `
  1400. <style id="bodyCSS">` + globalCSS + `
  1401. #nav-static-wrapper {
  1402. width: 2px;
  1403. opacity: .7;
  1404. }
  1405. @media screen and (max-width: 1000px) {
  1406. #nav-static-wrapper {
  1407. width: 82px;
  1408. opacity: 1;
  1409. }
  1410. }
  1411. #content {
  1412. padding: 0;
  1413. }
  1414. #menu-icon { transition: 1s; }
  1415. .tes-sidemenuCollapsed #menu-icon {
  1416. z-index: -1;
  1417. opacity: 0;
  1418. }
  1419. body.tes-changefont {
  1420. font-family: sans-serif;
  1421. }
  1422. #header-user {
  1423. left: 62px;
  1424. transition: 1s;
  1425. }
  1426. .tes-sidemenuCollapsed #header-user { display: none; }
  1427. @media screen and (max-width: 1000px) {
  1428. #header-user {
  1429. left: 21px;
  1430. }
  1431. }
  1432. @media screen and (max-width: 600px) {
  1433. #header-user {
  1434. left: auto;
  1435. right: 54px;
  1436. }
  1437. }
  1438. @media screen and (min-width: 1000px) {
  1439. #menu-icon:hover { opacity: 1; }
  1440. #menu-icon {
  1441. top: 4px;
  1442. left: 19px;
  1443. height: 12px;
  1444. width: 109px;
  1445. font-size: 10px;
  1446. background: #04caff;
  1447. border-radius: 6px;
  1448. opacity: .8;
  1449. }
  1450. #menu-icon:after {
  1451. position: absolute;
  1452. top: 3px;
  1453. left: 51px;
  1454. content: "";
  1455. height: 7px;
  1456. width: 7px;
  1457. border-width: 2px 2px 0px 0px;
  1458. border-style: solid;
  1459. border-color: #fff;
  1460. box-sizing: border-box;
  1461. transform: rotate(45deg);
  1462. transition: .2s;
  1463. }
  1464. #menu-icon:hover:after {
  1465. left: 55px;
  1466. }
  1467. #menu-icon.expanded:after {
  1468. border-width: 0px 0px 2px 2px;
  1469. }
  1470. #menu-icon.expanded:hover:after {
  1471. left: 40px;
  1472. }
  1473. #menu-icon > svg {
  1474. opacity: 0;
  1475. }
  1476. }
  1477.  
  1478. body.tes-nightmode {
  1479. color: var(--nightmode-textcolor);
  1480. background: var(--nightmode-bgcolor);
  1481. }
  1482. body.tes-nightmode.blacknight {
  1483. color: gray;
  1484. background: var(--nightmodeBlack-bgcolor);
  1485. }
  1486. .tes-nightmode.blacknight #nav-static-wrapper { background: var(--nightmodeBlack-bgcolor); }
  1487. </style>
  1488. `;
  1489. bodyCSS.insertAdjacentHTML(insertPosition, bodyCSShtml);
  1490. }
  1491.  
  1492. messageCSS = `
  1493. .tes-nightmode { color: var(--nightmode-textcolor);}
  1494. .tes-nightmode.blacknight { color: gray;}
  1495.  
  1496. .tes-mention-message { color: red; }
  1497.  
  1498. .tes-nightmode.tes-mention-message { color: #e44a3f; }
  1499. .tes-nightmode.message.system,
  1500. .tes-nightmode #chat-content > .message.system {
  1501. background-color: #313c3f;
  1502. color: #677174;
  1503. }
  1504. .tes-nightmode.blacknight.message.system,
  1505. .tes-nightmode.blacknight #chat-content > .message.system {
  1506. background-color: #090909;
  1507. color: #4d4d4d;
  1508. }
  1509. `;
  1510.  
  1511. { // chatlogCSS
  1512. chatlogCSShtml = `
  1513. <style id="chatlogCSS" scope="tinychat-chatlog">` + globalCSS + `
  1514. #chat-content > .message {
  1515. padding-bottom: 0;
  1516. padding-top: 0!important;
  1517. margin-bottom: 0;
  1518. min-height: 0px!important;
  1519. }
  1520. /*
  1521. #chat-content > .message:hover {
  1522. background: rgba(0, 0, 0, 0.03);
  1523. }
  1524. */
  1525. #chat-content > .message.common {
  1526. margin-bottom: 5px;
  1527. }
  1528. #chat-content > .message.system {
  1529. padding: 0;
  1530. }
  1531. #chat-content.tes-notif-off > .message.system {
  1532. display: none;
  1533. }
  1534. #chat-content.tes-notif-off > .message.system.dontHide {
  1535. display: initial;
  1536. }
  1537. #chat-instant > a:first-child,
  1538. #chat-content > .message > a:first-child {
  1539. top: auto;
  1540. }
  1541. #chat-position #input:before {
  1542. background: none;
  1543. }
  1544. #chat-instant > a > .avatar,
  1545. #chat-content > .message > a > .avatar {
  1546. border-radius: unset;
  1547. }
  1548. #timestamp {
  1549. font-size: 11px;
  1550. color: silver;
  1551. /* float: right; */
  1552. position: absolute;
  1553. right: 0;
  1554. padding-top: 3px;
  1555. }
  1556. #chat-content > .message > .nickname {
  1557. overflow: initial;
  1558. line-height: initial;
  1559. }
  1560. #chat-content div.message.common:last-of-type {
  1561. margin-bottom: 10px;
  1562. }
  1563. #chat-instant-button.tes-loading {
  1564. border: 0;
  1565. font-size: x-large;
  1566. animation: spin .5s linear infinite;
  1567. }
  1568. @keyframes spin {
  1569. 0% { transform: rotate(0deg); }
  1570. 100% { transform: rotate(360deg); }
  1571. }
  1572. #tes-chatlogDisplay {
  1573. display: none;
  1574. position: fixed;
  1575. top: 50px;
  1576. left: 50px;
  1577. width: 90%;
  1578. height: 80%;
  1579. z-index: 7;
  1580. cursor: default;
  1581. }
  1582. #tes-chatlogDisplay.show { display: unset; }
  1583. #tes-chatlogDisplay * {
  1584. float: left;
  1585. height: 100%;
  1586. }
  1587. #tes-chatlogDisplay textarea {
  1588. background: rgba(255, 255, 255, .8);
  1589. transition: .2s;
  1590. opacity: 0;
  1591. border-radius: 6px;
  1592. width: 90%;
  1593. }
  1594. #tes-chatlogDisplay textarea.show {
  1595. opacity: 1;
  1596. }
  1597. #tes-chatlogDisplay #close {
  1598. opacity: 0;
  1599. transition: .2s;
  1600. width: 40px;
  1601. background: #41b7ef;
  1602. height: 40px;
  1603. border-top-right-radius: 10px;
  1604. border-bottom-right-radius: 10px;
  1605. position: relative;
  1606. color: white;
  1607. top: 40%;
  1608. vertical-align: middle;
  1609. font-size: 22px;
  1610. text-align: center;
  1611. padding-top: 8px;
  1612. cursor: pointer;
  1613. }
  1614. #tes-chatlogDisplay #close:hover {
  1615. background: #72caf3;
  1616. }
  1617. #tes-chatlogDisplay #close.show {
  1618. opacity: 1;
  1619. }
  1620. #tes-chatlogButtons {
  1621. position: absolute;
  1622. top: 2px;
  1623. left: 6px;
  1624. font: 15px monospace;
  1625. z-index: 11;
  1626. }
  1627. .tes-chatlogBut {
  1628. padding: 2px;
  1629. border-radius: 4px;
  1630. border: silver 1px solid;
  1631. color: silver;
  1632. transition: .3s;
  1633. width: 10px;
  1634. height: 10px;
  1635. overflow: hidden;
  1636. cursor: pointer;
  1637. opacity: 1;
  1638. float: left;
  1639. }
  1640. .tes-chatlogBut:hover {
  1641. width: 1.5em;
  1642. color: var(--textcolor);
  1643. border-color: var(--textcolor);
  1644. }
  1645. .tes-chatlogBut ~ .tes-chatlogBut { margin-left: 2px; }
  1646. .tes-chatlogBut .icon { width: auto; }
  1647. .tes-chatlogBut .label {
  1648. width: 0;
  1649. opacity: 0;
  1650. overflow: hidden;
  1651. transition: .3s;
  1652. display: block;
  1653. position: relative;
  1654. top: -2px;
  1655. left: 13px;
  1656. font: 11px sans-serif;
  1657. color: var(--textcolor);
  1658. }
  1659. .tes-chatlogBut:hover .label {
  1660. opacity: 1;
  1661. width: auto;
  1662. }
  1663. .tes-chatboxPM #tes-chatlogSave {
  1664. opacity: 0;
  1665. z-index: -5;
  1666. }
  1667. #tes-chatlogSave .icon {
  1668. /* transform: scaleY(.6); */
  1669. position: absolute;
  1670. top: -1px;
  1671. left: 4px;
  1672. }
  1673. #tes-chatlogSave .icon svg {
  1674. width: 19px;
  1675. height: 19px;
  1676. position: relative;
  1677. left: -3px;
  1678. }
  1679. #tes-chatlogSave .icon path {
  1680. transform: scale(.08) scaleX(1.2) rotate(180deg);
  1681. 10%: 10px
  1682. height:;
  1683. fill: #ccc;
  1684. transform-origin: 11px 12px;
  1685. }
  1686. #tes-chatlogSave:hover .icon path { fill: var(--textcolor); }
  1687. #tes-chatlogSave:hover { width: 4.2em; }
  1688. #tes-chatlogSave:hover .label { width: 4.3em; }
  1689. #tes-chatlogView .icon {
  1690. font-size: 10px;
  1691. top: 1px;
  1692. position: absolute;
  1693. }
  1694. #tes-chatlogView:hover { width: 2.5em; }
  1695.  
  1696. .tes-nightmode #tes-chatlogSave .icon path { fill: var(--nightmode-textSecondarycolor); }
  1697. .tes-nightmode.blacknight #tes-chatlogSave .icon path { fill: #444; }
  1698. .tes-nightmode #tes-chatlogSave:hover .icon path { fill: var(--nightmode-textcolor); }
  1699. .tes-nightmode.blacknight #tes-chatlogSave:hover .icon path { fill: gray; }
  1700. .tes-nightmode .tes-chatlogBut {
  1701. color: var(--nightmode-textSecondarycolor);
  1702. border-color: var(--nightmode-textSecondarycolor);
  1703. }
  1704. .tes-nightmode.blacknight .tes-chatlogBut {
  1705. color: #444;
  1706. border-color: #444;
  1707. }
  1708. .tes-nightmode .tes-chatlogBut:hover {
  1709. color: var(--nightmode-textcolor);
  1710. border-color: var(--nightmode-textcolor);
  1711. }
  1712. .tes-nightmode.blacknight .tes-chatlogBut:hover {
  1713. color: #777;
  1714. border-color: #777;
  1715. }
  1716. .tes-nightmode #tes-chatlogDisplay textarea {
  1717. background: rgba(45, 55, 58, .8);
  1718. color: var(--nightmode-textcolor);
  1719. border: 1px solid #506368;
  1720. caret-color: #41b7ef;
  1721. }
  1722. .tes-nightmode.blacknight #tes-chatlogDisplay textarea {
  1723. background: rgba(0, 0, 0, .8);
  1724. color: gray;
  1725. border: 1px solid #444;
  1726. }
  1727. .tes-nightmode .tes-chatlogBut .label { color: var(--nightmode-textcolor); }
  1728. .tes-nightmode.blacknight .tes-chatlogBut .label { color: gray; }
  1729. .tes-nightmode #chat-content > .message > .nickname[data-status=""],
  1730. .tes-nightmode #chat-instant > .nickname[data-status=""] {
  1731. color: var(--nightmode-textcolor);
  1732. }
  1733. .tes-nightmode.blacknight #chat-content > .message > .nickname[data-status=""],
  1734. .tes-nightmode.blacknight #chat-instant > .nickname[data-status=""] {
  1735. color: gray;
  1736. }
  1737.  
  1738. #chat-wrapper.tes-nightmode,
  1739. .tes-nightmode .on-white-scroll::-webkit-scrollbar-track,
  1740. .tes-nightmode #textarea,
  1741. .tes-nightmode #chat-instant {
  1742. background: var(--nightmode-bgcolor);
  1743. color: var(--nightmode-textcolor);
  1744. }
  1745. #chat-wrapper.tes-nightmode.blacknight,
  1746. .tes-nightmode.blacknight .on-white-scroll::-webkit-scrollbar-track,
  1747. .tes-nightmode.blacknight #textarea,
  1748. .tes-nightmode.blacknight #chat-instant {
  1749. background: var(--nightmodeBlack-bgcolor);
  1750. color: gray;
  1751. }
  1752.  
  1753. .tes-nightmode .on-white-scroll::-webkit-scrollbar-thumb {
  1754. border-color: var(--nightmode-bgcolor);
  1755. }
  1756. .tes-nightmode.blacknight .on-white-scroll::-webkit-scrollbar-thumb {
  1757. border-color: var(--nightmodeBlack-bgcolor);
  1758. }
  1759.  
  1760. #chat-wrapper.tes-nightmode { border-color: var(--nightmode-trimcolor); }
  1761. #chat-wrapper.tes-nightmode.blacknight { border-color: #222; }
  1762. .tes-nightmode #timestamp { color: var(--nightmode-textSecondarycolor); }
  1763. .tes-nightmode.blacknight #timestamp { color: #545454; }
  1764. #chat-wider.tes-nightmode { background-color: var(--nightmode-trimcolor); }
  1765. #chat-wider.tes-nightmode.blacknight { background-color: #141414; }
  1766. #chat-wider.tes-nightmode:before { border-color: transparent #636e6e; }
  1767. #chat-wider.tes-nightmode.blacknight:before { border-color: transparent #444; }
  1768. .tes-nightmode #input:after { border-color: var(--nightmode-trimcolor); }
  1769. .tes-nightmode.blacknight #input:after { border-color: #222; }
  1770. .tes-nightmode #chat-content > .message.system { background-color: #313c3f; }
  1771. .tes-nightmode.blacknight #chat-content > .message.system { background-color: #090909; }
  1772. .tes-nightmode.blacknight .on-white-scroll::-webkit-scrollbar-thumb { background-color: #111; }
  1773. </style>
  1774. `;
  1775. chatlogCSS.insertAdjacentHTML(insertPosition, chatlogCSShtml);
  1776. }
  1777.  
  1778. { // sidemenuCSS
  1779. var firefoxCSS = "";
  1780. if (browserSpoofedChrome) {
  1781. firefoxCSS = `
  1782. #sidemenu {
  1783. left: 0!important;
  1784. }
  1785. `;
  1786. }
  1787. sidemenuCSShtml = `
  1788. <style id="sidemenuCSS" scope="tinychat-sidemenu">` + globalCSS + `
  1789. #sidemenu {
  1790. min-width: 162px;
  1791. max-width: 10%;
  1792. left: auto;
  1793. transition: 1s;
  1794. }
  1795. @media screen and (max-width: 1000px) {
  1796. #sidemenu {
  1797. left: -188px;
  1798. }
  1799. }
  1800. #sidemenu-content {
  1801. padding-left: 2px;
  1802. }
  1803. #live-directory-wrapper {
  1804. padding: 0;
  1805. }
  1806. #top-buttons-wrapper {
  1807. padding: 0;
  1808. }
  1809. #user-info { transition: 1s; }
  1810. .logged-in #user-info {
  1811. padding: 0;
  1812. height: auto;
  1813. text-align: center;
  1814. }
  1815. #user-info > div { overflow: unset; }
  1816. #user-info > div:before {
  1817. position: relative;
  1818. top: 0;
  1819. }
  1820. #user-info button { opacity: .8; }
  1821. #user-info:hover button { opacity: 1; }
  1822. #user-info > a { display: none; }
  1823. #user-info:hover > a { display: initial; }
  1824. @media screen and (min-width: 1000px) {
  1825. #live-directory, #upgrade {
  1826. height: 23px;
  1827. line-height: 22px;
  1828. font-size: 13px;
  1829. opacity: .8;
  1830. }
  1831. #live-directory:before {
  1832. height: 8px;
  1833. width: 8px;
  1834. top: 0px;
  1835. }
  1836. #upgrade {
  1837. margin-top: 4px;
  1838. }
  1839. #live-directory:hover, #upgrade:hover {
  1840. opacity: 1;
  1841. }
  1842. }
  1843. #sidemenu.tes-sidemenuCollapsed {
  1844. min-width: 10px;
  1845. max-width: 10px;
  1846. }
  1847. .tes-sidemenuCollapsed #user-info { display: none; }
  1848. #tes-sidemenu-grabber {
  1849. position: absolute;
  1850. top: 50%;
  1851. right: 0;
  1852. background: var(--nightmode-trimcolor);
  1853. color: #536165;
  1854. z-index: 3;
  1855. border-radius: 10px 0 0 10px;
  1856. height: 37px;
  1857. padding-top: 24px;
  1858. width: 21px;
  1859. text-align: center;
  1860. font-size: 11px;
  1861. transition: .4s;
  1862.  
  1863. /*
  1864. background: white;
  1865. border: #dddddd 1px solid;
  1866. border-right: 0;
  1867. */
  1868. }
  1869. #tes-sidemenu-grabber:hover {
  1870. background: #506368;
  1871. color: #788c91;
  1872. cursor: pointer;
  1873. }
  1874. .tes-sidemenuCollapsed #tes-sidemenu-grabber {
  1875. border-radius: 0 10px 10px 0;
  1876. right: -7px;
  1877. text-align: right;
  1878. padding-right: 3px;
  1879. }
  1880. .tes-sidemenuCollapsed #tes-sidemenu-grabber:hover {
  1881. right: -18px;
  1882. padding-right: 9px;
  1883. width: 18px;
  1884. }
  1885. ` + firefoxCSS +
  1886. `
  1887. #sidemenu.tes-nightmode.blacknight,
  1888. .tes-nightmode.blacknight #sidemenu-content::-webkit-scrollbar-track {
  1889. background: var(--nightmodeBlack-bgcolor);
  1890. }
  1891. .tes-nightmode.blacknight #tes-sidemenu-grabber {
  1892. background: #141414;
  1893. color: #3b3b3b;
  1894. }
  1895. .tes-nightmode.blacknight #tes-sidemenu-grabber:hover {
  1896. background: #333;
  1897. color: #5c5c5c;
  1898. }
  1899. .tes-nightmode.blacknight #user-info { background: var(--nightmodeBlack-bgcolor); }
  1900. .tes-nightmode.blacknight #user-info > button {
  1901. background: #035268;
  1902. color: #aaa;
  1903. }
  1904. .tes-nightmode.blacknight #user-info > button:hover {
  1905. background: #0080a3;
  1906. color: white;
  1907. }
  1908. .tes-nightmode.blacknight #sidemenu-content::-webkit-scrollbar-thumb {
  1909. border: 5px solid var(--nightmodeBlack-bgcolor);
  1910. background-color: #111;
  1911. }
  1912. </style>
  1913. `;
  1914. sidemenuCSS.insertAdjacentHTML(insertPosition, sidemenuCSShtml);
  1915. }
  1916.  
  1917. { // videomoderationCSS
  1918. videomoderationCSShtml = `
  1919. <style id="videomoderationCSS" scope="tc-video-moderation">` + globalCSS + `
  1920. #moderatorlist {
  1921. padding-left: 0;
  1922. z-index: 7;
  1923. }
  1924. #moderatorlist:hover {
  1925. position: absolute;
  1926. background: white;
  1927. z-index: 1000;
  1928. width: 300px;
  1929. min-height: 155px;
  1930. flex-direction: column;
  1931. position: absolute;
  1932. background: rgba(45, 55, 58, 0.8);
  1933. z-index: 1000;
  1934. width: 350px;
  1935. max-height: fit-content!important;
  1936. left: 15px;
  1937. border-radius: 13px;
  1938. border: #47575c 1px solid;
  1939. }
  1940. #moderatorlist:after {
  1941. top: 47px;
  1942. }
  1943.  
  1944. #moderatorlist.tes-nightmode.blacknight > #header > span > button { background: var(--nightmodeBlack-bgcolor); }
  1945. #moderatorlist.tes-nightmode.blacknight:hover {
  1946. background: var(--nightmodeBlack-bgcolor);
  1947. border-color: #333;
  1948. }
  1949. </style>
  1950. `;
  1951. videomoderationCSS.insertAdjacentHTML(insertPosition, videomoderationCSShtml);
  1952. }
  1953.  
  1954. { // webappCSS
  1955. webappCSShtml = `
  1956. <style id="webappCSS" scope="tinychat-webrtc-app">` + globalCSS + `
  1957. #room {
  1958. padding: 0;
  1959. padding-left: 142px;
  1960. }
  1961. #room.tes-sidemenuCollapsed { padding-left: 0; }
  1962. @media screen and (max-width: 1000px) {
  1963. :host > #room {
  1964. padding-left: 82px;
  1965. }
  1966. }
  1967. @media screen and (max-width: 600px) {
  1968. :host > #room {
  1969. padding-left: 0;
  1970. }
  1971. }
  1972. /* legind - why doesnt this work properly? */
  1973. #room-content {
  1974. flex-direction: column !important;
  1975. margin-left: 15px !important;
  1976. }
  1977. .tes-nightmode tinychat-videolist { background: var(--nightmode-bgcolor); }
  1978. .tes-nightmode.blacknight tinychat-videolist { background: var(--nightmodeBlack-bgcolor); }
  1979. </style>
  1980. `;
  1981. webappCSS.insertAdjacentHTML(insertPosition, webappCSShtml);
  1982. }
  1983. }catch(e){tcl("error injectCSS: " + e.message);}
  1984. }
  1985.  
  1986. function injectElements() {
  1987. try{
  1988. headerGrabberParElem = titleElem.querySelector("#room-header");
  1989. headerGrabberParElem.insertAdjacentHTML("beforeend", `<div id="tes-header-grabber">▲</div>`);
  1990. headerGrabberElem = headerGrabberParElem.querySelector("#tes-header-grabber");
  1991. headerGrabberElem.addEventListener("click", headerGrabber);
  1992.  
  1993. sidemenuOverlayElem = bodyElem.querySelector("#menu-icon");
  1994. sidemenuOverlayElem.addEventListener("click", function(){sidemenuOverlayElem.classList.toggle("expanded");});
  1995.  
  1996. chatlogButtonsHTML = `
  1997. <div id="tes-chatlogButtons">
  1998. <div id="tes-chatlogSave" class="tes-chatlogBut">
  1999. <span class="icon">
  2000. <svg xmlns="http://www.w3.org/2000/svg" xmlns:svg="http://www.w3.org/2000/svg">
  2001. <path d="m0,50l50,-50l50,50l-25,0l0,50l-50,0l0,-50l-25,0z"></path>
  2002. </svg>
  2003. </span><!-- ⇩ -->
  2004. <span class="label">download</span>
  2005. </div>
  2006. <div id="tes-chatlogView" class="tes-chatlogBut">
  2007. <span class="icon">☰</span>
  2008. <span class="label">view</span>
  2009. </div>
  2010. <div id="tes-chatlogDisplay">
  2011. <textarea spellcheck="false"></textarea>
  2012. <div id="close">✕</div>
  2013. </div>
  2014. </div>`;
  2015.  
  2016. selectAllButton = chatlogElem.querySelector("#chat-wrapper").insertAdjacentHTML("afterbegin", chatlogButtonsHTML);
  2017. chatlogElem.querySelector("#tes-chatlogSave").addEventListener("click", function(){copyChatlog("download")} );
  2018. chatlogElem.querySelector("#tes-chatlogView").addEventListener("click", function(){copyChatlog("view")} );
  2019. chatlogElem.querySelector("#tes-chatlogDisplay #close").addEventListener("click", function(){copyChatlog("close")} );
  2020.  
  2021. if (!isPaidAccount) {
  2022. sidemenuGrabberParElem = sidemenuElem.querySelector("#sidemenu");
  2023. sidemenuGrabberElem = document.createElement("div");
  2024. sidemenuGrabberElem.setAttribute("id", "tes-sidemenu-grabber");
  2025. sidemenuGrabberElem.innerHTML = "◀";
  2026. sidemenuGrabberElem.addEventListener("click", sidemenuGrabber);
  2027. sidemenuGrabberParElem.appendChild(sidemenuGrabberElem);
  2028. sidemenuGrabberElem = sidemenuElem.querySelector("#tes-sidemenu-grabber");
  2029. }
  2030. }catch(e){tcl("error injectElements: " + e.message);}
  2031. }
  2032.  
  2033. function sidemenuGrabber() {
  2034. try{
  2035. sidemenuGrabberParElem.classList.toggle("tes-sidemenuCollapsed");
  2036. sidemenuGrabberParElem.classList.contains("tes-sidemenuCollapsed") ? sidemenuGrabberElem.innerHTML = "▶" : sidemenuGrabberElem.innerHTML = "◀";
  2037.  
  2038. userlistElem.querySelector("#userlist").classList.toggle("tes-sidemenuCollapsed");
  2039. videolistElem.querySelector("#videolist").classList.toggle("tes-sidemenuCollapsed");
  2040. webappElem.querySelector("#room").classList.toggle("tes-sidemenuCollapsed");
  2041. bodyElem.classList.toggle("tes-sidemenuCollapsed");
  2042. }catch(e){tcl("error sidemenuGrabber: " + e.message);}
  2043. }
  2044.  
  2045. function headerGrabber() {
  2046. try{
  2047. headerGrabberParElem.classList.toggle("tes-headerCollapsed");
  2048. headerGrabberParElem.classList.contains("tes-headerCollapsed") ? headerGrabberElem.innerHTML = "▼" : headerGrabberElem.innerHTML = "▲";
  2049. }catch(e){tcl("error headerGrabber: " + e.message);}
  2050. }
  2051.  
  2052. function updateScroll() {
  2053. scrollbox.scrollTop = scrollbox.scrollHeight;
  2054. scrollbox.scrollTop = scrollbox.scrollTop + 5;
  2055. }
  2056.  
  2057. function userHasScrolled(e) {
  2058. var scrollwheelAmount = e.deltaY;
  2059.  
  2060. if (scrollwheelAmount < 0) {
  2061. autoScrollStatus = false;
  2062. }
  2063. if (autoScrollStatus === false && scrollbox.scrollHeight - scrollbox.scrollTop == scrollbox.offsetHeight) {
  2064. autoScrollStatus = true;
  2065. }
  2066. }
  2067.  
  2068. function newMessageAdded() {
  2069. try{
  2070. if (autoScrollStatus === true && settingsQuick["Autoscroll"]) { updateScroll(); }
  2071. timestampAdd();
  2072. messageParser();
  2073. }catch(e){tcl("error newMessageAdded: " + e.message);}
  2074. }
  2075.  
  2076. function userContextmenuUpdated() {
  2077. try{
  2078. var elemBottom = 0;
  2079. var topPos = userContextmenuCSS.getBoundingClientRect().top;
  2080. var elemBottom = topPos + userContextmenuCSS.offsetHeight;
  2081. if (elemBottom > (window.innerHeight - 82)) {
  2082. // userContextmenuCSS.style.top = (userContextmenuCSS.style.top - userlistElem.querySelector("#userlist").scrollTop - 200) + "px";
  2083. // userContextmenuCSS.style.top = (userlistElem.querySelector("#userlist").scrollTop - window.innerHeight) + "px";
  2084. userContextmenuCSS.style.top = (window.innerHeight - 82 - userContextmenuCSS.offsetHeight - 15) + "px";
  2085. // tcl("Change: " + userContextmenuCSS.style.top);
  2086. }
  2087.  
  2088. // tcl("elemBottom: " + elemBottom + ". Max: " + (window.innerHeight - 82) + ". offsetHeight: " + userContextmenuCSS.offsetHeight + ". New top: " + (window.innerHeight - 82 - userContextmenuCSS.offsetHeight));
  2089. }catch(e){tcl("error userContextmenuUpdated: " + e.message);}
  2090. }
  2091.  
  2092. function messageParserCheckCSS() {
  2093. try{
  2094. var messages = chatlogElem.querySelectorAll(messageQueryString)
  2095. for (i=0; i < messages.length; i++) {
  2096. var tcMessageHtmlElem = messages[i].querySelector("tc-message-html").shadowRoot;
  2097. if (!tcMessageHtmlElem.querySelector("#messageCSS")) tcMessageHtmlElem.appendChild(messageParserAddCSS());
  2098. if (settingsQuick["NightMode"]) tcMessageHtmlElem.querySelector("#html").classList.add("tes-nightmode");
  2099. }
  2100. }catch(e){tcl("error messageParserCheckCSS: " + e.message);}
  2101. }
  2102. function messageParserAddCSS(elem=null) {
  2103. try{
  2104. var node = document.createElement("style");
  2105. var textnode = document.createTextNode(messageCSS);
  2106. node.appendChild(textnode);
  2107. node.setAttribute("id", "messageCSS");
  2108.  
  2109. if (elem) { elem.appendChild(node); }
  2110. else { return node; }
  2111. }catch(e){tcl("error messageParserAddCSS: " + e.message);}
  2112. }
  2113. function messageParser() {
  2114. try{
  2115. latestMessageElem = chatlogElem.querySelector(messageQueryString + ":last-of-type");
  2116.  
  2117. var typeSystem = false;
  2118.  
  2119. if (latestMessageElem != null) {
  2120. if (latestMessageElem.classList.contains("system")) typeSystem = true;
  2121. latestMessageElem.setAttribute("id", "msg-"+messageCount);
  2122. messageCount++;
  2123.  
  2124. if (!typeSystem) {
  2125. var latestMessageNickElem = latestMessageElem.querySelector(".nickname");
  2126. var latestMessageNick = latestMessageNickElem.innerHTML;
  2127. }
  2128. else {
  2129. latestMessageNick = "&system";
  2130. }
  2131.  
  2132. tcMessageHtmlElem = latestMessageElem.querySelector("tc-message-html").shadowRoot;
  2133. latestMessageContentElem = tcMessageHtmlElem.querySelector("#html");
  2134.  
  2135. if (!browserFirefox) {
  2136. if (!tcMessageHtmlElem.querySelector("#messageCSS")) {
  2137. messageParserAddCSS(tcMessageHtmlElem);
  2138. }
  2139. if (settingsQuick["NightMode"]) latestMessageContentElem.classList.add("tes-nightmode");
  2140. if (settingsQuick["NightModeBlack"]) latestMessageContentElem.classList.add("blacknight");
  2141. }
  2142.  
  2143.  
  2144. latestMessageContent = latestMessageContentElem.innerHTML;
  2145.  
  2146. latestMessageContent.includes(" banned ") || latestMessageContent.includes(" kicked ") ? latestMessageElem.classList.add("dontHide") : void(0);
  2147.  
  2148. if (!browserFirefox && settingsQuick["MentionsMonitor"]) {
  2149. for (i=0; i < settingMentions.length; i++) {
  2150. if (latestMessageContent.toLowerCase().includes(settingMentions[i].toLowerCase())) {
  2151. latestMessageContentElem.classList.add("tes-mention-message");
  2152. audioPop.play();
  2153. tcl('MENTION: "' + settingMentions[i] + '" : ' + latestMessageContent);
  2154. break;
  2155. }
  2156. }
  2157. }
  2158. }
  2159. }catch(e){tcl("error messageParser: " + e.message);}
  2160. }
  2161.  
  2162.  
  2163. var messagesMO = new MutationObserver(function (e) {
  2164. if (e[0].addedNodes) newMessageAdded();
  2165. });
  2166. messagesMO.observe(chatlogElem.querySelector("#chat-content"), { childList: true });
  2167.  
  2168. var camsMO = new MutationObserver(function (e) {
  2169. if (e[0].addedNodes) newCamAdded();
  2170. });
  2171. camsMO.observe(videolistElem.querySelector(".videos-items:last-child"), { childList: true });
  2172.  
  2173. var userContextmenuMO = new MutationObserver(function (e) {
  2174. if (e[0].addedNodes) userContextmenuUpdated();
  2175. });
  2176. userContextmenuMO.observe(userContextmenuCSS, { attributes: true });
  2177.  
  2178. var chatTextboxMO = new MutationObserver(function (e) {
  2179. if (e[0].addedNodes) chatboxSwitch();
  2180. });
  2181. chatTextboxMO.observe(chatlogElem.querySelector("#chat-instant"), { attributes: true, attributeFilter: ['class'], childList: false, characterData: false });
  2182.  
  2183. var userlistMO = new MutationObserver(function (e) {
  2184. if (e[0].addedNodes) newUserAdded();
  2185. });
  2186. userlistMO.observe(userlistElem.querySelector("#userlist"), { childList: true });
  2187.  
  2188. function chatboxSwitch() {
  2189. messageParserCheckCSS();
  2190. return;
  2191.  
  2192. // if (chatlistElem.querySelector("#chat-instant-button")) chatlistElem.querySelector("#chat-instant-button").classList.add("tes-loading");
  2193. try{
  2194. chatboxPM = (chatlogElem.querySelector("#chat-instant").getAttribute("class") == "show");
  2195. chatboxPM ? chatlogCSS.classList.add("tes-chatboxPM") : chatlogCSS.classList.remove("tes-chatboxPM");
  2196. messageParserCheckCSS();
  2197. }catch(e){tcl("error chatboxSwitch: " + e.message)};
  2198. }
  2199.  
  2200. function timestampAdd(opt=null) {
  2201. try{
  2202. var SHOW_SECONDS = true;
  2203.  
  2204. var date = new Date();
  2205. var hours = date.getHours();
  2206. var minutes = date.getMinutes().toString();
  2207. var secs = date.getSeconds().toString();
  2208.  
  2209. if (hours > 11) {
  2210. hours = (hours % 12 || 12);
  2211. var period = "pm";
  2212. }
  2213. else { var period = "am"; }
  2214.  
  2215. if (hours == "0") { hours = "12"; }
  2216. if (minutes == "0") { minutes = "00"; }
  2217. if (minutes.length == 1) { minutes = "0" + minutes; }
  2218. if (secs.length == 1) { secs = "0" + secs; }
  2219.  
  2220. if (SHOW_SECONDS == true) {
  2221. var timestamp = hours + ":" + minutes + ":" + secs + "" + period;
  2222. }
  2223. else {
  2224. var timestamp = hours + ":" + minutes + period;
  2225. }
  2226.  
  2227. if (opt == "return") return;
  2228.  
  2229. var queryString = messageQueryString + ".common:last-of-type .nickname";
  2230. if (chatlogElem.querySelector(queryString) != null) {
  2231. var recentMsgNickname = chatlogElem.querySelector(queryString);
  2232. recentMsgNickname.insertAdjacentHTML("afterend", "<span id='timestamp'> " + timestamp + "</span>");
  2233. }
  2234. }catch(e){tcl("error timestampAdd: " + e.message);}
  2235. }
  2236.  
  2237. function newUserAdded(opt=null) {
  2238. try{
  2239. if (!userlistElem.querySelector("#userlist .list-item")) return;
  2240. var usersElems = userlistElem.querySelectorAll("#userlist .list-item");
  2241. userCount = usersElems.length;
  2242.  
  2243. setTimeout(function() {
  2244. for (i=0; i < usersElems.length; i++) {
  2245. var userNickItem = usersElems[i].querySelector(".nickname");
  2246. var userNick = userNickItem.innerHTML;
  2247.  
  2248. userNickItem.classList.remove("tes-myNick");
  2249. if (userNick == myNick) {
  2250. userNickItem.classList.add("tes-myNick");
  2251. }
  2252. }
  2253. }, 500);
  2254.  
  2255. if (opt == "scanOnly") {
  2256. return;
  2257. }
  2258. else {
  2259. if (!userlistElem.querySelector("#tes-userCount")) {
  2260. userCountParElem = userlistElem.querySelector("#header > span");
  2261. userCountElem = document.createElement("span");
  2262. userCountElem.setAttribute("id", "tes-userCount");
  2263. userCountElem.innerHTML = "(" + userCount + ")";
  2264. userCountParElem.appendChild(userCountElem);
  2265. userCountElem = userlistElem.querySelector("#tes-userCount");
  2266. }
  2267. else {
  2268. userCountElem.innerHTML = "(" + userCount + ")";
  2269. }
  2270. }
  2271. }catch(e){tcl("error newUserAdded: " + e.message);}
  2272. }
  2273.  
  2274. function newCamAdded() {
  2275. try{
  2276. if (videolistElem.querySelector(camQueryString)) var camElems = videolistElem.querySelectorAll(camQueryString);
  2277. else return;
  2278.  
  2279. camsCount = 0;
  2280.  
  2281. for (i=0; i < camElems.length; i++) {
  2282. camsCount = i + 1;
  2283. var camItem = camElems[i].querySelector("tc-video-item").shadowRoot;
  2284. var camItemCSS = camItem.querySelector(".video");
  2285. if (settingsQuick["NightMode"]) camItemCSS.classList.add("tes-nightmode");
  2286. else camItemCSS.classList.remove("tes-nightmode");
  2287. if (settingsQuick["NightModeBlack"]) camItemCSS.classList.add("blacknight");
  2288. else camItemCSS.classList.remove("blacknight");
  2289. if (settingsQuick["BorderlessCams"]) camItemCSS.classList.add("tes-borderlesscams");
  2290. else camItemCSS.classList.remove("tes-borderlesscams");
  2291.  
  2292. if (!camItem.querySelector("#camItemCSS")) camItemCSS.insertAdjacentHTML("afterbegin", camItemCSShtml);
  2293.  
  2294. var camName = camItem.querySelector(".nickname").getAttribute("title");
  2295. camElems[i].setAttribute("id", "camUser-"+camName);
  2296.  
  2297. // Cam maxing
  2298. try {
  2299. if (camItem.querySelector(".icon-tes-max")) {
  2300. var maxbutton = camItem.querySelector(".icon-tes-max");
  2301. maxbutton.parentNode.removeChild(maxbutton);
  2302. }
  2303.  
  2304. camItem.querySelector(".icon-resize").insertAdjacentHTML("beforebegin", camMaxButtonHtml);
  2305. camItem.querySelector(".icon-tes-max").setAttribute("id", "maxbutton-" + camName);
  2306.  
  2307.  
  2308. var maxCamVar = function(maxCamVarArg){
  2309. videolistElem.querySelector(".videos-items:last-child").classList.remove("tes-max-noAnim");
  2310. maximizeCam(maxCamVarArg, "buttonpress");
  2311. };
  2312. camItem.querySelector("#maxbutton-"+camName).addEventListener("click", maxCamVar.bind(this, camName));
  2313.  
  2314. if (camMaxedCurrent == camName) {
  2315. camElems[i].classList.add("tes-maxedCam");
  2316. camElems[i].parentElement.classList.add("tes-max");
  2317. }
  2318. if (!videolistElem.querySelector(".tes-maxedCam")) camElems[i].parentElement.classList.remove("tes-max");
  2319.  
  2320. if (videolistCSS.querySelector("#camMaxCSS")) {
  2321. var maxcss = videolistCSS.querySelector("#camMaxCSS");
  2322. maxcss.parentNode.removeChild(maxcss);
  2323. }
  2324. videolistCSS.insertAdjacentHTML("beforeend", camMaxCSShtml);
  2325.  
  2326. }
  2327. catch(e) { tcl("error newCamAdded: " + e.message); }
  2328.  
  2329. if (settingsQuick["HideAllCams"] == "true" || urlPars.get("hideallcams") == "") {
  2330. camItem.querySelector("button.icon-visibility").click();
  2331. tcl("Cam hide: " + camName);
  2332. }
  2333.  
  2334. camCounter(camElems[i]);
  2335. }
  2336. }catch(e){tcl("error newCamAdded: " + e.message);}
  2337. }
  2338.  
  2339. function maximizeCam(camName, opt=null) {
  2340. try {
  2341. if (camName != camMaxedCurrent && camMaxedCurrent != null) {
  2342. maximizeCam(camMaxedCurrent);
  2343. maximizeCam(camName);
  2344. return;
  2345. }
  2346.  
  2347. var camElem = videolistElem.querySelector("#camUser-" + camName);
  2348. if (camElem == null) {
  2349. camMaxedCurrent = null;
  2350. return;
  2351. }
  2352.  
  2353. if (opt == "bbuttonpress") {
  2354. camElem.parentElement.classList.remove("tes-max-noAnim");
  2355. }
  2356.  
  2357. if (camElem.classList.contains("tes-maxedCam")) {
  2358. camElem.classList.remove("tes-maxedCam");
  2359. camElem.parentElement.classList.remove("tes-max");
  2360. camMaxedCurrent = null;
  2361. }
  2362. else {
  2363. camElem.classList.add("tes-maxedCam");
  2364. camElem.parentElement.classList.add("tes-max");
  2365. camMaxedCurrent = camName;
  2366. setTimeout(function(){ camElem.parentElement.classList.add("tes-max-noAnim"); }, 500);
  2367. }
  2368. camCounter(camElem);
  2369. }
  2370. catch(e) { tcl("error maximizeCam: " + e.message); }
  2371. }
  2372.  
  2373. function camCounter(camElem) {
  2374. try{
  2375. if (camsCount == 12) {
  2376. camElem.parentElement.classList.remove("tes-camCount10-11");
  2377. camElem.parentElement.classList.remove("tes-camCount2");
  2378.  
  2379. camElem.parentElement.classList.add("tes-camCount12");
  2380. }
  2381. else if (camsCount > 9 && camsCount < 12) {
  2382. camElem.parentElement.classList.remove("tes-camCount12");
  2383. camElem.parentElement.classList.remove("tes-camCount2");
  2384.  
  2385. camElem.parentElement.classList.add("tes-camCount10-11");
  2386. }
  2387. else if (camsCount == 2) {
  2388. camElem.parentElement.classList.remove("tes-camCount12");
  2389. camElem.parentElement.classList.remove("tes-camCount10-11");
  2390.  
  2391. camElem.parentElement.classList.add("tes-camCount2");
  2392. }
  2393. else {
  2394. camElem.parentElement.classList.remove("tes-camCount12");
  2395. camElem.parentElement.classList.remove("tes-camCount10-11");
  2396. camElem.parentElement.classList.remove("tes-camCount2");
  2397. }
  2398. }catch(e){tcl("error camCounter: " + e.message);}
  2399. }
  2400. } catch(e) { tcl("error runTES: " + e.message); }
  2401. /* End main function */
  2402. return {
  2403. newUserAdded: newUserAdded
  2404. };
  2405. }
  2406.  
  2407.  
  2408. function tcl(m) { console.log("%cTES: " + "%c" + m, "font-weight: bold; color: #53b6ef;", "") };
  2409.  
  2410. function TESwsParser() {
  2411. wsdata = [];
  2412. chatlogMain = "";
  2413. userlistLog = {};
  2414. userlistLogQuits = {};
  2415. newline = `
  2416. `;
  2417. WebSocket.prototype._send = WebSocket.prototype.send;
  2418. WebSocket.prototype.send = function (data) {
  2419. this._send(data);
  2420. this.addEventListener('message', function (msg) {
  2421. try{
  2422. if (msg.data.includes('"tc":"joined"')) {
  2423. var joined = JSON.parse(msg.data);
  2424. myNick = joined["self"]["nick"];
  2425. myHandle = joined["self"]["handle"];
  2426. }
  2427. if (msg.data.includes('"tc":"msg"') && msg.data.includes('"handle"')) {
  2428. var messageArr = JSON.parse(msg.data);
  2429. var handle = messageArr["handle"];
  2430. chatlogAdd(userlistLog[handle]["nick"] + ": " + messageArr["text"]);
  2431. }
  2432. if (msg.data.includes('"item"')) {
  2433. if (msg.data.includes('tc":"yut_play"')) {
  2434. var youtubeArr = JSON.parse(msg.data);
  2435. var id = youtubeArr["item"]["id"];
  2436. chatlogAdd("- YouTube video started: " + "https://youtube.com/watch?v=" + id);
  2437. }
  2438. if (msg.data.includes('tc":"yut_stop"')) chatlogAdd("- YouTube video stopped.");
  2439. }
  2440. if (msg.data.match(/"tc":"(?:un)?publish"/)) {
  2441. var publishArr = JSON.parse(msg.data);
  2442. var action = (publishArr["tc"] == "publish") ? "is" : "stopped";
  2443. var handle = publishArr["handle"];
  2444.  
  2445. if (userlistLog[handle]) var nick = userlistLog[handle]["nick"];
  2446. else var nick = userlistLogQuits[handle]["nick"];
  2447.  
  2448. chatlogAdd("- " + nick + " " + action + " broadcasting.");
  2449. }
  2450. if (msg.data.includes('"tc":"sysmsg"')) {
  2451. var systext = JSON.parse(msg.data)["text"];
  2452. chatlogAdd("-- " + systext);
  2453. }
  2454. if (msg.data.includes('"tc":"userlist"')) {
  2455. userlistArr = JSON.parse(msg.data)["users"];
  2456. for (i=0; i < userlistArr.length; i++) {
  2457. var nick = userlistArr[i]["nick"];
  2458. var handle = userlistArr[i]["handle"];
  2459. var username = userlistArr[i]["username"];
  2460. userlistLog[handle] = {"nick":nick, "username":username};
  2461. }
  2462. }
  2463. if (msg.data.includes('"tc":"join","username":"')) {
  2464. var userArr = JSON.parse(msg.data)
  2465. var nick = userArr["nick"];
  2466. var handle = userArr["handle"];
  2467. var username = userArr["username"];
  2468. userlistLog[handle] = {"nick":nick, "username":username};
  2469. }
  2470. if (msg.data.includes('"tc":"quit"')) {
  2471. var userArr = JSON.parse(msg.data);
  2472. var handle = userArr["handle"];
  2473. userlistLogQuits[handle] = userlistLog[handle];
  2474. delete userlistLog[handle];
  2475. }
  2476. if (msg.data.includes('"tc":"nick"')) {
  2477. var userArr = JSON.parse(msg.data);
  2478. var handle = userArr["handle"];
  2479. var nick = userArr["nick"];
  2480.  
  2481. userlistLog[handle]["nick"] = nick;
  2482. if (handle == myHandle) {
  2483. myNick = nick;
  2484. }
  2485. TESapp.newUserAdded("scanOnly");
  2486. }
  2487. }catch(e){tcl("error TESwsParser: " + e.message);}
  2488. }, false);
  2489. this.send = function (data) {
  2490. this._send(data);
  2491. };
  2492.  
  2493. }
  2494.  
  2495. function chatlogAdd(arg) {
  2496. var timestamp = new Date().toLocaleTimeString('en-US', { hour12: false });
  2497. chatlogMain += "[" + timestamp + "] " + arg + newline;
  2498. }
  2499. }
Advertisement
Add Comment
Please, Sign In to add comment
Advertisement