Skip to content

Instantly share code, notes, and snippets.

Show Gist options
  • Save Kurotaku-sama/090f27bf20be879ddd5d0de88af3ac7f to your computer and use it in GitHub Desktop.
Save Kurotaku-sama/090f27bf20be879ddd5d0de88af3ac7f to your computer and use it in GitHub Desktop.
Adds buttons to send commands in the Twitch chat
// ==UserScript==
// @name Twitch staggerrilla command buttons
// @namespace https://kurotaku.de
// @version 1.0.9
// @description Adds buttons to send commands in the Twitch chat
// @author Kurotaku
// @license MIT
// @match https://www.twitch.tv/staggerrilla*
// @icon https://static.twitchcdn.net/assets/favicon-32-e29e246c157142c94346.png
// @updateURL https://gist.github.com/Kurotaku-sama/090f27bf20be879ddd5d0de88af3ac7f/raw/Twitch%2520staggerrilla%2520command%2520buttons.user.js
// @downloadURL https://gist.github.com/Kurotaku-sama/090f27bf20be879ddd5d0de88af3ac7f/raw/Twitch%2520staggerrilla%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 = 'staggerrilla'; // 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();
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 staggerrilla 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 staggerrilla 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/<br><b>Warning: If you already generated such a oauth token for another channel, copy it from that script and paste it here!</b>',
'type': 'textbox'
},
'voucher_buttons': {
'label': 'Voucher redemption buttons',
'type': 'checkbox',
'default': true
},
'buttons_general':
{
'label': 'General 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 temporaril 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="fish" class="actionbutton">Fish</button>
<button cmd="bloop" class="actionbutton">Bloop</button>
<button cmd="bub" class="actionbutton">Bub</button>
<button cmd="bleep" class="actionbutton">Bleep</button>
<button cmd="insert 75" class="actionbutton">Insert 75</button>
</div>`;
let html = `<div id="actions" class="k-buttongroups">${buttongroups}</div>`;
document.querySelector(".chat-input").insertAdjacentHTML('beforebegin', html);
let actionbuttons = document.querySelectorAll(".k-buttongroup .actionbutton");
actionbuttons.forEach(el => {el.addEventListener("click", send_command, 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_75k" voucher="75k Bubbers" cost="115000" class="actionbutton">+75k</button>
<button id="add_100k" voucher="100k Bubbers" cost="150000" class="actionbutton">+100k</button>
<button id="add_200k" voucher="300k" cost="300000" class="actionbutton">+200k</button>
</div></div>`
document.querySelector(".chat-input").insertAdjacentHTML('afterend', html);
document.querySelector("#add_75k").addEventListener("click", add_bubs, false);
document.querySelector("#add_100k").addEventListener("click", add_bubs, false);
document.querySelector("#add_200k").addEventListener("click", add_bubs, false);
});
}
async function add_bubs(trigger) {
let voucher = trigger.target.attributes.voucher.value;
let cost = parseInt(trigger.target.attributes.cost.value);
let storebutton = document.querySelector(".community-points-summary button");
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");
});
}
// 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);
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment