Skip to content

Instantly share code, notes, and snippets.

Show Gist options
  • Save Kurotaku-sama/2f22a38c553d5403a97271edaa601b8f to your computer and use it in GitHub Desktop.
Save Kurotaku-sama/2f22a38c553d5403a97271edaa601b8f to your computer and use it in GitHub Desktop.
Adds buttons to send commands for the onstream games in the YouTube chat
// ==UserScript==
// @name YouTube hitsquadgodfather command buttons
// @namespace kurotaku.de
// @version 1.2.6
// @description Adds buttons to send commands for the onstream games in the YouTube chat
// @author Kurotaku
// @license MIT
// @match https://www.youtube.com/live_chat?*
// @icon https://www.youtube.com/s/desktop/6ee70b2c/img/favicon_32x32.png
// @require https://openuserjs.org/src/libs/sizzle/GM_config.js
// @updateURL https://gist.github.com/Kurotaku-sama/2f22a38c553d5403a97271edaa601b8f/raw/YouTube%2520hitsquadgodfather%2520command%2520buttons.user.js
// @downloadURL https://gist.github.com/Kurotaku-sama/2f22a38c553d5403a97271edaa601b8f/raw/YouTube%2520hitsquadgodfather%2520command%2520buttons.user.js
// @require https://gist.github.com/Kurotaku-sama/9ebeb659500f6eee2f780344948e1e8f/raw/kuros_library.user.js
// @grant GM_getValue
// @grant GM_setValue
// @grant GM_registerMenuCommand
// ==/UserScript==
(async function() {
if(document.querySelector("html").innerHTML.includes("HitsquadGodfather")) { // Check if the page contains the word HitsquadGodfather to make sure its only appearing on GF Stream
await init_gm_config(); // Initialize the configuration
wait_for_element('#input-container #input.yt-live-chat-text-input-field-renderer').then(async () => {
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 yt-spec-button-shape-next yt-spec-button-shape-next--tonal yt-spec-button-shape-next--mono yt-spec-button-shape-next--size-m">Hitsquad</button>
<button cmd="strikes" class="actionbutton yt-spec-button-shape-next yt-spec-button-shape-next--tonal yt-spec-button-shape-next--mono yt-spec-button-shape-next--size-m">Strikes</button>
<button cmd="points" class="actionbutton yt-spec-button-shape-next yt-spec-button-shape-next--tonal yt-spec-button-shape-next--mono yt-spec-button-shape-next--size-m">Points</button>
</div></div>`;
if(GM_config.get("buttons_trivia"))
buttongroups += `<label class="k-buttongroup-label">Trivia</label>
<div class="k-buttongroup">
<button cmd="answer1" class="actionbutton yt-spec-button-shape-next yt-spec-button-shape-next--tonal yt-spec-button-shape-next--mono yt-spec-button-shape-next--size-m">1</button>
<button cmd="answer2" class="actionbutton yt-spec-button-shape-next yt-spec-button-shape-next--tonal yt-spec-button-shape-next--mono yt-spec-button-shape-next--size-m">2</button>
<button cmd="answer3" class="actionbutton yt-spec-button-shape-next yt-spec-button-shape-next--tonal yt-spec-button-shape-next--mono yt-spec-button-shape-next--size-m">3</button>
<button cmd="answer4" class="actionbutton yt-spec-button-shape-next yt-spec-button-shape-next--tonal yt-spec-button-shape-next--mono yt-spec-button-shape-next--size-m">4</button>
</div>`;
if(GM_config.get("showdown_buttons")) {
buttongroups += ``;
// Selection
buttongroups += `<label class="k-buttongroup-label">Showdown</label>
<div class="k-buttongroup">
<button cmd="wizard" class="actionbutton yt-spec-button-shape-next yt-spec-button-shape-next--tonal yt-spec-button-shape-next--mono yt-spec-button-shape-next--size-m">Wizard</button>
<button cmd="knight" class="actionbutton yt-spec-button-shape-next yt-spec-button-shape-next--tonal yt-spec-button-shape-next--mono yt-spec-button-shape-next--size-m">Knight</button>
<button cmd="cleric" class="actionbutton yt-spec-button-shape-next yt-spec-button-shape-next--tonal yt-spec-button-shape-next--mono yt-spec-button-shape-next--size-m">Cleric</button>
<button cmd="experience" class="actionbutton yt-spec-button-shape-next yt-spec-button-shape-next--tonal yt-spec-button-shape-next--mono yt-spec-button-shape-next--size-m">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 yt-spec-button-shape-next yt-spec-button-shape-next--tonal yt-spec-button-shape-next--mono yt-spec-button-shape-next--size-m">Attack</button>
<button cmd="flames" class="actionbutton yt-spec-button-shape-next yt-spec-button-shape-next--tonal yt-spec-button-shape-next--mono yt-spec-button-shape-next--size-m">Flames</button>
<button cmd="shield" class="actionbutton yt-spec-button-shape-next yt-spec-button-shape-next--tonal yt-spec-button-shape-next--mono yt-spec-button-shape-next--size-m">Shield</button>
<button cmd="moan" class="actionbutton yt-spec-button-shape-next yt-spec-button-shape-next--tonal yt-spec-button-shape-next--mono yt-spec-button-shape-next--size-m">Moan</button>
</div>`;
// Knight
buttongroups += `<div class="k-buttongroup k-role hidden" data-role="knight">
<button cmd="attack" class="targetbutton yt-spec-button-shape-next yt-spec-button-shape-next--tonal yt-spec-button-shape-next--mono yt-spec-button-shape-next--size-m">Attack</button>
<button cmd="frenzy" class="actionbutton yt-spec-button-shape-next yt-spec-button-shape-next--tonal yt-spec-button-shape-next--mono yt-spec-button-shape-next--size-m">Frenzy</button>
<button cmd="rally" class="actionbutton yt-spec-button-shape-next yt-spec-button-shape-next--tonal yt-spec-button-shape-next--mono yt-spec-button-shape-next--size-m">Rally</button>
<button cmd="moan" class="actionbutton yt-spec-button-shape-next yt-spec-button-shape-next--tonal yt-spec-button-shape-next--mono yt-spec-button-shape-next--size-m">Moan</button>
</div>`;
// Cleric
buttongroups += `<div class="k-buttongroup k-role hidden" data-role="cleric">
<button cmd="attack" class="targetbutton yt-spec-button-shape-next yt-spec-button-shape-next--tonal yt-spec-button-shape-next--mono yt-spec-button-shape-next--size-m">Attack</button>
<button cmd="divine" class="targetbutton yt-spec-button-shape-next yt-spec-button-shape-next--tonal yt-spec-button-shape-next--mono yt-spec-button-shape-next--size-m">Divine</button>
<button cmd="heal" class="actionbutton yt-spec-button-shape-next yt-spec-button-shape-next--tonal yt-spec-button-shape-next--mono yt-spec-button-shape-next--size-m">Heal</button>
<button cmd="moan" class="actionbutton yt-spec-button-shape-next yt-spec-button-shape-next--tonal yt-spec-button-shape-next--mono yt-spec-button-shape-next--size-m">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 yt-spec-button-shape-next yt-spec-button-shape-next--tonal yt-spec-button-shape-next--mono yt-spec-button-shape-next--size-m">1</button>
<button cmd="2" class="actionbutton yt-spec-button-shape-next yt-spec-button-shape-next--tonal yt-spec-button-shape-next--mono yt-spec-button-shape-next--size-m">2</button>
<button cmd="3" class="actionbutton yt-spec-button-shape-next yt-spec-button-shape-next--tonal yt-spec-button-shape-next--mono yt-spec-button-shape-next--size-m">3</button>
<button cmd="4" class="actionbutton yt-spec-button-shape-next yt-spec-button-shape-next--tonal yt-spec-button-shape-next--mono yt-spec-button-shape-next--size-m">4</button>
<button cmd="5" class="actionbutton yt-spec-button-shape-next yt-spec-button-shape-next--tonal yt-spec-button-shape-next--mono yt-spec-button-shape-next--size-m">5</button>
<button class="closebutton yt-spec-button-shape-next yt-spec-button-shape-next--tonal yt-spec-button-shape-next--mono yt-spec-button-shape-next--size-m">Close</button>
</div>`;
document.querySelector("#contents #panel-pages").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)});
});
}
})();
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': 'YouTube hitsquadgodfather config',
'fields':
{
'script_enabled':
{
'label': 'Enable/Disable the script',
'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
},
},
'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 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)
sendMessageToYouTubeChat(suffix + cmd + ' - ' + makeid(5));
//console.log(suffix + cmd);
else
alert("Please contact script creator, this button doesn't seem to work correctly");
}
function sendMessageToYouTubeChat(message) {
// Without this solution I probably would hang myself :D
// https://stackoverflow.com/questions/75962593/sending-message-on-youtube-live-chat-with-chrome-extension
console.log('Sending message:', message);
//const liveChatFrame = document.querySelector('iframe.style-scope.ytd-live-chat-frame');
//const chatInputBox = liveChatFrame.contentDocument.querySelector('#input.yt-live-chat-text-input-field-renderer');
const chatInputBox = document.querySelector('#input.yt-live-chat-text-input-field-renderer');
console.log('Chat input box:', chatInputBox);
chatInputBox.focus();
chatInputBox.innerText = message;
chatInputBox.dispatchEvent(new Event('input', { bubbles: true }));
//setTimeout(() => {
//const sendButton = liveChatFrame.contentDocument.querySelector('#button.yt-icon-button[aria-label="Send"]');
const sendButton = document.querySelector('#send-button button');
console.log('Send button:', sendButton);
if (sendButton) {
console.log('Clicking send button');
try {
sendButton.dispatchEvent(new MouseEvent('click', { bubbles: true }));
} catch (error) {
console.error('Error sending message:', error);
}
} else {
console.error('Could not find send button');
}
//}, 1000);
}
// Add custom styles
let styles = `
.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