🏠 Home 

DiscordVMSG

Voice Message using Discord liek snapchat. Hold the microphone button next to the chat bar to create a voice chat.


Install this script?
// ==UserScript==
// @name         DiscordVMSG
// @namespace    None
// @version      0.2
// @language     English
// @description  Voice Message using Discord liek snapchat. Hold the microphone button next to the chat bar to create a voice chat.
// @author       xPythh
// @match        https://discord.com/channels/*
// @grant        none
// ==/UserScript==
var checkIfReadyInterval;
var microphonePicture;
var startedAt;
var isTalking = false;
var leftchannel = [];
var rightchannel = [];
var recorder = null;
var recordingLength = 0;
var volume = null;
var mediaStream = null;
var sampleRate = 48000; // voice pitch need to be edited according to microphone, increase if its too dark, or decrease it if too hight
var context = null;
var voiceBlob;
var localStorage;
// Chat Bar is dynamic and "reinitialised" between each browsing page, so we need to constantly insert it, if doesn't exist
function attachMicrophoneButton()
{
if (!document.getElementById("chatTalkButton"))
{
var mainDiv = document.createElement('div');// Main Button Div
mainDiv.id = "chatTalkButton";
mainDiv.classList.add('button-3AYNKb');
mainDiv.classList.add('button-318s1X');
var mainButton = document.createElement('button');// Button itself
mainButton.type = "button";
mainButton.classList.add('button-14-BFJ');
mainButton.classList.add('enabled-2cQ-u7');
mainButton.classList.add('lookBlank-3eh9lL');
var secondDiv = document.createElement('div');// Div containing the Logo
secondDiv.classList.add('contents-18-Yxp');
var buttonLogo = new Image(); // Microphone Logo
var cantTalk = document.querySelector(".channelTextAreaDisabled-8rmlrp");
var canSendFiles = document.querySelector(".attachButton-2WznTc");
if (!cantTalk && canSendFiles) {
buttonLogo.src = "https://i.imgur.com/FdJV697.png"; // Can send files and talk in chat
} else {
buttonLogo.src = "https://i.imgur.com/2o7DvgF.png"; // Can't send messages / Files
}
buttonLogo.setAttribute('draggable', false);
microphonePicture = buttonLogo;
secondDiv.appendChild(buttonLogo);
mainButton.appendChild(secondDiv);
mainDiv.appendChild(mainButton);
// Check if the chatbox exists before creating any element (Else will break up Discord Interface)
var chatTools = document.querySelector(".buttons-3JBrkn");
if (chatTools)
{
var microphoneButton = document.body.appendChild(mainDiv);
chatTools.insertBefore(microphoneButton, chatTools.firstChild);
if (!cantTalk) microphoneButton.addEventListener('mousedown', function(event)
{
isTalking = true;
startedAt = Date.now();
microphonePicture.src = "https://i.imgur.com/bx2hCl3.gif";
startRecording();
});
// Passing trought document, then user can leave the button rectangle
document.addEventListener('mouseup', function(event)
{
if (!isTalking) return;
microphonePicture.src = "https://i.imgur.com/FdJV697.png";
stopRecording();
if (Date.now() - startedAt < 500) return; // Message too short, let's not send that
var xhr = new XMLHttpRequest();
var fd = new FormData();
fd.append("audio_data", voiceBlob , `VMSG_${Date.now() / 1000}.wav`);
var channelsData = location.href.match(/channels\/([\w@]+)\/(\d+)/);
var channelId = channelsData[2]
xhr.open("POST",`https://discord.com/api/v8/channels/${channelId}/messages`, true);
xhr.setRequestHeader("Authorization", JSON.parse(localStorage.token));
xhr.send(fd);
// Reinitialise Every vocal variables
isTalking = false;
voiceBlob = null;
leftchannel = [];
rightchannel = [];
recordingLength = 0;
});
}
}
}
function flattenArray(channelBuffer, recordingLength) {
var r###lt = new Float32Array(recordingLength);
var offset = 0;
for (var i = 0; i < channelBuffer.length; i++) {
var buffer = channelBuffer[i];
r###lt.set(buffer, offset);
offset += buffer.length;
}
return r###lt;
}
function interleave(leftChannel, rightChannel) {
var length = leftChannel.length + rightChannel.length;
var r###lt = new Float32Array(length);
var inputIndex = 0;
for (var index = 0; index < length;) {
r###lt[index++] = leftChannel[inputIndex];
r###lt[index++] = rightChannel[inputIndex];
inputIndex++;
}
return r###lt;
}
function writeUTFBytes(view, offset, string) {
for (var i = 0; i < string.length; i++) view.setUint8(offset + i, string.charCodeAt(i));
}
function startRecording() {
navigator.getUserMedia = navigator.getUserMedia || navigator.webkitGetUserMedia || navigator.mozGetUserMedia || navigator.msGetUserMedia;
navigator.getUserMedia({audio: true},
function (e) {
window.AudioContext = window.AudioContext || window.webkitAudioContext;
context = new AudioContext();
mediaStream = context.createMediaStreamSource(e);
var bufferSize = 2048;
var numberOfInputChannels = 2;
var numberOfOutputChannels = 2;
if (context.createScriptProcessor) {
recorder = context.createScriptProcessor(bufferSize, numberOfInputChannels, numberOfOutputChannels);
} else {
recorder = context.createJavaScriptNode(bufferSize, numberOfInputChannels, numberOfOutputChannels);
}
recorder.onaudioprocess = function (e) {
leftchannel.push(new Float32Array(e.inputBuffer.getChannelData(0)));
rightchannel.push(new Float32Array(e.inputBuffer.getChannelData(1)));
recordingLength += bufferSize;
}
mediaStream.connect(recorder);
recorder.connect(context.destination);
},function (e) {});
}
function stopRecording() {
if (!recorder) return;
recorder.disconnect(context.destination);
mediaStream.disconnect(recorder);
var leftBuffer = flattenArray(leftchannel, recordingLength);
var rightBuffer = flattenArray(rightchannel, recordingLength);
var interleaved = interleave(leftBuffer, rightBuffer);
var buffer = new ArrayBuffer(44 + interleaved.length * 2);
var view = new DataView(buffer);
writeUTFBytes(view, 0, 'RIFF');
view.setUint32(4, 44 + interleaved.length * 2, true);
writeUTFBytes(view, 8, 'WAVE');
writeUTFBytes(view, 12, 'fmt ');
view.setUint32(16, 16, true); // chunkSize
view.setUint16(20, 1, true); // wFormatTag
view.setUint16(22, 2, true); // wChannels: stereo (2 channels)
view.setUint32(24, sampleRate, true); // dwSamplesPerSec
view.setUint32(28, sampleRate * 4, true); // dwAvgBytesPerSec
view.setUint16(32, 4, true); // wBlockAlign
view.setUint16(34, 16, true); // wBitsPerSample
writeUTFBytes(view, 36, 'data');
view.setUint32(40, interleaved.length * 2, true);
var index = 44;
var volume = 1;
for (var i = 0; i < interleaved.length; i++) {
view.setInt16(index, interleaved[i] * (0x7FFF * volume), true);
index += 2;
}
voiceBlob = new Blob([view], { type: 'audio/wav' });
}
function checkIfReady() {
if (document.querySelector(".buttons-3JBrkn"))
{
window.dispatchEvent(new Event('beforeunload'));
localStorage = document.body.appendChild(document.createElement('iframe')).contentWindow.localStorage;
clearInterval(checkIfReadyInterval)
setInterval(attachMicrophoneButton,125);
}
}
checkIfReadyInterval = setInterval(checkIfReady,1000);