mirror of
https://github.com/chylex/Transparent-Twitch-Chat.git
synced 2025-05-18 15:34:04 +02:00
951 lines
25 KiB
JavaScript
951 lines
25 KiB
JavaScript
// ==UserScript==
|
|
// @name Transparent Twitch Chat
|
|
// @description Why decide between missing a PogChamp or sacrificing precious screen space, when you can have the best of both worlds!
|
|
// @version {VERSION}
|
|
// @namespace https://chylex.com
|
|
// @homepageURL https://github.com/chylex/Transparent-Twitch-Chat
|
|
// @supportURL https://github.com/chylex/Transparent-Twitch-Chat/issues
|
|
// @updateURL https://github.com/chylex/Transparent-Twitch-Chat/raw/master/dist/TransparentTwitchChat.user.js
|
|
// @include https://www.twitch.tv/*
|
|
// @run-at document-end
|
|
// @grant GM_getValue
|
|
// @grant GM_setValue
|
|
// @noframes
|
|
// ==/UserScript==
|
|
|
|
const settings = {
|
|
globalSwitch: true,
|
|
|
|
chatWidth: 350,
|
|
chatFilters: "",
|
|
playerPosition: "center center",
|
|
grayTheme: false,
|
|
|
|
hideHeader: true,
|
|
hideChatInput: false,
|
|
hidePinnedCheer: false,
|
|
hideConversations: false,
|
|
|
|
transparentChat: true,
|
|
smoothTextShadow: false,
|
|
chatLeftSide: false,
|
|
backgroundOpacity: 30,
|
|
|
|
hideBadgeTurbo: true,
|
|
hideBadgePrime: true,
|
|
hideBadgeSubscriber: true,
|
|
hideBadgeVIP: false,
|
|
hideBadgeSubGift: false,
|
|
hideBadgeBitCheer: false,
|
|
hideBadgeLeader: false,
|
|
badgeOpacity: 85
|
|
};
|
|
|
|
if (typeof GM_getValue !== "undefined"){
|
|
for(let key in settings){
|
|
settings[key] = GM_getValue(key, settings[key]);
|
|
}
|
|
}
|
|
|
|
const isFirefox = "mozPaintCount" in window;
|
|
|
|
function tryRemoveElement(ele){
|
|
if (ele && ele.parentNode){
|
|
ele.parentNode.removeChild(ele);
|
|
}
|
|
}
|
|
|
|
function onSettingsUpdated(){
|
|
generateCustomCSS();
|
|
refreshChatFilters();
|
|
|
|
if (typeof GM_setValue !== "undefined"){
|
|
for(let key in settings){
|
|
GM_setValue(key, settings[key]);
|
|
}
|
|
}
|
|
}
|
|
|
|
// Styles
|
|
|
|
function generateCustomCSS(){
|
|
if (!settings.globalSwitch){
|
|
tryRemoveElement(document.getElementById("chylex-ttc-style-custom"));
|
|
return;
|
|
}
|
|
|
|
const wa = ":not(.ttcwa)"; // selector priority workaround
|
|
const rcol = ".right-column--theatre";
|
|
const rcolBlur = ".right-column--theatre:not(:hover)";
|
|
const isTheatre = ".ttc-theatre";
|
|
const fullWidth = ".ttc-rcol-collapsed";
|
|
const fullScreen = ".ttc-player-fullscreen";
|
|
|
|
let style = document.getElementById("chylex-ttc-style-custom");
|
|
|
|
if (!style){
|
|
style = document.createElement("style");
|
|
style.id = "chylex-ttc-style-custom";
|
|
}
|
|
|
|
style.innerHTML = `@#rem{{
|
|
|
|
@#css{{
|
|
|
|
// fix scrollbars
|
|
|
|
${rcolBlur} .chat-list__lines .simplebar-track.vertical {
|
|
visibility: hidden !important;
|
|
}
|
|
|
|
@#css}}
|
|
|
|
${isFirefox ? `@#css{{
|
|
${rcol} .video-chat__message-list-wrapper:not(.video-chat__message-list-wrapper--unsynced) {
|
|
overflow-y: hidden !important;
|
|
}
|
|
@#css}}` : ``}
|
|
|
|
@#css{{
|
|
|
|
// general player styles
|
|
|
|
${isTheatre} .video-player video {
|
|
object-position: ${settings.playerPosition} !important;
|
|
}
|
|
|
|
// general chat styles
|
|
|
|
${rcolBlur} .channel-root__right-column${wa} {
|
|
background: rgba(14, 12, 19, ${settings.backgroundOpacity * 0.01}) !important;
|
|
}
|
|
|
|
${rcol}${wa}, ${rcol} .channel-root__right-column${wa} {
|
|
width: ${settings.chatWidth - 10}px !important;
|
|
}
|
|
|
|
${rcol} .video-chat {
|
|
flex-basis: auto !important;
|
|
}
|
|
|
|
${rcol} .video-chat__header {
|
|
display: none !important;
|
|
}
|
|
|
|
${rcol} .room-picker {
|
|
width: ${settings.chatWidth - 10}px;
|
|
}
|
|
|
|
${rcol} .hidden {
|
|
display: none;
|
|
}
|
|
|
|
${rcol} .video-chat__sync-button {
|
|
width: ${settings.chatWidth - 50}px;
|
|
z-index: 10;
|
|
background-color: #b8b5c0 !important;
|
|
}
|
|
|
|
@#css}}
|
|
|
|
#root[data-a-page-loaded-name="VideoWatchPage"] ${rcolBlur}:not(.right-column--collapsed) .right-column__toggle-visibility {
|
|
display: none !important;
|
|
}
|
|
|
|
${settings.hideHeader ? `@#css{{
|
|
${rcolBlur} .stream-chat-header {
|
|
display: none !important;
|
|
}
|
|
|
|
${rcolBlur}:not(.right-column--collapsed) .right-column__toggle-visibility {
|
|
display: none !important;
|
|
}
|
|
@#css}}` : ``}
|
|
|
|
${settings.hideChatInput ? `@#css{{
|
|
${rcolBlur} .chat-input {
|
|
display: none !important;
|
|
}
|
|
@#css}}` : ``}
|
|
|
|
${settings.hidePinnedCheer ? `@#css{{
|
|
.channel-leaderboard {
|
|
display: none;
|
|
}
|
|
@#css}}` : ``}
|
|
|
|
${settings.transparentChat ? `@#css{{
|
|
|
|
// expand player width
|
|
|
|
body:not(${fullScreen}) .persistent-player--theatre {
|
|
width: 100% !important;
|
|
}
|
|
|
|
body:not(${fullWidth}):not(${fullScreen}) .persistent-player--theatre .top-bar,
|
|
body:not(${fullWidth}):not(${fullScreen}) .persistent-player--theatre .player-controls {
|
|
padding-right: ${settings.chatWidth - 10}px;
|
|
}
|
|
|
|
body:not(${fullWidth}):not(${fullScreen}) .persistent-player--theatre .player-overlay-background > div {
|
|
right: ${settings.chatWidth - 10}px !important;
|
|
}
|
|
|
|
// chat container transparency
|
|
|
|
${rcol} .chat-room {
|
|
background: transparent !important;
|
|
}
|
|
|
|
${rcolBlur} .chylex-ttc-chat-container {
|
|
color: #ece8f3 !important;
|
|
}
|
|
|
|
${rcolBlur} .rooms-header, ${rcolBlur} .leaderboard-header-tabbed-layout {
|
|
background: transparent !important;
|
|
}
|
|
|
|
${rcolBlur} .chat-input {
|
|
opacity: 0.6;
|
|
}
|
|
|
|
// chat messages
|
|
|
|
${rcolBlur} .chylex-ttc-chat-container {
|
|
${settings.smoothTextShadow ? `
|
|
text-shadow: 0 0 2px @#hex(000d), -1px 0 1px @#hex(0006), 0 -1px 1px @#hex(0006), 1px 0 1px @#hex(0006), 0 1px 1px @#hex(0006);
|
|
` : `
|
|
text-shadow: -1px 0 0 @#hex(000a), 0 -1px 0 @#hex(000a), 1px 0 0 @#hex(000a), 0 1px 0 @#hex(000a);
|
|
`}
|
|
}
|
|
|
|
${rcolBlur} .chat-author__display-name, ${rcolBlur} .vod-message__timestamp {
|
|
${settings.smoothTextShadow ? `
|
|
text-shadow: -1px 0 1px @#hex(0006), 0 -1px 1px @#hex(0006), 1px 0 1px @#hex(0006), 0 1px 1px @#hex(0006);
|
|
` : `
|
|
text-shadow: -1px 0 0 @#hex(0008), 0 -1px 0 @#hex(0008), 1px 0 0 @#hex(0008), 0 1px 0 @#hex(0008);
|
|
`}
|
|
}
|
|
|
|
${rcolBlur} .chat-line__message--mention-recipient {
|
|
text-shadow: none;
|
|
}
|
|
|
|
${rcolBlur} .chat-line__message a {
|
|
color: #cdb9f5 !important;
|
|
}
|
|
|
|
// conversation menu
|
|
|
|
.whispers--theatre-mode .whispers-threads-box__container:not(.whispers-threads-box__container--open):not(:hover) {
|
|
opacity: ${Math.max(0.1, settings.backgroundOpacity * 0.01)};
|
|
}
|
|
@#css}}` : `@#css{{
|
|
|
|
// adapt player size with disabled transparency
|
|
|
|
body:not(${fullWidth}):not(${fullScreen}) .persistent-player--theatre {
|
|
width: calc(100% - ${settings.chatWidth - 10}px) !important;
|
|
}
|
|
|
|
body:not(${fullScreen}) .persistent-player--theatre .player-streamstatus {
|
|
margin-right: 20px !important;
|
|
}
|
|
@#css}}`}
|
|
|
|
// conversation menu and bottom margin
|
|
|
|
.whispers--theatre-mode.whispers--right-column-expanded-beside {
|
|
right: ${settings.chatWidth - 10}px !important;
|
|
}
|
|
|
|
${settings.hideConversations ? `@#css{{
|
|
.whispers--theatre-mode${wa} {
|
|
display: none !important;
|
|
}
|
|
|
|
.video-player__container--theatre-whispers, .highwind-video-player__container--theatre-whispers {
|
|
bottom: 1px !important; // allows hiding player controls in fullscreen by moving cursor all the way down
|
|
}
|
|
@#css}}` : ``}
|
|
|
|
// chat on left side
|
|
|
|
${settings.chatLeftSide && settings.transparentChat ? `@#css{{
|
|
${isTheatre} .side-nav {
|
|
display: none !important;
|
|
}
|
|
|
|
${rcol}${wa}, ${rcol} .chat-list__lines .simplebar-track.vertical {
|
|
left: 0 !important;
|
|
right: auto !important;
|
|
}
|
|
|
|
${rcol} .channel-root__right-column${wa} {
|
|
border-left: none !important;
|
|
border-right: var(--border-width-default) solid var(--color-border-base) !important;
|
|
}
|
|
|
|
body:not(${fullWidth}):not(${fullScreen}) .persistent-player--theatre .top-bar {
|
|
padding-left: ${settings.chatWidth}px;
|
|
padding-right: 0;
|
|
}
|
|
|
|
body:not(${fullWidth}):not(${fullScreen}) .persistent-player--theatre .player-controls {
|
|
padding-left: ${settings.chatWidth - 10}px;
|
|
padding-right: 0;
|
|
}
|
|
|
|
body:not(${fullWidth}):not(${fullScreen}) .persistent-player--theatre .player-overlay-background > div {
|
|
left: ${settings.chatWidth - 10}px !important;
|
|
right: 0 !important;
|
|
}
|
|
|
|
.whispers--theatre-mode.whispers--right-column-expanded-beside {
|
|
right: 0px !important;
|
|
}
|
|
|
|
${rcol} .right-column__toggle-visibility {
|
|
transform: rotate(180deg) !important;
|
|
}
|
|
|
|
${rcol}.right-column--collapsed .right-column__toggle-visibility {
|
|
left: 0.5rem;
|
|
}
|
|
@#css}}` : ``}
|
|
|
|
// gray theme
|
|
|
|
${settings.grayTheme ? `@#css{{
|
|
${rcol} [data-a-target="chat-input"] {
|
|
background-color: #0e0e0e !important;
|
|
border-color: #2b2b2b !important;
|
|
}
|
|
|
|
${rcol} [data-a-target="chat-input"]:focus {
|
|
border-color: #787878 !important;
|
|
box-shadow: 0 0 6px -2px #787878 !important;
|
|
}
|
|
|
|
${rcol} [data-a-target="chat-send-button"] {
|
|
background-color: #2b2b2b !important;
|
|
border: 1px solid #000000 !important;
|
|
}
|
|
|
|
${rcol} [data-a-target="chat-send-button"]:active, ${rcol} [data-a-target="chat-send-button"]:focus {
|
|
box-shadow: 0 0 6px 0 #787878 !important;
|
|
}
|
|
@#css}}` : ``}
|
|
|
|
@#css{{
|
|
|
|
// badge tweaks
|
|
|
|
${rcolBlur} a[data-a-target="chat-badge"] {
|
|
opacity: ${settings.badgeOpacity / 100};
|
|
${settings.badgeOpacity === 0 ? `display: none !important;` : ``}
|
|
}
|
|
|
|
@#css}}
|
|
|
|
${settings.hideBadgeTurbo ? `@#css{{
|
|
${rcol} .chat-badge[alt="Turbo"] {
|
|
display: none;
|
|
}
|
|
@#css}}` : ``}
|
|
|
|
${settings.hideBadgePrime ? `@#css{{
|
|
${rcol} .chat-badge[alt$="Prime"] {
|
|
display: none;
|
|
}
|
|
@#css}}` : ``}
|
|
|
|
${settings.hideBadgeSubscriber ? `@#css{{
|
|
${rcol} .chat-badge[alt~="Subscriber"] {
|
|
display: none;
|
|
}
|
|
@#css}}` : ``}
|
|
|
|
${settings.hideBadgeVIP ? `@#css{{
|
|
${rcol} .chat-badge[alt="VIP"] {
|
|
display: none;
|
|
}
|
|
@#css}}` : ``}
|
|
|
|
${settings.hideBadgeSubGift ? `@#css{{
|
|
${rcol} .chat-badge[alt*="Gift Subs"] {
|
|
display: none;
|
|
}
|
|
@#css}}` : ``}
|
|
|
|
${settings.hideBadgeBitCheer ? `@#css{{
|
|
${rcol} .chat-badge[alt~="cheer"] {
|
|
display: none;
|
|
}
|
|
@#css}}` : ``}
|
|
|
|
${settings.hideBadgeLeader ? `@#css{{
|
|
${rcol} .chat-badge[alt*="Bits Leader"], ${rcol} .chat-badge[alt*="Gifter Leader"] {
|
|
display: none;
|
|
}
|
|
@#css}}` : ``}
|
|
|
|
@#css{{
|
|
|
|
// dynamic styles for settings, replaces default style
|
|
|
|
#chylex-ttc-settings-btn {
|
|
margin-left: ${settings.chatWidth - 60}px;
|
|
}
|
|
|
|
@#css}}
|
|
@#rem}}`;
|
|
|
|
document.head.appendChild(style);
|
|
}
|
|
|
|
function generateSettingsCSS(){
|
|
if (document.getElementById("chylex-ttc-style-settings")){
|
|
return;
|
|
}
|
|
|
|
const style = document.createElement("style");
|
|
style.id = "chylex-ttc-style-settings";
|
|
style.innerHTML = `@#rem{{@#css{{
|
|
|
|
// settings button
|
|
|
|
#chylex-ttc-settings-btn {
|
|
display: none;
|
|
width: 2.5em;
|
|
height: 2.5em;
|
|
position: absolute;
|
|
bottom: 105px;
|
|
margin-left: 290px;
|
|
z-index: 9;
|
|
cursor: pointer;
|
|
fill: @#hex(fffa);
|
|
}
|
|
|
|
.video-chat #chylex-ttc-settings-btn {
|
|
bottom: 18px;
|
|
}
|
|
|
|
#chylex-ttc-settings-btn svg {
|
|
width: 100%;
|
|
height: 100%;
|
|
}
|
|
|
|
#chylex-ttc-settings-btn:hover {
|
|
fill: #fff;
|
|
}
|
|
|
|
.right-column--theatre:hover #chylex-ttc-settings-btn {
|
|
display: block;
|
|
}
|
|
|
|
// settings modal
|
|
|
|
#chylex-ttc-settings-modal {
|
|
position: absolute;
|
|
left: 50%;
|
|
top: 50%;
|
|
width: 870px;
|
|
height: 294px;
|
|
margin-left: -435px;
|
|
margin-top: -147px;
|
|
z-index: 10000;
|
|
background-color: @#hex(111c);
|
|
}
|
|
|
|
#chylex-ttc-settings-modal #ttc-opt-global-wrapper {
|
|
position: absolute;
|
|
margin: 5px 0 0 -69px;
|
|
display: inline-block;
|
|
}
|
|
|
|
#chylex-ttc-settings-modal h2 {
|
|
color: @#hex(fffe);
|
|
font-size: 24px;
|
|
text-align: center;
|
|
margin: 0;
|
|
padding: 14px 0 13px;
|
|
background-color: @#hex(0009);
|
|
}
|
|
|
|
#chylex-ttc-settings-modal .ttc-flex-container {
|
|
display: flex;
|
|
flex-direction: row;
|
|
justify-content: space-between;
|
|
padding: 8px 4px;
|
|
}
|
|
|
|
#chylex-ttc-settings-modal p {
|
|
color: @#hex(fffd);
|
|
font-size: 14px;
|
|
margin-top: 8px;
|
|
padding: 0 9px;
|
|
}
|
|
|
|
#chylex-ttc-settings-modal p:first-of-type {
|
|
margin: 0 0 4px;
|
|
}
|
|
|
|
#chylex-ttc-settings-modal .player-menu__section {
|
|
padding: 0 12px 2px;
|
|
}
|
|
|
|
#chylex-ttc-settings-modal .player-menu__header {
|
|
margin-bottom: 0;
|
|
color: @#hex(fffa);
|
|
}
|
|
|
|
#chylex-ttc-settings-modal .player-menu__item {
|
|
display: flex;
|
|
align-items: center;
|
|
margin: 2px 0 9px;
|
|
padding-left: 1px;
|
|
}
|
|
|
|
#chylex-ttc-settings-modal .player-menu__item.ttc-setting-small-margin {
|
|
margin-bottom: 7px;
|
|
}
|
|
|
|
#chylex-ttc-settings-modal .switch {
|
|
font-size: 10px;
|
|
height: 17px;
|
|
line-height: 17px;
|
|
}
|
|
|
|
#chylex-ttc-settings-modal .switch span {
|
|
width: 27px;
|
|
}
|
|
|
|
#chylex-ttc-settings-modal .switch.active span {
|
|
left: 25px;
|
|
}
|
|
|
|
#chylex-ttc-settings-modal .switch::before, #chylex-ttc-settings-modal .switch::after {
|
|
width: 26px;
|
|
box-sizing: border-box;
|
|
}
|
|
|
|
#chylex-ttc-settings-modal .switch::before {
|
|
text-align: left;
|
|
padding-left: 5px;
|
|
}
|
|
|
|
#chylex-ttc-settings-modal .switch::after {
|
|
text-align: right;
|
|
padding-right: 3px;
|
|
}
|
|
|
|
#chylex-ttc-settings-modal input[type="text"] {
|
|
width: 100%;
|
|
padding: 1px 4px;
|
|
}
|
|
|
|
#chylex-ttc-settings-modal input[type="range"] {
|
|
width: 100%;
|
|
}
|
|
|
|
#chylex-ttc-settings-modal select {
|
|
width: 100%;
|
|
padding: 1px 0;
|
|
}
|
|
|
|
#chylex-ttc-settings-modal output {
|
|
color: @#hex(fffc);
|
|
display: inline-block;
|
|
flex: 1 1 42px;
|
|
padding-left: 6px;
|
|
text-align: left;
|
|
}
|
|
|
|
#chylex-ttc-settings-modal .tw-toggle__button {
|
|
width: 4rem;
|
|
}
|
|
|
|
#chylex-ttc-settings-modal .tw-toggle__button, #chylex-ttc-settings-modal .tw-toggle__button::after {
|
|
border-radius: 0;
|
|
}
|
|
@#css}}@#rem}}`;
|
|
|
|
document.head.appendChild(style);
|
|
}
|
|
|
|
// Filters
|
|
|
|
function getNodeText(node){
|
|
if (node.nodeType === Node.TEXT_NODE){
|
|
return node.nodeValue;
|
|
}
|
|
|
|
if (node.nodeType === Node.ELEMENT_NODE){
|
|
if (node.tagName === "IMG"){
|
|
return node.getAttribute("alt") || "";
|
|
}
|
|
else{
|
|
let text = "";
|
|
|
|
for(let child of node.childNodes){
|
|
text += getNodeText(child);
|
|
}
|
|
|
|
return text;
|
|
}
|
|
}
|
|
|
|
return "";
|
|
}
|
|
|
|
var filtersRegex = null;
|
|
|
|
var filtersObserver = new MutationObserver(function(mutations){
|
|
for(let mutation of mutations){
|
|
for(let added of mutation.addedNodes){
|
|
let text;
|
|
const classes = added.classList;
|
|
|
|
if (classes.contains("chat-line__message")){
|
|
const nodes = Array.from(added.childNodes);
|
|
const colon = nodes.findIndex(node => node.tagName === "SPAN" && node.innerText === ": ");
|
|
text = nodes.slice(colon+1).map(getNodeText).join("");
|
|
}
|
|
else{
|
|
text = getNodeText(added.querySelector(".qa-mod-message") || added);
|
|
}
|
|
|
|
if (filtersRegex.test(text)){
|
|
classes.add("hidden");
|
|
}
|
|
}
|
|
}
|
|
});
|
|
|
|
function refreshChatFilters(){
|
|
const chat = document.querySelector(".chat-list__lines .simplebar-content > div, .video-chat__message-list-wrapper ul");
|
|
|
|
if (!chat){
|
|
return false;
|
|
}
|
|
|
|
const filters = (settings.chatFilters || "").split(",").map(entry => entry.trim()).filter(entry => !!entry);
|
|
|
|
if (filters.length === 0){
|
|
filtersRegex = null;
|
|
}
|
|
else{
|
|
const options = filters.map(entry => entry.replace(/[.+?^${}()|[\]\\]/g, "\\$&").replace(/\*/g, "(?:\\S*)").replace(/\s+/g, "\\s+")).join("|");
|
|
filtersRegex = new RegExp("(?:^|[^a-z0-9])(?:"+options+")(?:$|[^a-z0-9])", "i");
|
|
}
|
|
|
|
if (filtersRegex && settings.globalSwitch){
|
|
filtersObserver.observe(chat, { childList: true });
|
|
}
|
|
else{
|
|
filtersObserver.disconnect();
|
|
}
|
|
|
|
return true;
|
|
}
|
|
|
|
// Helpers
|
|
|
|
var classObserverCallback = function(mutations){
|
|
for(let mutation of mutations){
|
|
const classes = mutation.target.classList;
|
|
|
|
if (classes.contains("right-column")){
|
|
document.body.classList.toggle("ttc-theatre", classes.contains("right-column--theatre"));
|
|
document.body.classList.toggle("ttc-rcol-collapsed", classes.contains("right-column--collapsed"));
|
|
}
|
|
}
|
|
};
|
|
|
|
var classObserver = new MutationObserver(classObserverCallback);
|
|
|
|
function setupClassHelpers(){
|
|
const col = document.querySelector(".right-column");
|
|
|
|
if (!col){
|
|
return false;
|
|
}
|
|
|
|
classObserver.observe(col, { attributes: true, attributeFilter: [ "class" ] });
|
|
|
|
classObserverCallback([
|
|
{ target: col }
|
|
]);
|
|
|
|
return true;
|
|
}
|
|
|
|
function setupFullscreenHelper(){
|
|
for(let event of [ "fullscreenchange", "webkitfullscreenchange", "mozfullscreenchange", "msfullscreenchange" ]){
|
|
if ("on" + event in document){
|
|
document.addEventListener(event, function(){
|
|
document.body.classList.toggle("ttc-player-fullscreen", document.fullscreenElement || document.webkitFullscreenElement || document.mozFullScreenElement || document.msFullscreenElement);
|
|
});
|
|
|
|
break;
|
|
}
|
|
}
|
|
}
|
|
|
|
// Settings
|
|
|
|
function debounce(func, wait){
|
|
let timeout = -1;
|
|
|
|
return function(){
|
|
window.clearTimeout(timeout);
|
|
timeout = window.setTimeout(func, wait);
|
|
};
|
|
}
|
|
|
|
function createSettingsModal(){
|
|
tryRemoveElement(document.getElementById("chylex-ttc-settings-modal"));
|
|
|
|
const generateOptionBase = function(title, item, extra){
|
|
extra = extra || {};
|
|
|
|
return `
|
|
<div class="player-menu__section" data-enabled="true"${extra.floatLeft ? ` style="float:left"` : ""}>
|
|
<div class="player-menu__header">
|
|
<span class="js-menu-header">${title}</span>
|
|
</div>
|
|
<div class="player-menu__item ${extra.itemClasses ? " " + extra.itemClasses : ""}">
|
|
${item}
|
|
</div>
|
|
</div>`;
|
|
};
|
|
|
|
const prepareOptionEvent = function(option, setupCallback){
|
|
window.setTimeout(function(){
|
|
const ele = document.getElementById("ttc-opt-" + option);
|
|
setupCallback(ele);
|
|
}, 1);
|
|
};
|
|
|
|
const updateOption = function(option, value){
|
|
settings[option] = value;
|
|
onSettingsUpdated();
|
|
};
|
|
|
|
// Concrete option types
|
|
|
|
const generateToggle = function(title, option, floatLeft){
|
|
prepareOptionEvent(option, function(ele){
|
|
ele.addEventListener("click", function(){ updateOption(option, ele.checked); });
|
|
});
|
|
|
|
return generateOptionBase(title, `
|
|
<div class="tw-toggle">
|
|
<input class="tw-toggle__input" id="ttc-opt-${option}" value="${settings[option] ? "on" : "off"}" type="checkbox"${settings[option] ? " checked" : ""}>
|
|
<label for="ttc-opt-${option}" class="tw-toggle__button"></label>
|
|
</div>`, floatLeft ? { floatLeft: true } : {});
|
|
};
|
|
|
|
const generateTxtbox = function(title, option, cfg){
|
|
prepareOptionEvent(option, function(ele){
|
|
ele.addEventListener("input", debounce(function(){ updateOption(option, ele.value); }, cfg.wait));
|
|
});
|
|
|
|
return generateOptionBase(title, `<input id="ttc-opt-${option}" type="text" value="${settings[option]}" placeholder="${cfg.placeholder}">`);
|
|
};
|
|
|
|
const generateSelect = function(title, option, cfg){
|
|
prepareOptionEvent(option, function(ele){
|
|
ele.addEventListener("input", function(){ updateOption(option, ele.value); });
|
|
});
|
|
|
|
const initialOption = settings[option];
|
|
const optionElements = Object.keys(cfg).map(function(key){
|
|
return `<option value="${key}"${key == initialOption ? " selected" : ""}>${cfg[key]}</option>`;
|
|
});
|
|
|
|
return generateOptionBase(title, `<select id="ttc-opt-${option}">${optionElements}</select>`);
|
|
};
|
|
|
|
const generateSlider = function(title, option, cfg){
|
|
prepareOptionEvent(option, function(ele){
|
|
const regenerate = debounce(onSettingsUpdated, cfg.wait);
|
|
|
|
ele.addEventListener("input", function(){
|
|
settings[option] = parseInt(ele.value, 10);
|
|
document.getElementById("ttc-optval-" + option).value = ele.value + cfg.text;
|
|
regenerate();
|
|
});
|
|
});
|
|
|
|
return generateOptionBase(title, `
|
|
<input id="ttc-opt-${option}" type="range" min="${cfg.min}" max="${cfg.max}" step="${cfg.step}" value="${settings[option]}">
|
|
<output id="ttc-optval-${option}" for="ttc-opt-${option}">${settings[option]}${cfg.text}</option>
|
|
`, { itemClasses: "ttc-setting-small-margin" });
|
|
};
|
|
|
|
// Generate modal
|
|
|
|
const modal = document.createElement("div");
|
|
modal.id = "chylex-ttc-settings-modal";
|
|
modal.innerHTML = `
|
|
<h2>
|
|
<div id="ttc-opt-global-wrapper" class="tw-toggle">
|
|
<input class="tw-toggle__input" id="ttc-opt-global" value="${settings.globalSwitch ? "on" : "off"}" type="checkbox"${settings.globalSwitch ? " checked" : ""}>
|
|
<label for="ttc-opt-global" class="tw-toggle__button"></label>
|
|
</div>
|
|
|
|
<span>Transparent Twitch Chat</span>
|
|
</h2>
|
|
|
|
<div class="ttc-flex-container">
|
|
<div style="flex: 0 0 23%">
|
|
<p>General</p>
|
|
${generateSlider("Chat Width", "chatWidth", { min: 250, max: 600, step: 25, wait: 500, text: "px" })}
|
|
${generateTxtbox("Chat Filters", "chatFilters", { wait: 500, placeholder: "Example: kappa, *abc*" })}
|
|
${generateSelect("Player Position", "playerPosition", {
|
|
"top left": "Top Left",
|
|
"top center": "Top Center",
|
|
"top right": "Top Right",
|
|
"center left": "Center Left",
|
|
"center center": "Center",
|
|
"center right": "Center Right",
|
|
"bottom left": "Bottom Left",
|
|
"bottom center": "Bottom Center",
|
|
"bottom right": "Bottom Right"
|
|
})}
|
|
${generateToggle("Gray Theme", "grayTheme")}
|
|
</div>
|
|
|
|
<div style="flex: 0 0 21%">
|
|
<p>Transparency</p>
|
|
${generateToggle("Transparent Chat", "transparentChat")}
|
|
${generateToggle("Smooth Text Shadow", "smoothTextShadow")}
|
|
${generateToggle("Chat on Left Side", "chatLeftSide")}
|
|
${generateSlider("Background Opacity", "backgroundOpacity", { min: 0, max: 100, step: 5, wait: 100, text: "%" })}
|
|
</div>
|
|
|
|
<div style="flex: 0 0 16%">
|
|
<p>Elements</p>
|
|
${generateToggle("Hide Chat Header", "hideHeader")}
|
|
${generateToggle("Hide Chat Input", "hideChatInput")}
|
|
${generateToggle("Hide Pinned Cheer", "hidePinnedCheer")}
|
|
${generateToggle("Hide Whispers", "hideConversations")}
|
|
</div>
|
|
|
|
<div style="flex: 0 0 19%">
|
|
<p>Badges</p>
|
|
${generateToggle("Hide Subscriber Badge", "hideBadgeSubscriber")}
|
|
${generateToggle("Hide Prime Badge", "hideBadgePrime")}
|
|
${generateToggle("Hide Turbo Badge", "hideBadgeTurbo")}
|
|
${generateToggle("Hide VIP Badge", "hideBadgeVIP")}
|
|
</div>
|
|
|
|
<div style="flex: 0 0 21%">
|
|
<p style="visibility: hidden">Badges</p>
|
|
${generateToggle("Hide Sub Gift Badge", "hideBadgeSubGift")}
|
|
${generateToggle("Hide Bit Cheer Badge", "hideBadgeBitCheer")}
|
|
${generateToggle("Hide Gift/Bit Leader Badge", "hideBadgeLeader")}
|
|
${generateSlider("Badge Opacity", "badgeOpacity", { min: 0, max: 100, step: 5, wait: 100, text: "%" })}
|
|
</div>
|
|
</div>
|
|
`;
|
|
|
|
document.body.appendChild(modal);
|
|
|
|
document.getElementById("ttc-opt-global").addEventListener("click", function(e){
|
|
settings.globalSwitch = e.currentTarget.checked;
|
|
onSettingsUpdated();
|
|
});
|
|
|
|
modal.addEventListener("click", function(e){
|
|
e.stopPropagation();
|
|
});
|
|
}
|
|
|
|
function insertSettingsButton(){
|
|
const container = document.querySelector("[data-test-selector='chat-room-component-layout'] > div, .video-chat");
|
|
|
|
if (!container){
|
|
return false;
|
|
}
|
|
|
|
container.classList.add("chylex-ttc-chat-container");
|
|
|
|
tryRemoveElement(document.getElementById("chylex-ttc-settings-btn"));
|
|
tryRemoveElement(document.getElementById("chylex-ttc-settings-modal"));
|
|
|
|
const button = document.createElement("div");
|
|
button.id = "chylex-ttc-settings-btn";
|
|
button.innerHTML = '<svg viewBox="0 0 15 15"><path d="M8.463,0.062c-0.639,-0.083 -1.287,-0.083 -1.926,0l-0.251,1.333c-0.802,0.159 -1.565,0.475 -2.244,0.929l-1.12,-0.765c-0.511,0.394 -0.969,0.852 -1.363,1.363l0.765,1.12c-0.454,0.679 -0.77,1.442 -0.929,2.244l-1.333,0.251c-0.083,0.639 -0.083,1.287 0,1.926l1.333,0.251c0.159,0.802 0.475,1.565 0.929,2.244l-0.765,1.12c0.394,0.511 0.852,0.969 1.363,1.363l1.12,-0.765c0.679,0.454 1.442,0.77 2.244,0.929l0.251,1.333c0.639,0.083 1.287,0.083 1.926,0l0.251,-1.333c0.802,-0.159 1.565,-0.475 2.244,-0.929l1.12,0.765c0.511,-0.394 0.969,-0.852 1.363,-1.363l-0.765,-1.12c0.454,-0.679 0.77,-1.442 0.929,-2.244l1.333,-0.251c0.083,-0.639 0.083,-1.287 0,-1.926l-1.333,-0.251c-0.159,-0.802 -0.475,-1.565 -0.929,-2.244l0.765,-1.12c-0.394,-0.511 -0.852,-0.969 -1.363,-1.363l-1.12,0.765c-0.679,-0.454 -1.442,-0.77 -2.244,-0.929l-0.251,-1.333Zm-0.963,2.731c2.598,0 4.707,2.109 4.707,4.707c0,2.598 -2.109,4.707 -4.707,4.707c-2.598,0 -4.707,-2.109 -4.707,-4.707c0,-2.598 2.109,-4.707 4.707,-4.707Z"/><rect x="6.75" y="6" width="1.5" height="5.25"/><rect x="4.89" y="4.5" width="5.221" height="1.5"/></svg>';
|
|
container.appendChild(button);
|
|
|
|
button.addEventListener("click", function(e){
|
|
if (!document.getElementById("chylex-ttc-settings-modal")){
|
|
createSettingsModal();
|
|
e.stopPropagation();
|
|
}
|
|
});
|
|
|
|
if (isFirefox && container.classList.contains("video-chat")){
|
|
const wrapper = document.querySelector(".video-chat__message-list-wrapper");
|
|
const unsynced = "video-chat__message-list-wrapper--unsynced";
|
|
|
|
wrapper.addEventListener("wheel", function(e){
|
|
if (e.deltaY < 0){
|
|
wrapper.classList.add(unsynced);
|
|
}
|
|
});
|
|
|
|
wrapper.addEventListener("keydown", function(e){
|
|
if (e.keyCode === 38 || e.keyCode === 33){ // up arrow || page up
|
|
wrapper.classList.add(unsynced);
|
|
}
|
|
});
|
|
}
|
|
|
|
return true;
|
|
}
|
|
|
|
// Setup
|
|
|
|
var prevAddress = null;
|
|
var rehookInterval = null;
|
|
|
|
window.setInterval(function(){
|
|
if (location.href != prevAddress){
|
|
prevAddress = location.href;
|
|
|
|
var hooks = [
|
|
refreshChatFilters,
|
|
setupClassHelpers,
|
|
insertSettingsButton
|
|
];
|
|
|
|
window.clearInterval(rehookInterval);
|
|
|
|
rehookInterval = window.setInterval(function(){
|
|
for(let index = hooks.length - 1; index >= 0; index--){
|
|
if (hooks[index]()){
|
|
hooks.splice(index, 1);
|
|
}
|
|
}
|
|
|
|
if (hooks.length === 0){
|
|
window.clearInterval(rehookInterval);
|
|
rehookInterval = null;
|
|
}
|
|
}, 250);
|
|
}
|
|
}, 1000);
|
|
|
|
document.body.addEventListener("click", function(){
|
|
tryRemoveElement(document.getElementById("chylex-ttc-settings-modal"));
|
|
});
|
|
|
|
setupFullscreenHelper();
|
|
|
|
generateSettingsCSS();
|
|
generateCustomCSS();
|