- // ==UserScript==
- // @name MIDI Player Bot
- // @namespace https://thealiendrew.github.io/
- // @version 2.5.3
- // @description Plays MIDI files!
- // @author AlienDrew
- // @license GPL-3.0-or-later
- // @match *://multiplayerpiano.com/*
- // @match *://mppclone.com/*
- // @match *://mpp.terrium.net/*
- // @match *://piano.ourworldofpixels.com/*
- // @match *://multiplayerpiano.net/*
- // @icon https://raw.githubusercontent.com/TheAlienDrew/Tampermonkey-Scripts/master/Multiplayer%20Piano/MPP-MIDI-Player-Bot/favicon.png
- // @grant GM_info
- // @grant GM_getResourceText
- // @grant GM_getResourceURL
- // @resource MIDIPlayerJS https://raw.githubusercontent.com/grimmdude/MidiPlayerJS/master/browser/midiplayer.js
- // @run-at document-end
- // ==/UserScript==
-
- /* Copyright (C) 2020 Andrew Larson (thealiendrew@gmail.com)
- * This program is free software: you can redistribute it and/or modify
- * it under the terms of the GNU General Public License as published by
- * the Free Software Foundation, either version 3 of the License, or
- * (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- * GNU General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License
- * along with this program. If not, see <https://www.gnu.org/licenses/>.
- */
-
- /* globals MPP, MidiPlayer */
-
- // =============================================== FILES
-
- // midiplayer.js via https://github.com/grimmdude/MidiPlayerJS
- // (but I should maybe switch to https://github.com/mudcube/MIDI.js OR https://github.com/Tonejs/Midi)
- var stringMIDIPlayerJS = GM_getResourceText("MIDIPlayerJS");
- var scriptMIDIPlayerJS = document.createElement("script");
- scriptMIDIPlayerJS.type = 'text/javascript';
- scriptMIDIPlayerJS.appendChild(document.createTextNode(stringMIDIPlayerJS));
- (document.body || document.head || document.documentElement).appendChild(scriptMIDIPlayerJS);
-
- // =============================================== CONSTANTS
-
- // Script constants
- const SCRIPT = GM_info.script;
- const NAME = SCRIPT.name;
- const NAMESPACE = SCRIPT.namespace;
- const VERSION = SCRIPT.version;
- const DESCRIPTION = SCRIPT.description;
- const AUTHOR = SCRIPT.author;
- const DOWNLOAD_URL = SCRIPT.downloadURL;
-
- // Time constants (in milliseconds)
- const TENTH_OF_SECOND = 100; // mainly for repeating loops
- const SECOND = 10 * TENTH_OF_SECOND;
- const CHAT_DELAY = 5 * TENTH_OF_SECOND; // needed since the chat is limited to 10 messages within less delay
- const SLOW_CHAT_DELAY = 2 * SECOND // when you are not the owner, your chat quota is lowered
- const REPEAT_DELAY = 2 * TENTH_OF_SECOND; // makes transitioning songs in repeat feel better
- const SONG_NAME_TIMEOUT = 10 * SECOND; // if a file doesn't play, then forget about showing the song name it after this time
-
- // URLs
- const FEEDBACK_URL = "https://forms.gle/x4nqjynmRMEN2GSG7";
-
- // Players listed by IDs (these are the _id strings)
- const BANNED_PLAYERS = []; // empty for now
- const LIMITED_PLAYERS = ["8c81505ab941e0760697d777"];
-
- // Bot constants
- const CHAT_MAX_CHARS = 512; // there is a limit of this amount of characters for each message sent (DON'T CHANGE)
- const PERCUSSION_CHANNEL = 10; // (DON'T CHANGE)
- const MPP_ROOM_SETTINGS_ID = "room-settings-btn"; // (DON'T CHANGE)
- const MIDI_FILE_SIZE_LIMIT_BYTES = 5242880; // Maximum is roughly somewhere around 150 MB, but only black midi's get to that point
-
- // Bot constant settings
- const ALLOW_ALL_INTRUMENTS = false; // removes percussion instruments (turning this on makes a lot of MIDIs sound bad)
- const BOT_SOLO_PLAY = true; // sets what play mode when the bot boots up on an owned room
-
- // Bot custom constants
- const PREFIX = "/";
- const PREFIX_LENGTH = PREFIX.length;
- const BOT_KEYWORD = "MIDI"; // this is used for auto enabling the public commands in a room that contains the keyword (character case doesn't matter)
- const BOT_ACTIVATOR = BOT_KEYWORD.toLowerCase();
- const BOT_USERNAME = NAME + " [" + PREFIX + "help]";
- const BOT_NAMESPACE = '(' + NAMESPACE + ')';
- const BOT_DESCRIPTION = DESCRIPTION + " Made with JS via Tampermonkey, and thanks to grimmdude for the MIDIPlayerJS library."
- const BOT_AUTHOR = "Created by " + AUTHOR + '.';
- const BASE_COMMANDS = [
- ["help (command)", "displays info about command, but no command entered shows the commands"],
- ["about", "get information about this bot"],
- ["link", "get the download link for this bot"],
- ["feedback", "shows link to send feedback about the bot to the developer"],
- ["ping", "gets the milliseconds response time"]
- ];
- const BOT_COMMANDS = [
- ["play [MIDI URL]", "plays a specific song (URL must be a direct link to a MIDI file)"],
- ["stop", "stops all music from playing"],
- ["pause", "pauses the music at that moment in the song"],
- ["resume", "plays music right where pause left off"],
- ["song", "shows the current song playing and at what moment in time"],
- ["repeat", "toggles repeating current song on or off"],
- ["sustain", "toggles how sustain is controlled via either MIDI or by MPP"]
- ];
- const BOT_OWNER_COMMANDS = [
- ["loading", "toggles the MIDI loading progress audio, or text, on or off"],
- [BOT_ACTIVATOR, "toggles the public bot commands on or off"]
- ];
- const PRE_MSG = NAME + " (v" + VERSION + "): ";
- const PRE_HELP = PRE_MSG + "[Help]";
- const PRE_ABOUT = PRE_MSG + "[About]";
- const PRE_LINK = PRE_MSG + "[Link]";
- const PRE_FEEDBACK = PRE_MSG + "[Feedback]";
- const PRE_PING = PRE_MSG + "[Ping]";
- const PRE_PLAY = PRE_MSG + "[Play]";
- const PRE_STOP = PRE_MSG + "[Stop]";
- const PRE_PAUSE = PRE_MSG + "[Pause]";
- const PRE_RESUME = PRE_MSG + "[Resume]";
- const PRE_SONG = PRE_MSG + "[Song]";
- const PRE_REPEAT = PRE_MSG + "[Repeat]";
- const PRE_SUSTAIN = PRE_MSG + "[Sustain]";
- const PRE_DOWNLOADING = PRE_MSG + "[Downloading]";
- const PRE_LOAD_MUSIC = PRE_MSG + "[Load Music]";
- const PRE_PUBLIC = PRE_MSG + "[Public]";
- const PRE_LIMITED = PRE_MSG + "Limited!";
- const PRE_ERROR = PRE_MSG + "Error!";
- const WHERE_TO_FIND_MIDIS = "You can find some good MIDIs to upload from https://bitmidi.com/ and https://midiworld.com/, or you can use your own MIDI files via Google Drive/Dropbox/etc. with a direct download link";
- const NOT_OWNER = "The bot isn't the owner of the room";
- const NO_SONG = "Not currently playing anything";
- const LIST_BULLET = "• ";
- const DESCRIPTION_SEPARATOR = " - ";
- const CONSOLE_IMPORTANT_STYLE = "background-color: red; color: white; font-weight: bold";
-
- // Element constants
- const CSS_VARIABLE_X_DISPLACEMENT = "--xDisplacement";
- const PRE_ELEMENT_ID = "aliendrew-midi-player-bot";
- // buttons have some constant styles/classes
- const ELEM_ON = "display:block;";
- const ELEM_OFF = "display:none;";
- const ELEM_POS = "position:absolute;";
- const BTN_PAD_LEFT = 8; // pixels
- const BTN_PAD_TOP = 4; // pixels
- const BTN_WIDTH = 112; // pixels
- const BTN_HEIGHT = 24; // pixels
- const BTN_SPACER_X = BTN_PAD_LEFT + BTN_WIDTH; //pixels
- const BTN_SPACER_Y = BTN_PAD_TOP + BTN_HEIGHT; //pixels
- const BTNS_START_X = 300; //pixels
- const BTNS_END_X = BTNS_START_X + 4 * BTN_SPACER_X; //pixels
- const BTNS_TOP_0 = BTN_PAD_TOP; //pixels
- const BTNS_TOP_1 = BTN_PAD_TOP + BTN_SPACER_Y; //pixels
- const BTN_STYLE = ELEM_POS + ELEM_OFF;
-
- // Gets the correct note from MIDIPlayer to play on MPP
- const MIDIPlayerToMPPNote = {
- "A0": "a-1",
- "Bb0": "as-1",
- "B0": "b-1",
- "C1": "c0",
- "Db1": "cs0",
- "D1": "d0",
- "Eb1": "ds0",
- "E1": "e0",
- "F1": "f0",
- "Gb1": "fs0",
- "G1": "g0",
- "Ab1": "gs0",
- "A1": "a0",
- "Bb1": "as0",
- "B1": "b0",
- "C2": "c1",
- "Db2": "cs1",
- "D2": "d1",
- "Eb2": "ds1",
- "E2": "e1",
- "F2": "f1",
- "Gb2": "fs1",
- "G2": "g1",
- "Ab2": "gs1",
- "A2": "a1",
- "Bb2": "as1",
- "B2": "b1",
- "C3": "c2",
- "Db3": "cs2",
- "D3": "d2",
- "Eb3": "ds2",
- "E3": "e2",
- "F3": "f2",
- "Gb3": "fs2",
- "G3": "g2",
- "Ab3": "gs2",
- "A3": "a2",
- "Bb3": "as2",
- "B3": "b2",
- "C4": "c3",
- "Db4": "cs3",
- "D4": "d3",
- "Eb4": "ds3",
- "E4": "e3",
- "F4": "f3",
- "Gb4": "fs3",
- "G4": "g3",
- "Ab4": "gs3",
- "A4": "a3",
- "Bb4": "as3",
- "B4": "b3",
- "C5": "c4",
- "Db5": "cs4",
- "D5": "d4",
- "Eb5": "ds4",
- "E5": "e4",
- "F5": "f4",
- "Gb5": "fs4",
- "G5": "g4",
- "Ab5": "gs4",
- "A5": "a4",
- "Bb5": "as4",
- "B5": "b4",
- "C6": "c5",
- "Db6": "cs5",
- "D6": "d5",
- "Eb6": "ds5",
- "E6": "e5",
- "F6": "f5",
- "Gb6": "fs5",
- "G6": "g5",
- "Ab6": "gs5",
- "A6": "a5",
- "Bb6": "as5",
- "B6": "b5",
- "C7": "c6",
- "Db7": "cs6",
- "D7": "d6",
- "Eb7": "ds6",
- "E7": "e6",
- "F7": "f6",
- "Gb7": "fs6",
- "G7": "g6",
- "Ab7": "gs6",
- "A7": "a6",
- "Bb7": "as6",
- "B7": "b6",
- "C8": "c7"
- }
-
- // =============================================== VARIABLES
-
- var publicOption = false; // turn off the public bot commands if needed
- var pinging = false; // helps aid in getting response time
- var pingTime = 0; // changes after each ping
- var currentRoom = null; // updates when it connects to room
- var chatDelay = CHAT_DELAY; // for how long to wait until posting another message
- var endDelay; // used in multiline chats send commands
-
- var loadingOption = false; // controls if loading music should be on or not
- var loadingProgress = 0; // updates when loading files
- var loadingMusicLoop = null; // this is to play notes while a song is (down)loading
- var loadingMusicPrematureStop = false; // this is used when we need to stop the music after errors
- var ended = true;
- var stopped = false;
- var paused = false;
- var uploadButton = null; // this gets an element after it's loaded
- var currentSongElapsedFormatted = "00:00"; // changes with the amount of song being played
- var currentSongDurationFormatted = "00:00"; // gets updated when currentSongDuration is updated
- var currentSongDuration = 0; // this changes after each song is loaded
- var currentSongData = null; // this contains the song as a data URI
- var currentFileLocation = null; // this leads to the MIDI location (local or by URL)
- var currentSongName = null; // extracted from the file name/end of URL
- var previousSongData = null; // grabs current when changing successfully
- var previousSongName = null; // grabs current when changing successfully
- var repeatOption = false; // allows for repeat of one song
- var sustainOption = true; // makes notes end according to the midi file
-
- var mppRoomSettingsBtn = null; // tracks "Room Settings" element
- var xDisplacement = ""; // tracks xDisplacement value from CSS variables
-
- // =============================================== PAGE VISIBILITY
-
- var pageVisible = true;
- document.addEventListener('visibilitychange', function () {
- if (document.hidden) {
- pageVisible = false;
- } else {
- pageVisible = true;
- }
- });
-
- // =============================================== OBJECTS
-
- // The MIDIPlayer
- var Player = new MidiPlayer.Player(function(event) {
- if (MPP.client.preventsPlaying()) {
- if (Player.isPlaying()) pause();
- return;
- }
- var currentEvent = event.name;
- if (!exists(currentEvent) || currentEvent == "") return;
- if (currentEvent.indexOf("Note") == 0 && (ALLOW_ALL_INTRUMENTS || event.channel != PERCUSSION_CHANNEL)) {
- var currentNote = (exists(event.noteName) ? MIDIPlayerToMPPNote[event.noteName] : null);
- if (currentEvent == "Note on" && event.velocity > 0) { // start note
- MPP.press(currentNote, (event.velocity/100));
- if (!sustainOption) MPP.release(currentNote);
- } else if (sustainOption && (currentEvent == "Note off" || event.velocity == 0)) MPP.release(currentNote); // end note
- }
- if (!ended && !Player.isPlaying()) {
- ended = true;
- paused = false;
- if (!repeatOption) {
- currentSongData = null;
- currentSongName = null;
- }
- } else {
- var timeRemaining = Player.getSongTimeRemaining();
- var timeElapsed = currentSongDuration - (timeRemaining > 0 ? timeRemaining : 0);
- // BELOW TEMP: helps mitigate duration calculation issue, but still not fully fixed, see https://github.com/grimmdude/MidiPlayerJS/issues/64
- currentSongDuration = Player.getSongTime();
- currentSongDurationFormatted = timeClearZeros(secondsToHms(currentSongDuration));
- // ABOVE TEMP
- currentSongElapsedFormatted = timeSizeFormat(secondsToHms(timeElapsed), currentSongDurationFormatted);
- }
- });
- // see https://github.com/grimmdude/MidiPlayerJS/issues/25
- Player.sampleRate = 0; // this allows sequential notes that are supposed to play at the same time, do so when using fast MIDIs (e.g. some black MIDIs)
-
- // =============================================== FUNCTIONS
-
- // CORS Anywhere (allows downloading files where JS can't)
- var useCorsUrl = function(url) {
- var newUrl = null; // send null back if it's already a cors url
- var cors_api_url = 'https://cors-proxy.htmldriven.com/?url=';
- // prevents cors-anywhere-ifing a cors-anywhere link
- if (url.indexOf(cors_api_url) == -1) newUrl = cors_api_url + url;
- return newUrl;
- }
-
- // Get visual loading progress, just enter the current progressing number (usually time elapsed in seconds)
- var getProgress = function(intProgress) {
- var progress = intProgress % 20;
- switch(progress) {
- case 0: return " █░░░░░░░░░░"; break;
- case 1: case 19: return " ░█░░░░░░░░░"; break;
- case 2: case 18: return " ░░█░░░░░░░░"; break;
- case 3: case 17: return " ░░░█░░░░░░░"; break;
- case 4: case 16: return " ░░░░█░░░░░░"; break;
- case 5: case 15: return " ░░░░░█░░░░░"; break;
- case 6: case 14: return " ░░░░░░█░░░░"; break;
- case 7: case 13: return " ░░░░░░░█░░░"; break;
- case 8: case 12: return " ░░░░░░░░█░░"; break;
- case 9: case 11: return " ░░░░░░░░░█░"; break;
- case 10: return " ░░░░░░░░░░█"; break;
- }
- }
-
- // Checks if loading music should play
- var preventsLoadingMusic = function() {
- return !loadingMusicPrematureStop && !Player.isPlaying() && !MPP.client.preventsPlaying();
- }
-
- // This is used when loading a song in the midi player, if it's been turned on
- var humanMusic = function() {
- setTimeout(function() {
- if (preventsLoadingMusic()) MPP.press("c5", 1);
- if (preventsLoadingMusic()) MPP.release("c5");
- }, 200);
- setTimeout(function() {
- if (preventsLoadingMusic()) MPP.press("d5", 1);
- if (preventsLoadingMusic()) MPP.release("d5");
- }, 700);
- setTimeout(function() {
- if (preventsLoadingMusic()) MPP.press("c5", 1);
- if (preventsLoadingMusic()) MPP.release("c5");
- loadingMusicPrematureStop = false;
- }, 1200);
- }
-
- // Starts the loading music
- var startLoadingMusic = function() {
- if (loadingMusicLoop == null) {
- humanMusic();
- loadingMusicLoop = setInterval(function() {
- humanMusic();
- }, 2200);
- }
- }
-
- // Stops the loading music
- var stopLoadingMusic = function() {
- if (loadingMusicLoop != null) {
- loadingMusicPrematureStop = true;
- clearInterval(loadingMusicLoop);
- loadingMusicLoop = null;
- }
- }
-
- // Check to make sure variable is initialized with something
- var exists = function(element) {
- if (typeof(element) != "undefined" && element != null) return true;
- return false;
- }
-
- // Format time to HH:MM:SS from seconds
- var secondsToHms = function(d) {
- d = Number(d);
-
- var h, m, s;
- var hDisplay = "00";
- var mDisplay = hDisplay;
- var sDisplay = hDisplay;
-
- if (d != null && d > 0) {
- h = Math.floor(d / 3600);
- m = Math.floor((d % 3600) / 60);
- s = Math.floor((d % 3600) % 60);
-
- hDisplay = (h < 10 ? "0" : "") + h;
- mDisplay = (m < 10 ? "0" : "") + m;
- sDisplay = (s < 10 ? "0" : "") + s;
- }
-
- return hDisplay + ':' + mDisplay + ':' + sDisplay;
- }
-
- // Takes formatted time and removed preceeding zeros (only before minutes)
- var timeClearZeros = function(formattedHms) {
- var newTime = formattedHms;
- while (newTime.length > 5 && newTime.indexOf("00:") == 0) {
- newTime = newTime.substring(3);
- }
- return newTime;
- }
-
- // Resizes a formatted HH:MM:SS time to the second formatted time
- var timeSizeFormat = function(timeCurrent, timeEnd) {
- var newTimeFormat = timeCurrent;
- var timeCurrentLength = timeCurrent.length;
- var timeEndLength = timeEnd.length;
- // lose or add 00's
- if (timeCurrentLength > timeEndLength) newTimeFormat = timeCurrent.substring(timeCurrentLength - timeEndLength);
- while (newTimeFormat.length < timeEndLength) {
- newTimeFormat = "00:" + newTimeFormat;
- }
- return newTimeFormat;
- }
-
- // Generate a random number
- var randomNumber = function(min, max) {
- min = Math.ceil(min);
- max = Math.floor(max);
- return Math.floor(Math.random() * (max - min + 1)) + min;
- }
-
- // Puts quotes around string
- var quoteString = function(string) {
- var newString = string;
- if (exists(string) && string != "") newString = '"' + string + '"';
- return newString
- }
-
- // Gets file as a blob (data URI)
- var urlToBlob = function(url, callback) {
- // show file download progress
- var downloading = null;
- mppChatSend(PRE_DOWNLOADING + ' ' + url);
- if (loadingOption) startLoadingMusic();
- else {
- var progress = 0;
- downloading = setInterval(function() {
- mppChatSend(PRE_DOWNLOADING + getProgress(progress));
- progress++;
- }, chatDelay);
- }
-
- fetch(url, {
- headers: {
- "Content-Disposition": "attachment" // this might not be doing anything
- }
- }).then(response => {
- stopLoadingMusic();
- clearInterval(downloading);
- if (!response.ok) {
- throw new Error("Network response was not ok");
- }
- return response.blob();
- }).then(blob => {
- stopLoadingMusic();
- clearInterval(downloading);
- callback(blob);
- }).catch(error => {
- console.error("Normal fetch couldn't get the file:", error);
- var corsUrl = useCorsUrl(url);
- if (corsUrl != null) {
- if (loadingOption) startLoadingMusic();
-
- fetch(corsUrl, {
- headers: {
- "Content-Disposition": "attachment" // this might not be doing anything
- }
- }).then(response => {
- stopLoadingMusic();
- clearInterval(downloading);
- if (!response.ok) {
- throw new Error("Network response was not ok");
- }
- return response.blob();
- }).then(blob => {
- stopLoadingMusic();
- clearInterval(downloading);
- callback(blob);
- }).catch(error => {
- console.error("CORS Anywhere API fetch couldn't get the file:", error);
- stopLoadingMusic();
- clearInterval(downloading);
- callback(null);
- });
- }
- // callback(null); // disabled since the second fetch already should call the call back
- });
- }
-
- // Converts files/blobs to base64 (data URI)
- var fileOrBlobToBase64 = function(raw, callback) {
- if (raw == null) {
- stopLoadingMusic();
- callback(null);
- }
-
- // continue if we have a blob
- var reader = new FileReader();
- reader.readAsDataURL(raw);
- reader.onloadend = function() {
- var base64data = reader.result;
- callback(base64data);
- }
- }
-
- // Validates file or blob is a MIDI
- var isMidi = function(raw) {
- if (exists(raw)) {
- var mimetype = raw.type;
- // acceptable mimetypes for midi files
- switch(mimetype) {
- case "@file/mid": case "@file/midi":
- case "application/mid": case "application/midi":
- case "application/x-mid": case "application/x-midi":
- case "audio/mid": case "audio/midi":
- case "audio/x-mid": case "audio/x-midi":
- case "music/crescendo":
- case "x-music/mid": case "x-music/midi":
- case "x-music/x-mid": case "x-music/x-midi": return true; break;
- }
- }
- return false;
- }
-
- // Validates file or blob is application/octet-stream ... when using CORS
- var isOctetStream = function(raw) {
- if (exists(raw) && raw.type == "application/octet-stream") return true;
- else return false;
- }
-
- // Makes all commands into one string
- var formattedCommands = function(commandsArray, prefix, spacing) { // needs to be 2D array with commands before descriptions
- if (!exists(prefix)) prefix = '';
- var commands = '';
- var i;
- for(i = 0; i < commandsArray.length; ++i) {
- commands += (spacing ? ' ' : '') + prefix + commandsArray[i][0];
- }
- return commands;
- }
-
- // Gets 1 command and info about it into a string
- var formatCommandInfo = function(commandsArray, commandIndex) {
- return LIST_BULLET + PREFIX + commandsArray[commandIndex][0] + DESCRIPTION_SEPARATOR + commandsArray[commandIndex][1];
- }
-
- // Send messages without worrying about timing
- var mppChatSend = function(str, delay) {
- setTimeout(function(){MPP.chat.send(str)}, (exists(delay) ? delay : 0));
- }
-
- // Send multiline chats, and return final delay to make things easier for timings
- var mppChatMultiSend = function(strArray, optionalPrefix, initialDelay) {
- if (!exists(optionalPrefix)) optionalPrefix = '';
- var newDelay = 0;
- var i;
- for (i = 0; i < strArray.length; ++i) {
- var currentString = strArray[i];
- if (currentString != "") {
- ++newDelay;
- mppChatSend(optionalPrefix + strArray[i], chatDelay * newDelay);
- }
- }
- return chatDelay * newDelay;
- }
-
- // Stops the current song if any are playing
- var stopSong = function() {
- stopped = true;
- if (!ended) {
- Player.stop();
- currentSongElapsedFormatted = timeSizeFormat(secondsToHms(0), currentSongDurationFormatted);
- ended = true;
- }
- if (paused) paused = false;
- }
-
- // Gets song from data URI and plays it
- var playSong = function(songFileName, songData) {
- // stop any current songs from playing
- stopSong();
- // play song if it loaded correctly
- try {
- // load song
- Player.loadDataUri(songData);
- // play song
- Player.play();
- ended = false;
- stopped = false;
- var timeoutRecorder = 0;
- var showSongName = setInterval(function() {
- if (Player.isPlaying()) {
- clearInterval(showSongName);
-
- // changes song
- //var hasExtension = songFileName.lastIndexOf('.');
- previousSongData = currentSongData;
- previousSongName = currentSongName;
- currentSongData = songData;
- currentSongName = /*(hasExtension > 0) ? songFileName.substring(0, hasExtension) :*/ songFileName;
- currentSongElapsedFormatted = timeSizeFormat(secondsToHms(0), currentSongDurationFormatted);
- currentSongDuration = Player.getSongTime();
- currentSongDurationFormatted = timeClearZeros(secondsToHms(currentSongDuration));
-
- mppChatSend(PRE_PLAY + ' ' + getSongTimesFormatted(currentSongElapsedFormatted, currentSongDurationFormatted) + " Now playing " + quoteString(currentSongName));
- } else if (timeoutRecorder == SONG_NAME_TIMEOUT) {
- clearInterval(showSongName);
- } else timeoutRecorder++;
- }, 1);
- } catch(error) {
- stopLoadingMusic();
- // reload the previous working file if there is one
- if (previousSongData != null) Player.loadDataUri(previousSongData);
- mppChatSend(PRE_ERROR + " (play) " + error);
- }
- }
-
- // Plays the song from a URL if it's a MIDI
- var playURL = function(songUrl, songData) {
- currentFileLocation = songUrl;
- var songFileName = decodeURIComponent(currentFileLocation.substring(currentFileLocation.lastIndexOf('/') + 1));
- playSong(songFileName, songData);
- }
-
- // Plays the song from an uploaded file if it's a MIDI
- var playFile = function(songFile) {
- var songFileName = null;
-
- var error = PRE_ERROR + " (play)";
- // load in the file
- if (exists(songFile)) {
- // check and limit file size, mainly to prevent browser tab crashing (not enough RAM to load) and deter black midi
- songFileName = songFile.name.split(/(\\|\/)/g).pop();
- if (songFile.size <= MIDI_FILE_SIZE_LIMIT_BYTES) {
- if (isMidi(songFile)) {
- fileOrBlobToBase64(songFile, function(base64data) {
- // play song only if we got data
- if (exists(base64data)) {
- currentFileLocation = songFile.name;
- playSong(songFileName, base64data);
- uploadButton.value = ""; // reset file input
- } else mppChatSend(error + " Unexpected result, MIDI file couldn't load");
- });
- } else mppChatSend(error + " The file choosen, \"" + songFileName + "\", is either corrupted, or it's not really a MIDI file");
- } else mppChatSend(error + " The file choosen, \"" + songFileName + "\", is too big (larger than " + MIDI_FILE_SIZE_LIMIT_BYTES + " bytes), please choose a file with a smaller size");
- } else mppChatSend(error + " MIDI file not found");
- }
-
- // Creates the play, pause, resume, and stop button for the bot
- var createButtons = function() {
- // need the bottom area to append buttons to
- var buttonContainer = document.querySelector("#bottom div");
- // we need to keep track of the next button locations
- var nextLocationX = BTNS_END_X;
-
- // need to initialize CSS_VARIABLE_X_DISPLACEMENT
- document.documentElement.style.setProperty(CSS_VARIABLE_X_DISPLACEMENT, "0px");
-
- // play needs the div like all the other buttons
- // PLAY
- var playDiv = document.createElement("div");
- playDiv.id = PRE_ELEMENT_ID + "-play";
- playDiv.style = BTN_STYLE + "top:" + BTNS_TOP_0 + "px;left:calc(" + nextLocationX + "px + var(" + CSS_VARIABLE_X_DISPLACEMENT + "));";
- playDiv.classList.add("ugly-button");
- buttonContainer.appendChild(playDiv);
- // since we need upload files, there also needs to be an input element inside the play div
- var uploadBtn = document.createElement("input");
- var uploadBtnId = PRE_ELEMENT_ID + "-upload";
- uploadBtn.id = uploadBtnId;
- uploadBtn.style = "opacity:0;filter:alpha(opacity=0);position:absolute;top:0;left:0;width:110px;height:22px;border-radius:3px;-webkit-border-radius:3px;-moz-border-radius:3px;";
- uploadBtn.title = " "; // removes the "No file choosen" tooltip
- uploadBtn.type = "file";
- uploadBtn.accept = ".mid,.midi";
- uploadBtn.onchange = function() {
- if (!MPP.client.preventsPlaying() && uploadBtn.files.length > 0) playFile(uploadBtn.files[0]);
- else console.log("No MIDI file selected");
- }
- // fix cursor on upload file button
- var head = document.getElementsByTagName('HEAD')[0];
- var uploadFileBtnFix = this.document.createElement('link');
- uploadFileBtnFix.setAttribute('rel', 'stylesheet');
- uploadFileBtnFix.setAttribute('type', 'text/css');
- uploadFileBtnFix.setAttribute('href', 'data:text/css;charset=UTF-8,' + encodeURIComponent('#' + uploadBtnId + ", #" + uploadBtnId + "::-webkit-file-upload-button {cursor:pointer}"));
- head.appendChild(uploadFileBtnFix);
- // continue with other html for play button
- var playTxt = document.createTextNode("Play");
- playDiv.appendChild(uploadBtn);
- playDiv.appendChild(playTxt);
- // then we need to let the rest of the script know it so it can reset it after loading files
- uploadButton = uploadBtn;
-
- // other buttons can work fine without major adjustments
- // STOP
- nextLocationX += BTN_SPACER_X;
- var stopDiv = document.createElement("div");
- stopDiv.id = PRE_ELEMENT_ID + "-stop";
- stopDiv.style = BTN_STYLE + "top:" + BTNS_TOP_0 + "px;left:calc(" + nextLocationX + "px + var(" + CSS_VARIABLE_X_DISPLACEMENT + "));";
- stopDiv.classList.add("ugly-button");
- stopDiv.onclick = function() {
- if (!MPP.client.preventsPlaying()) stop();
- }
- var stopTxt = document.createTextNode("Stop");
- stopDiv.appendChild(stopTxt);
- buttonContainer.appendChild(stopDiv);
- // REPEAT
- nextLocationX += BTN_SPACER_X;
- var repeatDiv = document.createElement("div");
- repeatDiv.id = PRE_ELEMENT_ID + "-repeat";
- repeatDiv.style = BTN_STYLE + "top:" + BTNS_TOP_0 + "px;left:calc(" + nextLocationX + "px + var(" + CSS_VARIABLE_X_DISPLACEMENT + "));";
- repeatDiv.classList.add("ugly-button");
- repeatDiv.onclick = function() {
- if (!MPP.client.preventsPlaying()) repeat();
- }
- var repeatTxt = document.createTextNode("Repeat");
- repeatDiv.appendChild(repeatTxt);
- buttonContainer.appendChild(repeatDiv);
- // SONG
- nextLocationX += BTN_SPACER_X;
- var songDiv = document.createElement("div");
- songDiv.id = PRE_ELEMENT_ID + "-song";
- songDiv.style = BTN_STYLE + "top:" + BTNS_TOP_0 + "px;left:calc(" + nextLocationX + "px + var(" + CSS_VARIABLE_X_DISPLACEMENT + "));";
- songDiv.classList.add("ugly-button");
- songDiv.onclick = function() {
- if (!MPP.client.preventsPlaying()) song();
- }
- var songTxt = document.createTextNode("Song");
- songDiv.appendChild(songTxt);
- buttonContainer.appendChild(songDiv);
- // PAUSE
- nextLocationX = BTNS_END_X;
- var pauseDiv = document.createElement("div");
- pauseDiv.id = PRE_ELEMENT_ID + "-pause";
- pauseDiv.style = BTN_STYLE + "top:" + BTNS_TOP_1 + "px;left:calc(" + nextLocationX + "px + var(" + CSS_VARIABLE_X_DISPLACEMENT + "));";
- pauseDiv.classList.add("ugly-button");
- pauseDiv.onclick = function() {
- if (!MPP.client.preventsPlaying()) pause();
- }
- var pauseTxt = document.createTextNode("Pause");
- pauseDiv.appendChild(pauseTxt);
- buttonContainer.appendChild(pauseDiv);
- // RESUME
- nextLocationX += BTN_SPACER_X;
- var resumeDiv = document.createElement("div");
- resumeDiv.id = PRE_ELEMENT_ID + "-resume";
- resumeDiv.style = BTN_STYLE + "top:" + BTNS_TOP_1 + "px;left:calc(" + nextLocationX + "px + var(" + CSS_VARIABLE_X_DISPLACEMENT + "));";
- resumeDiv.classList.add("ugly-button");
- resumeDiv.onclick = function() {
- if (!MPP.client.preventsPlaying()) resume();
- }
- var resumeTxt = document.createTextNode("Resume");
- resumeDiv.appendChild(resumeTxt);
- buttonContainer.appendChild(resumeDiv);
- // SUSTAIN
- nextLocationX += BTN_SPACER_X;
- var sustainDiv = document.createElement("div");
- sustainDiv.id = PRE_ELEMENT_ID + "-sustain";
- sustainDiv.style = BTN_STYLE + "top:" + BTNS_TOP_1 + "px;left:calc(" + nextLocationX + "px + var(" + CSS_VARIABLE_X_DISPLACEMENT + "));";
- sustainDiv.classList.add("ugly-button");
- sustainDiv.onclick = function() {
- if (!MPP.client.preventsPlaying()) sustain();
- }
- var sustainTxt = document.createTextNode("Sustain");
- sustainDiv.appendChild(sustainTxt);
- buttonContainer.appendChild(sustainDiv);
- // PUBLIC
- nextLocationX += BTN_SPACER_X;
- var publicDiv = document.createElement("div");
- publicDiv.id = PRE_ELEMENT_ID + '-' + BOT_ACTIVATOR;
- publicDiv.style = BTN_STYLE + "top:" + BTNS_TOP_1 + "px;left:calc(" + nextLocationX + "px + var(" + CSS_VARIABLE_X_DISPLACEMENT + "));";
- publicDiv.classList.add("ugly-button");
- publicDiv.onclick = function() { public(true, true) }
- var publicTxt = document.createTextNode("Public");
- publicDiv.appendChild(publicTxt);
- buttonContainer.appendChild(publicDiv);
-
- // one more button to toggle the visibility of the other buttons
- nextLocationX = BTNS_END_X - BTN_SPACER_X;
- var buttonsOn = false;
- var togglerDiv = document.createElement("div");
- togglerDiv.id = PRE_ELEMENT_ID + "-toggler";
- togglerDiv.style = ELEM_POS + ELEM_ON + "top:" + BTNS_TOP_0 + "px;left:calc(" + nextLocationX + "px + var(" + CSS_VARIABLE_X_DISPLACEMENT + "));"; // normally BTNS_TOP_1, but had to be changed to work with mppclone
- togglerDiv.classList.add("ugly-button");
- togglerDiv.onclick = function() {
- if (buttonsOn) { // if on, then turn off, else turn on
- playDiv.style.display =
- stopDiv.style.display =
- repeatDiv.style.display =
- songDiv.style.display =
- pauseDiv.style.display =
- resumeDiv.style.display =
- sustainDiv.style.display =
- publicDiv.style.display = "none";
- buttonsOn = false;
- } else {
- playDiv.style.display =
- stopDiv.style.display =
- repeatDiv.style.display =
- songDiv.style.display =
- pauseDiv.style.display =
- resumeDiv.style.display =
- sustainDiv.style.display =
- publicDiv.style.display = "block";
- buttonsOn = true;
- }
- }
- var togglerTxt = document.createTextNode(NAME);
- togglerDiv.appendChild(togglerTxt);
- buttonContainer.appendChild(togglerDiv);
- }
-
- // Sends back the current time in the song against total time
- var getSongTimesFormatted = function(elapsed, duration) {
- return '[' + elapsed + " / " + duration + ']';
- }
-
- // Shows limited message for user
- var playerLimited = function(username) {
- // displays message with their name about being limited
- mppChatSend(PRE_LIMITED + " You must of done something to earn this " + quoteString(username) + " as you are no longer allowed to use the bot");
- }
-
- // When there is an incorrect command, show this error
- var cmdNotFound = function(cmd) {
- var error = PRE_ERROR + " Invalid command, " + quoteString(cmd) + " doesn't exist";
- if (publicOption) mppChatSend(error);
- else console.log(error);
- }
-
- // Commands
- var help = function(command, userId, yourId) {
- var isOwner = MPP.client.isOwner();
- if (!exists(command) || command == "") {
- var publicCommands = formattedCommands(BOT_COMMANDS, LIST_BULLET + PREFIX, true);
- mppChatSend(PRE_HELP + " Commands: " + formattedCommands(BASE_COMMANDS, LIST_BULLET + PREFIX, true)
- + (publicOption ? ' ' + publicCommands : '')
- + (userId == yourId ? " | Bot Owner Commands: " + (publicOption ? '' : publicCommands + ' ') + formattedCommands(BOT_OWNER_COMMANDS, LIST_BULLET + PREFIX, true) : ''));
- } else {
- var valid = null;
- var commandIndex = null;
- var commandArray = null;
- command = command.toLowerCase();
- // check commands arrays
- var i;
- for(i = 0; i < BASE_COMMANDS.length; i++) {
- if (BASE_COMMANDS[i][0].indexOf(command) == 0) {
- valid = command;
- commandArray = BASE_COMMANDS;
- commandIndex = i;
- }
- }
- var j;
- for(j = 0; j < BOT_COMMANDS.length; j++) {
- if (BOT_COMMANDS[j][0].indexOf(command) == 0) {
- valid = command;
- commandArray = BOT_COMMANDS;
- commandIndex = j;
- }
- }
- var k;
- for(k = 0; k < BOT_OWNER_COMMANDS.length; k++) {
- if (BOT_OWNER_COMMANDS[k][0].indexOf(command) == 0) {
- valid = command;
- commandArray = BOT_OWNER_COMMANDS;
- commandIndex = k;
- }
- }
- // display info on command if it exists
- if (exists(valid)) mppChatSend(PRE_HELP + ' ' + formatCommandInfo(commandArray, commandIndex),);
- else cmdNotFound(command);
- }
- }
- var about = function() {
- mppChatSend(PRE_ABOUT + ' ' + BOT_DESCRIPTION + ' ' + BOT_AUTHOR + ' ' + BOT_NAMESPACE);
- }
- var link = function() {
- mppChatSend(PRE_LINK + " You can download this bot from " + DOWNLOAD_URL);
- }
- var feedback = function() {
- mppChatSend(PRE_FEEDBACK + " Please go to " + FEEDBACK_URL + " in order to submit feedback.");
- }
- var ping = function() {
- // get a response back in milliseconds
- pinging = true;
- pingTime = Date.now();
- mppChatSend(PRE_PING);
- setTimeout(function() {
- if (pinging) mppChatSend("Pong! [within 1 second]");
- pinging = false;
- }, SECOND);
- }
- var play = function(url) {
- var error = PRE_ERROR + " (play)";
- // URL needs to be entered to play a song
- if (!exists(url) || url == "") {
- stopLoadingMusic();
- mppChatSend(error + " No MIDI url entered... " + WHERE_TO_FIND_MIDIS);
- } else {
- // downloads file if possible and then plays it if it's a MIDI
- urlToBlob(url, function(blob) {
- if (blob == null) mppChatSend(error + " Invalid URL, this is not a MIDI file, or the file requires a manual download from " + quoteString(' ' + url + ' ') + "... " + WHERE_TO_FIND_MIDIS);
- else if (isMidi(blob) || isOctetStream(blob)) {
- // check and limit file size, mainly to prevent browser tab crashing (not enough RAM to load) and deter black midi
- if (blob.size <= MIDI_FILE_SIZE_LIMIT_BYTES) {
- fileOrBlobToBase64(blob, function(base64data) {
- // play song only if we got data
- if (exists(base64data)) {
- if (isOctetStream(blob)) { // when download with CORS, need to replace mimetype, but it doesn't guarantee it's a MIDI file
- base64data = base64data.replace("application/octet-stream", "audio/midi");
- }
- playURL(url, base64data);
- } else mppChatSend(error + " Unexpected result, MIDI file couldn't load... " + WHERE_TO_FIND_MIDIS);
- });
- } else mppChatSend(error + " The file choosen, \"" + decodeURIComponent(url.substring(url.lastIndexOf('/') + 1)) + "\", is too big (larger than " + MIDI_FILE_SIZE_LIMIT_BYTES + " bytes), please choose a file with a smaller size");
- } else mppChatSend(error + " Invalid URL, this is not a MIDI file... " + WHERE_TO_FIND_MIDIS);
- });
- }
- }
- var stop = function() {
- // stops the current song
- if (ended) mppChatSend(PRE_STOP + ' ' + NO_SONG);
- else {
- stopSong();
- paused = false;
- mppChatSend(PRE_STOP + " Stopped playing " + quoteString(currentSongName));
- currentFileLocation = currentSongName = null;
- }
- }
- var pause = function() {
- // pauses the current song
- if (ended) mppChatSend(PRE_PAUSE + ' ' + NO_SONG);
- else {
- var title = PRE_PAUSE + ' ' + getSongTimesFormatted(currentSongElapsedFormatted, currentSongDurationFormatted);
- if (paused) mppChatSend(title + " The song is already paused");
- else {
- Player.pause();
- paused = true;
- mppChatSend(title + " Paused " + quoteString(currentSongName));
- }
- }
- }
- var resume = function() {
- // resumes the current song
- if (ended) mppChatSend(PRE_RESUME + ' ' + NO_SONG);
- else {
- var title = PRE_RESUME + ' ' + getSongTimesFormatted(currentSongElapsedFormatted, currentSongDurationFormatted);
- if (paused) {
- Player.play();
- paused = false;
- mppChatSend(title + " Resumed " + quoteString(currentSongName));
- } else mppChatSend(title + " The song is already playing");
- }
- }
- var song = function() {
- // shows current song playing
- if (exists(currentSongName) && currentSongName != "") {
- mppChatSend(PRE_SONG + ' ' + getSongTimesFormatted(currentSongElapsedFormatted, currentSongDurationFormatted)
- + " Currently " + (paused ? "paused on" : "playing") + ' ' + quoteString(currentSongName));
- } else mppChatSend(PRE_SONG + ' ' + NO_SONG);
- }
- var repeat = function() {
- // turns on or off repeat
- repeatOption = !repeatOption;
-
- mppChatSend(PRE_REPEAT + " Repeat set to " + (repeatOption ? "" : "not") + " repeating");
- }
- var sustain = function() {
- // turns on or off sustain
- sustainOption = !sustainOption;
-
- mppChatSend(PRE_SUSTAIN + " Sustain set to " + (sustainOption ? "MIDI controlled" : "MPP controlled"));
- }
- var loading = function(userId, yourId) {
- // only let the bot owner set if loading music should be on or not
- if (userId != yourId) return;
- loadingOption = !loadingOption;
- mppChatSend(PRE_LOAD_MUSIC + " The MIDI loading progress is now set to " + (loadingOption ? "audio" : "text"));
- }
- var public = function(userId, yourId) {
- // only let the bot owner set if public bot commands should be on or not
- if (userId != yourId) return;
- publicOption = !publicOption;
- mppChatSend(PRE_PUBLIC + " Public bot commands were turned " + (publicOption ? "on" : "off"));
- }
-
- // =============================================== MAIN
-
- Player.on('fileLoaded', function() {
- // Do something when file is loaded
- stopLoadingMusic();
- });
- MPP.client.on('a', function (msg) {
- // if user switches to VPN, these need to update
- var yourParticipant = MPP.client.getOwnParticipant();
- var yourId = yourParticipant._id;
- var yourUsername = yourParticipant.name;
- // get the message as string
- var input = msg.a.trim();
- var participant = msg.p;
- var username = participant.name;
- var userId = participant._id;
-
- // check if ping
- if (userId == yourId && pinging && input == PRE_PING) {
- pinging = false;
- pingTime = Date.now() - pingTime;
- mppChatSend("Pong! [" + pingTime + "ms]", 0 );
- }
-
- // make sure the start of the input matches prefix
- if (input.startsWith(PREFIX)) {
- // don't allow banned or limited users to use the bot
- var bannedPlayers = BANNED_PLAYERS.length;
- if (bannedPlayers > 0) {
- var i;
- for(i = 0; i < BANNED_PLAYERS.length; ++i) {
- if (BANNED_PLAYERS[i] == userId) {
- playerLimited(username);
- return;
- }
- }
- }
- var limitedPlayers = LIMITED_PLAYERS.length;
- if (limitedPlayers > 0) {
- var j;
- for(j = 0; j < LIMITED_PLAYERS.length; ++j) {
- if (LIMITED_PLAYERS[j] == userId) {
- playerLimited(username);
- return;
- }
- }
- }
- // evaluate input into command and possible arguments
- var message = input.substring(PREFIX_LENGTH).trim();
- var hasArgs = message.indexOf(' ');
- var command = (hasArgs != -1) ? message.substring(0, hasArgs) : message;
- var argumentsString = (hasArgs != -1) ? message.substring(hasArgs + 1).trim() : null;
- // look through commands
- var isBotOwner = userId == yourId;
- var preventsPlaying = MPP.client.preventsPlaying();
- switch (command.toLowerCase()) {
- case "help": case "h": if ((isBotOwner || publicOption) && !preventsPlaying) help(argumentsString, userId, yourId); break;
- case "about": case "ab": if ((isBotOwner || publicOption) && !preventsPlaying) about(); break;
- case "link": case "li": if ((isBotOwner || publicOption) && !preventsPlaying) link(); break;
- case "feedback": case "fb": if (isBotOwner || publicOption) feedback(); break;
- case "ping": case "pi": if (isBotOwner || publicOption) ping(); break;
- case "play": case "p": if ((isBotOwner || publicOption) && !preventsPlaying) play(argumentsString); break;
- case "stop": case "s": if ((isBotOwner || publicOption) && !preventsPlaying) stop(); break;
- case "pause": case "pa": if ((isBotOwner || publicOption) && !preventsPlaying) pause(); break;
- case "resume": case "r": if ((isBotOwner || publicOption) && !preventsPlaying) resume(); break;
- case "song": case "so": if ((isBotOwner || publicOption) && !preventsPlaying) song(); break;
- case "repeat": case "re": if ((isBotOwner || publicOption) && !preventsPlaying) repeat(); break;
- case "sustain": case "ss": if ((isBotOwner || publicOption) && !preventsPlaying) sustain(); break;
- case "loading": case "lo": loading(userId, yourId); break;
- case BOT_ACTIVATOR: public(userId, yourId); break;
- }
- }
- });
- MPP.client.on("ch", function(msg) {
- // set new chat delay based on room ownership after changing rooms
- if (!MPP.client.isOwner()) chatDelay = SLOW_CHAT_DELAY;
- else chatDelay = CHAT_DELAY;
- // update current room info
- var newRoom = MPP.client.channel._id;
- if (currentRoom != newRoom) {
- currentRoom = MPP.client.channel._id;
- // stop any songs that might have been playing before changing rooms
- if (currentRoom.toUpperCase().indexOf(BOT_KEYWORD) == -1) stopSong();
- }
- });
- MPP.client.on('p', function(msg) {
- var userId = msg._id;
- // kick ban all the banned players
- var bannedPlayers = BANNED_PLAYERS.length;
- if (bannedPlayers > 0) {
- var i;
- for(i = 0; i < BANNED_PLAYERS.length; ++i) {
- var bannedPlayer = BANNED_PLAYERS[i];
- if (userId == bannedPlayer) MPP.client.sendArray([{m: "kickban", _id: bannedPlayer, ms: 3600000}]);
- }
- }
- });
-
- // =============================================== INTERVALS
-
- // Stuff that needs to be done by intervals (e.g. repeat)
- var repeatingTasks = setInterval(function() {
- if (MPP.client.preventsPlaying()) return;
- // do repeat
- if (repeatOption && ended && !stopped && exists(currentSongName) && exists(currentSongData)) {
- ended = false;
- // nice delay before playing song again
- setTimeout(function() {Player.play()}, REPEAT_DELAY);
- }
- }, 1);
- var dynamicButtonDisplacement = setInterval(function() {
- // required when "Room Settings" button shows up
- mppRoomSettingsBtn = document.getElementById(MPP_ROOM_SETTINGS_ID);
- xDisplacement = getComputedStyle(document.documentElement).getPropertyValue(CSS_VARIABLE_X_DISPLACEMENT);
- // if "Room Settings" button exists and is visible, enable displacement, else revert only when not already changed
- if (xDisplacement == "0px" &&
- (mppRoomSettingsBtn &&
- (!mppRoomSettingsBtn.style ||
- (!mppRoomSettingsBtn.style.display ||
- (mppRoomSettingsBtn.style.display == "block"))))) {
- document.documentElement.style.setProperty(CSS_VARIABLE_X_DISPLACEMENT, BTN_SPACER_X + "px");
- } else if (xDisplacement != "0px" &&
- (!mppRoomSettingsBtn ||
- (mppRoomSettingsBtn.style &&
- mppRoomSettingsBtn.style.display &&
- mppRoomSettingsBtn.style.display != "block"))) {
- document.documentElement.style.setProperty(CSS_VARIABLE_X_DISPLACEMENT, "0px");
- }
- }, TENTH_OF_SECOND);
- var slowRepeatingTasks = setInterval(function() {
- // do background tab fix
- if (!pageVisible) {
- var note = MPP.piano.keys["a-1"].note;
- var participantId = MPP.client.getOwnParticipant().id;
- MPP.piano.audio.play(note, 0.01, 0, participantId);
- MPP.piano.audio.stop(note, 0, participantId);
- }
- }, SECOND);
-
- // Automatically turns off the sound warning (mainly for autoplay)
- var clearSoundWarning = setInterval(function() {
- var playButton = document.querySelector("#sound-warning button");
- if (exists(playButton)) {
- clearInterval(clearSoundWarning);
- playButton.click();
- // wait for the client to come online
- var waitForMPP = setInterval(function() {
- if (exists(MPP) && exists(MPP.client) && exists(MPP.client.channel) && exists(MPP.client.channel._id) && MPP.client.channel._id != "") {
- clearInterval(waitForMPP);
-
- currentRoom = MPP.client.channel._id;
- if (currentRoom.toUpperCase().indexOf(BOT_KEYWORD) >= 0) {
- loadingOption = publicOption = true;
- }
- createButtons();
- console.log(PRE_MSG + " Online!");
- }
- }, TENTH_OF_SECOND);
- }
- }, TENTH_OF_SECOND);