Instantly share code, notes, and snippets.
Last active
June 12, 2024 21:49
-
Star
(4)
4
You must be signed in to star a gist -
Fork
(1)
1
You must be signed in to fork a gist
-
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
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
// ==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); |
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
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.