Idle Pixel Audio Alerts

Audio Alerts for DHP

目前為 2023-12-18 提交的版本,檢視 最新版本

您需要先安裝使用者腳本管理器擴展,如 TampermonkeyGreasemonkeyViolentmonkey 之後才能安裝該腳本。

You will need to install an extension such as Tampermonkey to install this script.

您需要先安裝使用者腳本管理器擴充功能,如 TampermonkeyViolentmonkey 後才能安裝該腳本。

您需要先安裝使用者腳本管理器擴充功能,如 TampermonkeyUserscripts 後才能安裝該腳本。

你需要先安裝一款使用者腳本管理器擴展,比如 Tampermonkey,才能安裝此腳本

您需要先安裝使用者腳本管理器擴充功能後才能安裝該腳本。

(我已經安裝了使用者腳本管理器,讓我安裝!)

你需要先安裝一款使用者樣式管理器擴展,比如 Stylus,才能安裝此樣式

你需要先安裝一款使用者樣式管理器擴展,比如 Stylus,才能安裝此樣式

你需要先安裝一款使用者樣式管理器擴展,比如 Stylus,才能安裝此樣式

你需要先安裝一款使用者樣式管理器擴展後才能安裝此樣式

你需要先安裝一款使用者樣式管理器擴展後才能安裝此樣式

你需要先安裝一款使用者樣式管理器擴展後才能安裝此樣式

(我已經安裝了使用者樣式管理器,讓我安裝!)

// ==UserScript==
// @name         Idle Pixel Audio Alerts
// @namespace    http://tampermonkey.net/
// @version      1.0.1
// @description  Audio Alerts for DHP
// @author       Felipe Dounford
// @require      https://greasyfork.org/scripts/461221-hack-timer-js-by-turuslan/code/Hack%20Timerjs%20By%20Turuslan.js?version=1159560
// @require      https://greasyfork.org/scripts/441206-idlepixel/code/IdlePixel+.js
// @match        *://idle-pixel.com/login/play*
// @icon         https://www.google.com/s2/favicons?sz=64&domain=greasyfork.org
// @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 left-menu-item">
				<table class="game-menu-bar-left-table-btn left-menu-item-other" style="width: 100%;">
					<tbody>
						<tr>
							<td style="width: 30px;"><img id="menu-bar-idlepixelplus-icon" src="https://dhm.idle-pixel.com/images/soundOn.png" class="w20" title="alerts"></td>
							<td>AUDIO ALERTS</td>
						</tr>
					</tbody>
				</table>
			</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);
 
})();