Idle Pixel Audio Alerts

Audio Alerts for DHP

当前为 2023-12-12 提交的版本,查看 最新版本

// ==UserScript==
// @name         Idle Pixel Audio Alerts
// @namespace    http://tampermonkey.net/
// @version      1.0.0
// @description  Audio Alerts for DHP
// @author       Felipe Dounford
// @require      https://gf.qytechs.cn/scripts/461221-hack-timer-js-by-turuslan/code/Hack%20Timerjs%20By%20Turuslan.js?version=1159560
// @require      https://gf.qytechs.cn/scripts/441206-idlepixel/code/IdlePixel+.js
// @match        *://idle-pixel.com/login/play*
// @icon         https://www.google.com/s2/favicons?sz=64&domain=gf.qytechs.cn
// @grant        none
// @license      MIT
// ==/UserScript==

(function() {
    'use strict';

	//Change ding url to set default sound
	let ding = 'https://raw.githubusercontent.com/Dounford-Felipe/Audio-Alerts/main/ding.wav'
	//Change defaultText to set default TTS Text
	let defaultText = 'Ready'
	let alerts = [];
	window.muteAllAlerts = false;
	window.alertVolume = 1;
	window.alertVoices = [];
	window.alertVoice = '';

    class AlertsPlugin extends IdlePixelPlusPlugin {
        constructor() {
            super("alerts", {
                about: {
                    name: GM_info.script.name + " (ver: " + GM_info.script.version + ")",
                    version: GM_info.script.version,
                    author: GM_info.script.author,
                    description: GM_info.script.description
                }
            });
        }
 
        onLogin() {
			IdlePixelPlus.plugins.alerts.addUI()
			IdlePixelPlus.plugins.alerts.loadAlerts()
			speechSynthesis.onvoiceschanged = function () {
				IdlePixelPlus.plugins.alerts.getVoices()
			}
			const alertLoopInterval = setInterval(function(){
				IdlePixelPlus.plugins.alerts.newValue()
				IdlePixelPlus.plugins.alerts.alertLoop()
			}, 1000);
        }
    
		//Gets the tts voices, populate the select with them and set the current voice
		getVoices() {
			alertVoices = speechSynthesis.getVoices();
			const voiceSelect = document.getElementById('ttsVoices');
			alertVoices.forEach((voice, index) => {
				const option = document.createElement('option');
				option.value = index;
				option.textContent = voice.name;
				voiceSelect.appendChild(option);
			});
			// Set the current voice based on the value stored in localStorage or use the first voice
			alertVoice = localStorage.getItem('audioAlertsVoice') ? alertVoices[localStorage.getItem('audioAlertsVoice')] : alertVoices[0]
			document.getElementById('ttsVoices').value = localStorage.getItem('audioAlertsVoice') ? localStorage.getItem('audioAlertsVoice') : 0
		}

		//Adds the table and Style
		addUI() {
			let alertTable = `<table border="1" cellpadding="1" cellspacing="1" style="text-align: center;color: white;font-weight: bold;text-shadow: 1px 1px black;">
				<thead>
					<tr>
						<th style="width: 30%;">Variable</th>
						<th style="width: 10%;" colspan="2">Trigger</th>
						<th style="width: 10%;">Current Value</th>
						<th style="width: 10%;">Sound Type</th>
						<th style="width: 20%;">Option</th>
						<th style="width: 10%;">Enabled</th>
						<th></th>
					</tr>
				</thead>
				<tbody id="alertsBody">
				</tbody>
				<tfoot>
					<tr id="alertsFooter">
						<td colspan="3">
							<select id="ttsVoices" onchange="alertVoice = alertVoices[this.value]" style="width:100%"></select>
						</td>
						<td colspan="2">
							<input type="checkbox" onclick="muteAllAlerts = !muteAllAlerts" style="margin-right: 10px;"> Mute ALL
						</td>
						<td>
							<input type="range" min="1" max="100" value="100" id="alertVolume" onchange="alertVolume = this.value"> Volume
						</td>
						<td>
							<button onclick="IdlePixelPlus.plugins.alerts.saveAlerts()">Save</button>
						</td>
						<td>
							<button onclick="IdlePixelPlus.plugins.alerts.addAlert()">ADD</button>
						</td>
					</tr>
				</tfoot>
			</table>`
			IdlePixelPlus.addPanel("audioAlerts", "Audio Alerts", alertTable);
			
			let alertButton = `<div onclick="IdlePixelPlus.setPanel('audioAlerts')" class="hover hover-menu-bar-item">
                <img src="https://dhm.idle-pixel.com/images/soundOn.png" style="width: 20px;"> AUDIO ALERTS
            </div>`
			$('#menu-bar-buttons').append(alertButton)
		}

		//Adds new alert row and a new key to alerts array
		addAlert = function() {
			let alertRows = document.getElementById('alertsBody').getElementsByTagName("tr")
			let totalAlerts = alertRows.length
			let alertRow = document.createElement('tr')
			alertRow.id = `alert${totalAlerts+1}`
			alertRow.innerHTML = `<td>
						<input placeholder="Variable Name" id="variableName${totalAlerts+1}" style="width:100%">
					</td>
					<td>
						<select id="variableType${totalAlerts+1}">
							<option value="lt">&lt;</option>
							<option value="le">&le;</option>
							<option value="gt">&gt;</option>
							<option value="ge">&ge;</option>
							<option value="eq">&equals;</option>
							<option value="ne">&ne;</option>
						</select>
					</td>
					<td>
						<input placeholder="Value to Trigger" type="number" id="wantedValue${totalAlerts+1}">
					</td>
					<td><span id="variableValue"></span></td>
					<td>
						<select id="audioType${totalAlerts+1}">
							<option value="audio" selected="">Audio File</option>
							<option value="tts">Text To Speech</option>
							<option value="eval">Eval (Advanced Users Only!)</option>
						</select>
					</td>
					<td>
						<input placeholder="Text to Speech or sound URL" id="soundOption${totalAlerts+1}">
					</td>
					<td>
						<input type="checkbox" id="enabled${totalAlerts+1}">
					</td>
					<td style="padding-right: 6px;">
						<button onclick="IdlePixelPlus.plugins.alerts.removeAlert(this.parentNode.parentNode)">Delete</button>
					</td>`
			document.getElementById('alertsBody').append(alertRow)
			alerts[totalAlerts] = {type:'lt',variableName:'',wantedValue:'',soundType:'audio',sound:ding,enabled:false,triggered:false}
		}

		//Remove alert row and the array key, also changes the id of the remaining rows
		removeAlert = function(row) {
			let id = row.id.slice(5)
			alerts.splice(id-1,1)
			row.remove()
			let alertRows = document.getElementById('alertsBody').getElementsByTagName("tr")
			// Update remaining row IDs
			for (let i = 0; i < alertRows.length; i++) {alertRows[i].id = `alert${i+1}`}
			// Add a new alert if there are no rows remaining
			if (alertRows.length == 0) {IdlePixelPlus.plugins.alerts.addAlert()}
		}

		//Save the alerts, also sets the alerts, volume and current voice on localStorage
		saveAlerts = function() {
			let alertRows = document.getElementById('alertsBody').getElementsByTagName("tr")
			for (let i = 0; i < alertRows.length; i++) {
				alerts[i].type = alertRows[i].getElementsByTagName('select')[0].value
				alerts[i].variableName = 'var_' + alertRows[i].getElementsByTagName('input')[0].value
				alerts[i].wantedValue = alertRows[i].getElementsByTagName('input')[1].value
				alerts[i].soundType = alertRows[i].getElementsByTagName('select')[1].value
				alerts[i].sound = alertRows[i].getElementsByTagName('input')[2].value == '' ? ding : alertRows[i].getElementsByTagName('input')[2].value
				alerts[i].enabled = alertRows[i].getElementsByTagName("input")[3].checked
				alerts[i].triggered = false
			}
			let key = `audioAlerts`;
			localStorage.setItem(key, JSON.stringify(alerts));
			localStorage.setItem('audioAlertsVolume', alertVolume);
			let voiceIndex = document.getElementById('ttsVoices').value
			localStorage.setItem('audioAlertsVoice', voiceIndex);
		}

		//Loads both volume and alerts from the localStorage
		loadAlerts() {
			let key = `audioAlerts`;
			let audioAlerts = localStorage.getItem(key);
			if (audioAlerts) {
				audioAlerts = JSON.parse(audioAlerts);
				let alertRows = document.getElementById('alertsBody').getElementsByTagName("tr")
				for (let i = 0; i < audioAlerts.length; i++) {
					IdlePixelPlus.plugins.alerts.addAlert()
					alertRows[i].getElementsByTagName('select')[0].value = audioAlerts[i].type
					alertRows[i].getElementsByTagName('input')[0].value = audioAlerts[i].variableName.slice(4)
					alertRows[i].getElementsByTagName('input')[1].value = audioAlerts[i].wantedValue
					alertRows[i].getElementsByTagName('select')[1].value = audioAlerts[i].soundType
					alertRows[i].getElementsByTagName('input')[3].checked = audioAlerts[i].enabled
					alertRows[i].getElementsByTagName('input')[2].value = audioAlerts[i].sound == ding ? '' : audioAlerts[i].sound;
				}
				alerts = audioAlerts;
			} else {IdlePixelPlus.plugins.alerts.addAlert()}
			alertVolume = localStorage.getItem('audioAlertsVolume') ? localStorage.getItem('audioAlertsVolume') : 100;
			document.getElementById('alertVolume').value = alertVolume
		}

		//Displays the current value of the alert variables
		newValue() {
			let alertRows = document.getElementById('alertsBody').getElementsByTagName("tr")
			for (let i = 0; i < alertRows.length; i++) {
				alertRows[i].getElementsByTagName('span')[0].innerText = window[alerts[i].variableName] == undefined ? '' : window[alerts[i].variableName]
			}
		}

		//This is were the alert happen
		alertLoop() {
			for (let i = 0; i < alerts.length; i++) {
				if (alerts[i].enabled) {
					let type = alerts[i].type
					let triggered = 0
					switch(type) {
						case "lt": {
							triggered =  window[alerts[i].variableName] < alerts[i].wantedValue ? 1 : 0
							break;
						}
						case "le": {
							triggered =  window[alerts[i].variableName] <= alerts[i].wantedValue ? 1 : 0
							break;
						}
						case "gt": {
							triggered =  window[alerts[i].variableName] > alerts[i].wantedValue ? 1 : 0
							break;
						}
						case "ge": {
							triggered =  window[alerts[i].variableName] >= alerts[i].wantedValue ? 1 : 0
							break;
						}
						case "eq": {
							triggered =  window[alerts[i].variableName] == alerts[i].wantedValue ? 1 : 0
							break;
						}
						case "ne": {
							triggered =  window[alerts[i].variableName] != alerts[i].wantedValue && typeof window[alerts[i].variableName] != 'undefined' ? 1 : 0
							break;
						}
					}
					if (triggered == 1 && alerts[i].triggered == false) {
						alerts[i].triggered = true
						if (muteAllAlerts != true) {
							if(alerts[i].soundType == "audio") {
								let sound = new Audio(alerts[i].sound)
								sound = isNaN(sound.duration) ? new Audio(ding) : sound
								sound.volume = alertVolume / 100
								sound.play()
							} else if (alerts[i].soundType == "tts") {
								const message = new SpeechSynthesisUtterance();
								message.text = alerts[i].sound == ding ? defaultText : alerts[i].sound
								message.voice = alertVoice
								message.volume = alertVolume / 100
								window.speechSynthesis.speak(message);
							} else if (alerts[i].soundType == "eval") {// Remove from here
								let command = alerts[i].sound == 'https://raw.githubusercontent.com/Dounford-Felipe/Audio-Alerts/main/ding.wav' ? `console.log('You need to set ' + alerts[i].variableName + ' command')` : alerts[i].sound
								eval(command) // To here if you don't want eval
							}
						}
					} 
					if (triggered == 0) {
						alerts[i].triggered = false
					}
				}
			}
		}
	
	}
 
    const plugin = new AlertsPlugin();
    IdlePixelPlus.registerPlugin(plugin);
 
})();

QingJ © 2025

镜像随时可能失效,请加Q群300939539或关注我们的公众号极客氢云获取最新地址