// ==UserScript==
// @name Grizzway Tools
// @namespace http://tampermonkey.net/
// @version 4.8
// @description Epic fixes and visual mods for fishtank.live
// @author Grizzway
// @match *://*.fishtank.live/*
// @grant GM_addStyle
// @license MIT
// ==/UserScript==
(function() {
'use strict';
// User-editable color for stream title
const streamTitleColor = 'limegreen';
const streamTitleFilter = 'drop-shadow(0 0 1px #00ff00) drop-shadow(0 0 2px #00ff00)'
// Custom Ping Sound
const customPingSound = "https://files.catbox.moe/1qbutz.mp3"; // Replace with your own link PLEASE
// Sound blocking functionality
const blockedSounds = [
'https://cdn.fishtank.live/sounds/suicidebomb.mp3',
'https://cdn.fishtank.live/sounds/suicidebomb-1.mp3',
'https://cdn.fishtank.live/sounds/suicidebomb-2.mp3',
'https://cdn.fishtank.live/sounds/suicidebomb-3.mp3',
'https://cdn.fishtank.live/sounds/suicidebomb-4.mp3',
'https://cdn.fishtank.live/sounds/nuke-1.mp3',
'https://cdn.fishtank.live/sounds/nuke-2.mp3',
'https://cdn.fishtank.live/sounds/nuke-3.mp3',
'https://cdn.fishtank.live/sounds/nuke-4.mp3',
'https://cdn.fishtank.live/sounds/nuke-5.mp3',
'https://cdn.fishtank.live/sounds/horn.mp3'
];
// List of unwanted classes to remove
const unwantedClasses = [
'mirror',
'live-stream-player_blur__7BhBE',
'live-stream-player_upside-down__YvkE4',
'chat-message-default_shrink-ray__nGvpr'
];
// Save original Audio class
const OriginalAudio = window.Audio;
// Create a unified Audio wrapper
window.Audio = function(src) {
console.log("[Tampermonkey] Attempting to play sound with src:", src); // Log the source URL
// Check if the sound is a blocked one
if (src && typeof src === "string" && blockedSounds.some(sound => src.includes(sound))) {
console.log('Blocked sound (Audio wrapper):', src);
return new OriginalAudio(); // Prevent playing blocked sound
}
// Check for mention.mp3 and replace with custom ping sound
if (src && typeof src === "string" && src.toLowerCase().includes("mention")) {
console.log("[Tampermonkey] Replacing mention sound with custom sound!", src);
return new OriginalAudio(customPingSound); // Play custom ping sound instead
}
// Log all other sounds for debugging
console.log("[Tampermonkey] Playing sound without modification:", src);
// Default behavior for all other sounds
return new OriginalAudio(src);
};
// Keep Audio.prototype chain intact
window.Audio.prototype = OriginalAudio.prototype;
// Intercept fetch requests and ensure the cache doesn't block our custom sound
const originalFetch = window.fetch;
window.fetch = async function(resource, init) {
if (typeof resource === 'string') {
// Log all resources being fetched to ensure we catch the mention sound
console.log("[Tampermonkey] Fetching resource:", resource);
if (resource.includes('mention.mp3')) {
console.log("[Tampermonkey] Replacing mention sound via fetch:", resource);
return new Response(await fetch(customPingSound), {
status: 200
});
}
if (blockedSounds.some(sound => resource.includes(sound))) {
console.log('Blocked sound (fetch):', resource);
return new Response(null, {
status: 403
});
}
}
return originalFetch(resource, init);
};
// Intercept XMLHttpRequests and modify response for mention.mp3
const originalOpen = XMLHttpRequest.prototype.open;
XMLHttpRequest.prototype.open = function(method, url) {
console.log("[Tampermonkey] XMLHttpRequest opened with URL:", url);
if (url.includes("mention.mp3")) {
console.log("[Tampermonkey] Replacing mention sound via XHR:", url);
// Override the request and prevent the original
this.abort(); // Cancel the original request
const customAudioRequest = new XMLHttpRequest();
customAudioRequest.open(method, customPingSound, true);
customAudioRequest.send();
return;
}
if (blockedSounds.some(sound => url.includes(sound))) {
console.log('Blocked sound (XHR):', url);
this.abort();
} else {
originalOpen.apply(this, arguments);
}
};
// Block audio elements directly (HTMLAudioElement)
const originalAudioPlay = HTMLAudioElement.prototype.play;
HTMLAudioElement.prototype.play = function() {
console.log("[Tampermonkey] Attempting to play audio:", this.src);
if (this.src.includes("mention.mp3")) {
console.log("[Tampermonkey] Replacing mention sound with custom sound in HTMLAudioElement.");
this.src = customPingSound;
}
if (blockedSounds.some(sound => this.src.includes(sound))) {
console.log('Blocked sound (HTMLAudioElement):', this.src);
return Promise.reject('Blocked sound');
}
return originalAudioPlay.apply(this, arguments);
};
setInterval(() => {
const body = document.querySelector('body');
if (body) {
unwantedClasses.forEach(className => {
if (body.classList.contains(className)) {
body.classList.remove(className);
}
});
}
// Check if the video player is open
const videoPlayer = document.querySelector('.live-stream-player_live-stream-player__4CHjG');
if (videoPlayer) {
unwantedClasses.forEach(className => {
const elementsWithClass = videoPlayer.querySelectorAll(`.${className}`);
elementsWithClass.forEach(el => el.classList.remove(className));
if (videoPlayer.classList.contains(className)) {
videoPlayer.classList.remove(className);
}
});
}
// Check chat messages container and its children
const chatContainer = document.querySelector('#chat-messages.chat-messages_chat-messages__UeL0a');
if (chatContainer) {
unwantedClasses.forEach(className => {
const chatElements = chatContainer.querySelectorAll(`.${className}`);
chatElements.forEach(el => el.classList.remove(className));
});
}
// Ensure stream title color stays updated
const streamTitles = document.querySelectorAll('.live-stream_name__ngU04');
streamTitles.forEach(title => {
title.style.color = streamTitleColor;
title.style.filter = streamTitleFilter;
});
}, 1000);
function profileFix() {
const profileModal = document.querySelector('.profile-modal_profile-modal__4mjE7');
if (!profileModal || profileModal.offsetParent === null) return; // Ensure modal is visible
setTimeout(() => {
const bio = profileModal.querySelector('.user-profile_bio__nzdwR');
const clanActions = profileModal.querySelector('.user-profile_clan-actions__aS32x');
const header = profileModal.querySelector('.user-profile_header__zP1kv');
if (!bio || !clanActions || !header) return; // Ensure required elements exist
// Prevent duplicates: Check if already moved
if (header.contains(bio) && header.nextElementSibling === clanActions) return;
// Move bio into header, right after .user-profile_info__eFefT
const userInfo = header.querySelector('.user-profile_info__eFefT');
if (userInfo && !header.contains(bio)) {
bio.remove();
userInfo.insertAdjacentElement('afterend', bio);
}
// Move clan actions **just below** the header
if (header.nextElementSibling !== clanActions) {
clanActions.remove();
header.insertAdjacentElement('afterend', clanActions);
}
}, 100);
}
// Observer to detect when the profile modal appears
const profileObserver = new MutationObserver(() => {
const modal = document.querySelector('.profile-modal_profile-modal__4mjE7');
if (modal && modal.offsetParent !== null) {
profileFix();
}
});
profileObserver.observe(document.body, {
childList: true,
subtree: true
});
// Extract logged-in username
function getLoggedInUsername() {
const userElement = document.querySelector('.top-bar-user_display-name__bzlpw');
return userElement ? userElement.textContent.trim() : null;
}
// Remove text-shadow and change font-weight for the logged-in user
function styleLoggedInUserMessages() {
const username = getLoggedInUsername();
if (!username) return;
const messages = document.querySelectorAll('.chat-message-default_user__uVNvH');
messages.forEach(message => {
if (message.textContent.includes(username)) {
const userElement = message;
if (userElement) {
userElement.style.textShadow = 'none';
userElement.style.fontWeight = '1000';
}
const messageTextElement = message.closest('.chat-message-default_chat-message-default__JtJQL').querySelector('.chat-message-default_body__iFlH4');
if (messageTextElement) {
messageTextElement.style.textShadow = 'none';
messageTextElement.style.fontWeight = '1000';
}
}
});
}
function addLinkButton(messageElement, url) {
// Safety check: don't add another button if one already exists for this URL
const existingButton = messageElement.querySelector(`.custom-link-button[href="${url}"]`);
if (existingButton) return; // Skip if button already exists for this URL
const button = document.createElement('a');
button.href = url.startsWith('http') ? url : 'https://' + url;
button.target = '_blank';
button.rel = 'noopener noreferrer';
button.className = 'custom-link-button';
button.style.marginLeft = '8px';
button.style.width = '20px';
button.style.height = '20px';
button.style.display = 'inline-flex';
button.style.alignItems = 'center';
button.style.justifyContent = 'center';
button.style.backgroundColor = '#4EA1FF';
button.style.color = 'white';
button.style.borderRadius = '4px';
button.style.fontSize = '14px';
button.style.textDecoration = 'none';
button.style.verticalAlign = 'middle';
button.textContent = '🔗';
// Insert the button at the end of the message content
const messageContent = messageElement.querySelector('.chat-message-default_message__milmT');
if (messageContent) {
messageContent.appendChild(button); // Append the button to the message
} else {
console.warn('Unable to insert button: No message content found.');
}
}
function detectLinksAndButton(messageElement) {
const contentElement = messageElement.querySelector('.chat-message-default_message__milmT');
if (!contentElement) return;
const textContent = contentElement.innerText || contentElement.textContent || '';
const urlRegex = /(\b(?:[a-zA-Z0-9-]+\.)+[a-zA-Z]{2,}(?:\/[^\s]*)?\b)/g; // global flag for multiple matches
const matches = textContent.match(urlRegex);
if (matches) {
// Loop through all the found URLs and add a button for each one
matches.forEach(url => {
addLinkButton(messageElement, url);
});
}
}
function observeMessages(chatContainer) {
const observer = new MutationObserver((mutationsList) => {
mutationsList.forEach(mutation => {
mutation.addedNodes.forEach(node => {
if (node.nodeType === 1 && node.classList.contains('chat-message-default_chat-message-default__JtJQL')) {
detectLinksAndButton(node);
}
});
});
});
observer.observe(chatContainer, {
childList: true,
subtree: true
});
}
function waitForChatContainer() {
const chatContainer = document.querySelector('.chat-messages_chat-messages__UeL0a');
if (chatContainer) {
observeMessages(chatContainer);
} else {
setTimeout(waitForChatContainer, 1000);
}
}
window.onload = function() {
waitForChatContainer();
};
let isElementVisible = false; // Track visibility state
// Function to change the medal size
function changeMedalSize(isVisible) {
const buttons = document.querySelectorAll('.medal_medal__Hqowf.medal_md__RvQMV button');
buttons.forEach(button => {
if (isVisible) {
button.style.setProperty('--medal-size', '32px');
} else {
button.style.setProperty('--medal-size', '64px');
}
});
}
// Function to check if the medal selector is visible so it can fix the sizing
function checkElement() {
const medalSelector = document.querySelector('.medal-selector_medals__sk3PN');
if (medalSelector) {
// Check if it's visible
const rect = medalSelector.getBoundingClientRect();
const isVisible = rect.width > 0 && rect.height > 0;
// Only change the size if visibility has changed
if (isVisible !== isElementVisible) {
isElementVisible = isVisible;
changeMedalSize(isElementVisible);
}
} else {
// If the selector disappears completely
if (isElementVisible) {
isElementVisible = false;
changeMedalSize(false);
}
}
}
// check every 100ms
setInterval(checkElement, 100);
// Highlight messages and add glowing username for the logged-in user
function highlightUserMessages() {
const username = getLoggedInUsername();
if (!username) return;
const messages = document.querySelectorAll('.chat-message-default_user__uVNvH');
messages.forEach(message => {
if (message.textContent.includes(username)) {
const chatMessage = message.closest('.chat-message-default_chat-message-default__JtJQL');
if (chatMessage && !chatMessage.classList.contains('highlighted-message')) {
chatMessage.classList.add('highlighted-message');
}
if (!message.classList.contains('glowing-username')) {
message.classList.add('glowing-username');
}
}
});
}
// Re-check messages every second and apply the styles
setInterval(() => {
highlightUserMessages();
styleLoggedInUserMessages();
}, 1000);
function createToggle() {
const userTab = document.querySelector('.top-bar_links__4FJwt');
if (!userTab) {
console.log("User tab not found, retrying...");
setTimeout(createToggle, 500); // Retry until it's available
return;
}
// Create a container for the toggle
const container = document.createElement('div');
container.style.display = 'flex';
container.style.alignItems = 'center';
container.style.gap = '5px';
container.style.marginTop = '10px';
// Create the checkbox
const checkbox = document.createElement('input');
checkbox.type = 'checkbox';
checkbox.id = 'stylingToggle';
checkbox.checked = true; // Checked by default
// Create the label
const label = document.createElement('label');
label.htmlFor = 'stylingToggle';
label.textContent = 'Styling';
label.style.color = 'white'; // or whatever color fits your site
// Append checkbox and label to the container
container.appendChild(checkbox);
container.appendChild(label);
// Append container to user tab
userTab.appendChild(container);
// Listen to checkbox changes
checkbox.addEventListener('change', function() {
if (this.checked) {
applyOptionalStyles();
} else {
removeOptionalStyles();
}
});
}
function applyOptionalStyles() {
if (document.getElementById('optionalStyles')) return;
const style = document.createElement('style');
style.id = 'optionalStyles';
style.textContent = `
/* This is for the site background */
body, .layout_layout__5rz87, .select_options__t1ibN {
background-image: url('https://images.gamebanana.com/img/ss/mods/5f681fd055666.jpg') !important;
background-size: cover !important;
background-position: center !important;
background-repeat: no-repeat !important;
}
/* This is for the chat background */
.chat_chat__2rdNg {
background-image: url('https://i.imgur.com/UVjYx1I.gif') !important;
background-size: cover !important;
background-position: center !important;
background-repeat: no-repeat !important;
}
/* Your text highlight color */
.highlighted-message {
background-color: rgba(125, 5, 5, 0.4) !important;
}
/* The color your name glows in chat */
.glowing-username {
-webkit-text-stroke: 1px rgba(0, 255, 0, 0.2);
filter: drop-shadow(0 0 1px #00ff00) drop-shadow(0 0 2px #00ff00);
}
/* Header Colors */
.maejok-input-invalid, .maejok-context-message, .maejok-tts-warning-text,
.chat_header__8kNPS, .top-bar_top-bar__X4p2n, .panel_body__O5yBA, .inventory_slots__D4IrC {
background-color: limegreen !important;
border-color: limegreen !important;
}
/* More header stuff */
.panel_header__T2yFW {
background-color: darkgreen !important;
}
/* Removing dropshadow on certain text to make it look nicer */
.top-bar_top-bar__X4p2n {
box-shadow: none !important;
}
.maejok-context-message svg path {
fill: black !important;
}
/* Video player Opacity */
.hls-stream-player_hls-stream-player__BJiGl, .live-stream-player_container__A4sNR, .layout_center__Vsd3b {
opacity: 1;
}
/* Makes the Ads go away! */
.ads_ads__Z1cPk {
opacity: 0;
}
/* Poll bottom color aka the part next to the vote button */
.poll_footer__rALdX {
background-color: limegreen;
}
/* Poll Vote Button Disabled */
.poll_vote__b_NE0 button:disabled:hover {
background-color: red !important;
color: white !important;
border-color: black !important;
}
/* Poll Vote Button Enabled */
.poll_vote__b_NE0 button:hover {
background-color: red !important;
color: white !important;
border-color: black !important;
}
/* TTS & SFX Chat Messages */
.chat-message-tts_chat-message-tts__2Jlxi, .chat-message-sfx_chat-message-sfx__OGv6q {
border-color: #00ff00 !important;
background-color: darkgreen !important;
filter: drop-shadow(0 0 2px #00ff00) drop-shadow(0 0 2px #00ff00);
}
/* Interior Text for TTS & SFX, Currently Glows */
.chat-message-tts_message__sWVCc, .chat-message-sfx_message__d2Rei {
-webkit-text-stroke: 2px rgba(0, 255, 0, 0.6);
filter: drop-shadow(0 0 2px #00ff00) drop-shadow(0 0 2px #00ff00);
}
/* TTS & SFX Footer Timestamp */
.chat-message-tts_timestamp__pIVv0, .chat-message-sfx_timestamp__ilYfg {
color: black !important;
font-weight: bold !important;
text-shadow: none !important;
}
`;
document.head.appendChild(style);
}
function removeOptionalStyles() {
const style = document.getElementById('optionalStyles');
if (style) {
style.remove();
}
}
createToggle();
applyOptionalStyles();
// Custom style for the user's messages
GM_addStyle(`
/* IMPORTANT: THIS IS EVERY MODAL. DONT TOUCH THE SIZE OR ALIGNMENT */
.modal_modal__MS70U {
height:1000px !important;
width: 1500px !important;
align-self: anchor-center !important;
justify-self: anchor-center !important;
overflow: scroll !important;
background-color: #191d21bb !important; /* The last two characters are hex code for opacity. 00 for 0%, ff for 100% */
}
/* Modal Dim Background, 0% Opacity means no dimming */
.modal_backdrop__94Bu6 {
opacity: 0;
}
/* FULL SCREEN SETTINGS MENU & ITEM DEX DO NOT TOUCH */
.settings-modal_body__qdvDm, .profile-modal_profile-modal__4mjE7 {
display: flex;
flex-direction: column;
gap: 8px;
align-items: center;
margin: auto;
width: 100%;
padding: 16px;
background-color: rgba(0, 0, 0, .25);
border: 1px solid #505050;
border-radius: 4px;
}
/* FULL SCREEN SETTINGS MENU & ITEM DEX DO NOT TOUCH */
.user-profile-tabs_tab__2bsiR {
display: flex;
flex-wrap: wrap;
background-color: rgba(0, 0, 0, .5);
padding: 8px;
border: 1px solid #505050;
border-bottom-left-radius: 4px;
border-bottom-right-radius: 4px;
border-top: 0;
gap: 4px;
width: 1400px;
height: 900px;
justify-self: center;
}
/* FULL SCREEN SETTINGS MENU & ITEM DEX DO NOT TOUCH */
.user-profile-items_user-profile-items__rl_CV {
display: flex;
width: 1400px;
height: 900px;
}
/* FULL SCREEN SETTINGS MENU & ITEM DEX DO NOT TOUCH */
.user-profile-items_items__zuulV {
display: flex;
flex-wrap: wrap;
gap: 4px;
padding: 8px;
width: 100%;
height: 100%;
justify-content: space-evenly;
max-height: 900px !important;
}
.user-profile-tts-sfx_messages__w4_Ew {
max-height: 93vh !important; /* DO NOT TOUCH UNLESS YOU WANT YOUR SFX AND TTS HISTORY WINDOW BROKEN */
}
.user-profile_profile__g_tBc {
width: 1400px !important; /* DO NOT TOUCH UNLESS YOU WANT YOUR PROFILE AND/OR SETTINGS WINDOWS BROKEN */
max-width: 1400px !important; /* DO NOT TOUCH UNLESS YOU WANT YOUR PROFILE AND/OR SETTINGS WINDOWS BROKEN */
}
.user-profile_body__hk8ZS {
width: 1400px; /* DO NOT TOUCH UNLESS YOU WANT YOUR PROFILE AND/OR SETTINGS WINDOWS BROKEN */
align-content: center; /* DO NOT TOUCH UNLESS YOU WANT YOUR PROFILE AND/OR SETTINGS WINDOWS BROKEN */
}
.profile-modal_profile-modal__4mjE7 {
align-items: unset; /* DO NOT TOUCH UNLESS YOU WANT YOUR PROFILE AND/OR SETTINGS WINDOWS BROKEN */
}
.user-profile_bio__nzdwR {
padding-left: 80px; /* DO NOT TOUCH UNLESS YOU WANT YOUR PROFILE AND/OR SETTINGS WINDOWS BROKEN */
width: 1000px; /* DO NOT TOUCH UNLESS YOU WANT YOUR PROFILE AND/OR SETTINGS WINDOWS BROKEN */
}
.input_input__Zwrui textarea {
height: 100px; /* DO NOT TOUCH UNLESS YOU WANT YOUR PROFILE AND/OR SETTINGS WINDOWS BROKEN */
}
.user-profile_header__zP1kv {
width: 1400px; /* DO NOT TOUCH UNLESS YOU WANT YOUR PROFILE AND/OR SETTINGS WINDOWS BROKEN */
}
.medal_medal__Hqowf.medal_md__RvQMV button {
--medal-size: 64px; /* DO NOT TOUCH UNLESS YOU WANT YOUR PROFILE AND/OR SETTINGS WINDOWS BROKEN */
}
.user-update-profile_actions__vbfIX button {
width: 800px; /* DO NOT TOUCH UNLESS YOU WANT YOUR PROFILE AND/OR SETTINGS WINDOWS BROKEN */
}
.user-update-profile_user-update-profile__sa20I {
width: 1400px; /* DO NOT TOUCH UNLESS YOU WANT YOUR PROFILE AND/OR SETTINGS WINDOWS BROKEN */
}
.user-update-profile_details__7bBRy {
width: 350px; /* DO NOT TOUCH UNLESS YOU WANT YOUR PROFILE AND/OR SETTINGS WINDOWS BROKEN */
}
.user-update-profile_bio__DaV4N {
width: 800px; /* DO NOT TOUCH UNLESS YOU WANT YOUR PROFILE AND/OR SETTINGS WINDOWS BROKEN */
justify-self: flex-end; /* DO NOT TOUCH UNLESS YOU WANT YOUR PROFILE AND/OR SETTINGS WINDOWS BROKEN */
height: 200px; /* DO NOT TOUCH UNLESS YOU WANT YOUR PROFILE AND/OR SETTINGS WINDOWS BROKEN */
}
.modal_body__j3Bav {
align-self: anchor-center;
height:100%;
overflow: visible !important;
}
.modal_header__O0ebJ {
padding-top:50px;
font-size:xxx-large;
}
.item-generator-modal_items__Xs78_, .item-generator-modal_generator__vmam0 {
background-color: rgba(14, 16, 18, 1) !important;
}
.logs_logs__YL0uF {
width: 1400px;
align-self: center;
}
.logs_body__lqe_U {
height: 700px !important;
}
.logs_message__p9V2r {
font-size: medium;
}
.sfx-modal_sfx-modal__i_ppy, .tts-modal_tts-modal__rxY0z {
width: 1200px;
padding-top: 150px;
}
.select_value__yPLpn {
background-color: rgba(43, 45, 46, 1) !important;
}
.input_input-wrapper__xvMLO input{
background-color: rgba(43, 45, 46, 1) !important;
}
.user-update-profile_user-update-profile__sa20I .user-update-profile_bio__DaV4N {
grid-column: 1 / 3;
grid-row: 1 / 4;
}
.input_input-wrapper__xvMLO textarea {
height: 165px;
}
.user-update-profile_footer__kONMY {
grid-row: 2 / 6 !important;
height:60px;
}
.user-profile-tabs_user-profile-tabs__7SFh7 {
padding-top: 75px;
}
`);
})();