Skip to content

Instantly share code, notes, and snippets.

Show Gist options
  • Save Kurotaku-sama/bf8fef7e64b6954d6fad35f3682acc5e to your computer and use it in GitHub Desktop.
Save Kurotaku-sama/bf8fef7e64b6954d6fad35f3682acc5e to your computer and use it in GitHub Desktop.
Adds buttons to send commands for the onstream games in the twitch chat
// ==UserScript==
// @name Twitch hitsquadgodfather command buttons
// @namespace https://kurotaku.de
// @version 1.5.8
// @description Adds buttons to send commands for the onstream games in the Twitch chat
// @author Kurotaku
// @license MIT
// @match https://www.twitch.tv/hitsquadgodfather*
// @match https://www.twitch.tv/hitsquadbrawlers*
// @match https://www.twitch.tv/hitsquadplays*
// @match https://www.twitch.tv/*/hitsquadgodfather/chat*
// @match https://www.twitch.tv/*/hitsquadbrawlers/chat*
// @match https://www.twitch.tv/*/hitsquadplays/chat*
// @icon https://static.twitchcdn.net/assets/favicon-32-e29e246c157142c94346.png
// @updateURL https://gist.github.com/Kurotaku-sama/bf8fef7e64b6954d6fad35f3682acc5e/raw/Twitch%2520hitsquadgodfather%2520command%2520buttons.user.js
// @downloadURL https://gist.github.com/Kurotaku-sama/bf8fef7e64b6954d6fad35f3682acc5e/raw/Twitch%2520hitsquadgodfather%2520command%2520buttons.user.js
// @require https://gist.github.com/Kurotaku-sama/9ebeb659500f6eee2f780344948e1e8f/raw/kuros_library.user.js
// @require https://openuserjs.org/src/libs/sizzle/GM_config.js
// @grant GM_getValue
// @grant GM_setValue
// @grant GM_registerMenuCommand
// ==/UserScript==
const twitch_host = 'irc-ws.chat.twitch.tv';
const twitch_port = 443;
let twitch_channel; // Variable to store channel name later
let socket;
let timer;
let reconnect_interval = 5000;
(async function() {
await init_gm_config(); // Initialize the configuration
if(GM_config.get("script_enabled"))
if(GM_config.get("auth_username") != "" && GM_config.get("auth_oauth") != "") {
wait_for_element('.chat-input').then(async () => {
if(GM_config.get("voucher_buttons"))
add_voucher_buttons();
twitch_channel = document.title.split(" ")[0]; // Get channel name here bcs in the first view milliseconds the document title is only "Twitch"
if(twitch_channel === "Twitch") // Fallback for sites like Multistre.am
twitch_channel = "hitsquadgodfather";
connect_to_twitch();
add_command_buttons();
});
}
else // Warning if people haven't set up the oauth token correctly
wait_for_element('.chat-input').then(async () => {
let html = `<div id="actions" class="k-buttongroups"><label class="k-buttongroup-label">Hello thanks for installing my Twitch hitsquadgodfather command buttons userscript.<br><br>Click on the Tampermonkey extension and click on settings underneath the script and insert your username + oauth token in order to be able to connect to the chat with this script.</label></div>`;
document.querySelector(".chat-input").insertAdjacentHTML('beforebegin', html);
});
})();
function init_gm_config() {
GM_registerMenuCommand('Settings', () => {
GM_config.open();
});
let frame = document.createElement('div');
document.body.appendChild(frame);
GM_config.init(
{
'id': 'configuration',
'title': 'Twitch hitsquadgodfather config',
'fields':
{
'script_enabled':
{
'label': 'Enable/Disable the script',
'type': 'checkbox',
'default': true
},
'auth_username':
{
'label': 'Username',
'type': 'textbox'
},
'auth_oauth':
{
'label': 'Oauth (required for IRC connection to chat!)<br>Can be generated here: https://twitchapps.com/tmi/',
'type': 'textbox'
},
'voucher_buttons': {
'label': 'Voucher redemption buttons',
'type': 'checkbox',
'default': true
},
// 'voucher_buttons_point_check': {
// 'label': 'Point check for vouchers:<br>Disable this if you can\'t redeem vouchers even when you have the amount of required points.',
// 'type': 'checkbox',
// 'default': true
// },
'buttons_general':
{
'label': 'General buttons',
'type': 'checkbox',
'default': true
},
'buttons_trivia':
{
'label': 'Trivia buttons',
'type': 'checkbox',
'default': true
},
'showdown_buttons': {
'label': 'Showdown buttons',
'type': 'checkbox',
'default': true
},
'bypass_shadowban': {
'label': 'Bypass Shadowban:<br>Enable this only, if you get shadowbanned after a couple of commands.<br>(Shadowban is when your messages are temporarily not appear)',
'type': 'checkbox',
'default': false
},
},
'events': {
'save': () => {location.reload()},
},
'frame': frame,
'css': '#configuration {color: black; height:auto !important; width:auto !important; padding:20px !important;max-height: 600px !important;max-width:500px !important; border: 3px solid #000 !important} #configuration .section_header {background: unset; color:unset;} #configuration .config_header {font-size:17pt; font-weight:bold} #configuration .config_var {margin-top:10px; display: flex;} .config_var :nth-child(2) {order:-1; margin-right:10px;} #configuration_buttons_holder {text-align: center;} #configuration #configuration_resetLink {color:#fff;}'
});
}
function connect_to_twitch() {
socket = new WebSocket(`wss://${twitch_host}:${twitch_port}`);
socket.onopen = () => {
console.log('Twitch connection started.');
socket.send(`PASS ${GM_config.get("auth_oauth").includes("oauth:") ? GM_config.get("auth_oauth") : "oauth:" + GM_config.get("auth_oauth")}`);
socket.send(`NICK ${GM_config.get("auth_username")}`);
socket.send(`JOIN #${twitch_channel}`);
timer = setInterval(function() {
socket.send('PING :tmi.twitch.tv');
}, 5 * 60 * 1000); // Send all 5 minutes a ping
};
socket.onclose = function() {
console.log('Twitch connection closed.');
// Stoppe den Timer, wenn die Verbindung geschlossen wurde
clearInterval(timer);
// Versuche, die Verbindung automatisch neu zu öffnen
setTimeout(function() {
connect_to_twitch();
}, reconnect_interval);
};
}
function close_target() {
switch_panel(null);
}
function switch_panel(event) {
document.querySelector("#actions").classList.toggle("hidden");
document.querySelector("#targets").classList.toggle("hidden");
if(event)
document.querySelector("#targets").setAttribute("data-action", event.target.getAttribute("cmd"));
}
function show_role(event) {
let roles = document.querySelectorAll(".k-role");
roles.forEach(el => {
if(el.getAttribute("data-role") === event.target.getAttribute("data-role"))
el.classList.remove("hidden")
else
el.classList.add("hidden")
});
}
function send_command(event) {
let cmd = "";
if(event.target.parentNode.parentNode.getAttribute("data-action")) {
cmd = event.target.parentNode.parentNode.getAttribute("data-action"); // Add action attack or devine in case its from the switched panel
// Remove the data and go back to main panel
event.target.parentNode.parentNode.setAttribute("data-action", "");
switch_panel(null);
}
cmd += event.target.getAttribute("cmd");
let suffix = "!";
if(cmd.trim() !== "" && cmd !== null)
if(GM_config.get("bypass_shadowban"))
sendMessageToTwitchChat(`${suffix}${randomize_case(cmd)}`);
else
sendMessageToTwitchChat(`${suffix}${cmd}`);
else
alert("Please contact script creator, this button doesn't seem to work correctly");
}
function sendMessageToTwitchChat(message) {
socket.send(`PRIVMSG #${twitch_channel} :${message}`);
socket.onerror = (error) => {
console.error('Error:', error);
};
}
function add_command_buttons() {
let buttongroups = "";
if(GM_config.get("buttons_general"))
buttongroups += `<label class="k-buttongroup-label">General</label>
<div class="k-buttongroup">
<button cmd="hitsquad" class="actionbutton">Hitsquad</button>
<button cmd="strikes" class="actionbutton">Strikes</button>
</div>`;
if(GM_config.get("buttons_trivia"))
buttongroups += `<label class="k-buttongroup-label">Trivia</label>
<div class="k-buttongroup">
<button cmd="answer1" class="actionbutton">1</button>
<button cmd="answer2" class="actionbutton">2</button>
<button cmd="answer3" class="actionbutton">3</button>
<button cmd="answer4" class="actionbutton">4</button>
<button cmd="triviapoints" class="actionbutton">Points</button>
</div>`;
if(GM_config.get("showdown_buttons")) {
// Selection
buttongroups += `<label class="k-buttongroup-label">Showdown</label>
<div class="k-buttongroup">
<button cmd="wizard" class="actionbutton">Wizard</button>
<button cmd="knight" class="actionbutton">Knight</button>
<button cmd="cleric" class="actionbutton">Cleric</button>
<button cmd="experience" class="actionbutton">Experience</button>
</div>`;
// Labels to show roles
buttongroups += `<div class="k-labelgroup">
<label class="k-selection-label" data-role="wizard">Wizard</label>
<label class="k-selection-label" data-role="knight">Knight</label>
<label class="k-selection-label" data-role="cleric">Cleric</label>
<label class="k-selection-label" data-role="close">Close</label>
</div>`; // Wizard
buttongroups += `<div class="k-buttongroup k-role hidden" data-role="wizard">
<button cmd="attack" class="targetbutton">Attack</button>
<button cmd="flames" class="actionbutton">Flames</button>
<button cmd="shield" class="actionbutton">Shield</button>
<button cmd="moan" class="actionbutton">Moan</button></div>`;
// Knight
buttongroups += `<div class="k-buttongroup k-role hidden" data-role="knight">
<button cmd="attack" class="targetbutton">Attack</button>
<button cmd="frenzy" class="actionbutton">Frenzy</button>
<button cmd="rally" class="actionbutton">Rally</button>
<button cmd="moan" class="actionbutton">moan</button></div>`;
// Cleric
buttongroups += `<div class="k-buttongroup k-role hidden" data-role="cleric">
<button cmd="attack" class="targetbutton">Attack</button>
<button cmd="divine" class="targetbutton">Divine</button>
<button cmd="heal" class="actionbutton">Heal</button>
<button cmd="moan" class="actionbutton">Moan</button>
</div>`;
}
let html = `<div id="actions" class="k-buttongroups">${buttongroups}</div>`;
html += `<div id="targets" class="k-buttongroups hidden" data-action="">
<label class="k-buttongroup-label targets">Targets</label>
<div class="k-buttongroup">
<button cmd="1" class="actionbutton">1</button>
<button cmd="2" class="actionbutton">2</button>
<button cmd="3" class="actionbutton">3</button>
<button cmd="4" class="actionbutton">4</button>
<button cmd="5" class="actionbutton">5</button>
<button class="closebutton">Close</button>
</div>`;
document.querySelector(".chat-input").insertAdjacentHTML('beforebegin', html);
if(document.querySelector(".k-buttongroup .closebutton"))
document.querySelector(".k-buttongroup .closebutton").addEventListener("click", close_target, false);
let actionbuttons = document.querySelectorAll(".k-buttongroup .actionbutton");
actionbuttons.forEach(el => {el.addEventListener("click", send_command, false)});
let targetbuttons = document.querySelectorAll(".k-buttongroup .targetbutton");
targetbuttons.forEach(el => {el.addEventListener("click", switch_panel, false)});
let selection_labels = document.querySelectorAll(".k-selection-label");
selection_labels.forEach(el => {el.addEventListener("click", show_role, false)});
}
async function add_voucher_buttons() {
wait_for_element('.chat-input__buttons-container').then(async () => {
let html = `<div class="k-buttongroups"><div class="k-buttongroup">
<button id="add_1k" voucher="1,000 Clams Voucher" cost="5000" class="actionbutton">+1k Clams</button>
<button id="add_2k" voucher="2,000 Clams Voucher" cost="10000" class="actionbutton">+2k Clams</button>
</div></div>`
document.querySelector(".chat-input").insertAdjacentHTML('afterend', html);
document.querySelector("#add_1k").addEventListener("click", add_clams, false);
document.querySelector("#add_2k").addEventListener("click", add_clams, false);
});
}
async function add_clams(trigger) {
let voucher = trigger.target.attributes.voucher.value;
let cost = parseInt(trigger.target.attributes.cost.value);
let storebutton = document.querySelector(".community-points-summary button");
// let points = parseInt(storebutton.querySelector(`div[data-test-selector="balance-string"] > span`).innerHTML.toLowerCase()
// .replace(".", "").replace(",", "").replace(" ", "")
// .replace("k", "000").replace("万", "000").replace("萬", "000").replace("만", "000").replace("тыс", "000").replace("tis", "000")
// .replace("mio", "000000").replace("mil", "000000").replace("mill", "000000").replace("tr", "000000")
// .replace("млн", "000000").replace("εκ", "000000").replace("mn", "000000").replace("mln", "000000").replace("m", "000000"));
// if(GM_config.get("voucher_buttons_point_check") == false || points >= cost) { // Check if you have enough points (when not disabled by the point check)
storebutton.click();
wait_for_element('.rewards-list').then(async () => { // Wait till rewards list is showing
let rewards = document.querySelector(".rewards-list");
let reward = rewards.querySelector(`img[alt="${voucher}"]`);
if(reward) { // Open the voucher buy menu
reward.click();
wait_for_element('.reward-center-body button.ScCoreButton-sc-ocjdkq-0').then(async () => { // Wait till voucher item is showing
let reward_redeem_button = document.querySelector(".reward-center-body button.ScCoreButton-sc-ocjdkq-0");
if(reward_redeem_button.disabled == false)
reward_redeem_button.click();
else {
storebutton.click();
alert("Error: Reward not available, maybe you reached maximum amount of claims for this stream or you don't have enough channel points!");
}
});
}
else
alert("Error: Reward not found maybe they are disabled at the moment, if not than please contact script creator via Discord");
});
// }
// else
// alert("You don't have enough channel points for this Action!<br>If you are sure that you have enough points and this is a mistake, go into the userscript settings and disable \"Point check for vouchers\"");
}
// Add custom styles
let styles = `
.actionbutton {
min-width:40px;
background-color: var(--color-background-button-primary-default);
color: var(--color-text-button-primary);
display: inline-flex;
position: relative;
-moz-box-align: center;
align-items: center;
-moz-box-pack: center;
justify-content: center;
vertical-align: middle;
overflow: hidden;
text-decoration: none;
text-decoration-color: currentcolor;
white-space: nowrap;
user-select: none;
font-weight: var(--font-weight-semibold);
font-size: var(--button-text-default);
height: var(--button-size-default);
border-radius: var(--input-border-radius-default);
}
.k-buttongroups {
padding-left: 20px;
padding-right: 20px;}
.k-buttongroup {
display: flex;
flex-wrap: wrap;
grid-column-gap: 10px;}
.k-buttongroup-label {}
.k-buttongroup > button {
min-width:50px;
margin-bottom:5px;}
.k-labelgroup {
margin-top: 10px;
font-size: 20px;
justify-content: space-between;
display: flex;}
.hidden { display:none;}
`;
// Insert custom Styles
let style_sheet = document.createElement("style");
style_sheet.innerText = styles;
document.head.appendChild(style_sheet);
@Kurotaku-sama
Copy link
Author

i add you, but check your code tomorrow (i'm busy)

Write me your username or write me a PM instead of adding me, recently I get so extremly much random friendinvites that I had to disable friend requests.

@Kurotaku-sama
Copy link
Author

I am really sorry somehow the auto update for all my userscripts didn't worked for quiet a while now.
Everyone who is using any of my userscripts must reinstall the userscripts, I fixed them all.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment