durss

Voicemod websocket API

Jul 26th, 2021 (edited)
784
Never
Not a member of Pastebin yet? Sign Up, it unlocks many cool features!
  1. import { v4 as uuidv4 } from "uuid";
  2. import * as WebSocket from "ws";
  3.  
  4. /**
  5. * Created by Durss
  6. *
  7. * https://durss.ninja
  8. */
  9. export default class VoicemodWebSocket {
  10.  
  11.     public static ACTION_REGISTER_PLUGIN: string = "registerPlugin";
  12.     public static ACTION_GET_VOICES: string = "getVoices";
  13.     public static ACTION_GET_MEMES: string = "getMemes";
  14.     public static ACTION_SELECT_VOICE: string = "selectVoice";
  15.     public static ACTION_PLAY_MEME: string = "playMeme";
  16.     public static ACTION_STOP_ALL_MEME_SOUNDS: string = "stopAllMemeSounds";
  17.     public static ACTION_BEEP_SOUND_ON_OFF: string = "beepSound_OnOff";
  18.  
  19.     //Bellow events are captured but nothing is done with it so far
  20.     public static EVENT_TOGGLE_MUTE: string = "toggleMute";
  21.     public static EVENT_TOGGLE_VOICE_CHANGER: string = "toggleVoiceChanger";
  22.     public static EVENT_TOGGLE_BACKGROUND: string = "toggleBackground";
  23.     public static EVENT_TOGGLE_HEAR_MY_VOICE: string = "toggleHearMyVoice";
  24.     public static EVENT_VOICE_CHANGED_EVENT: string = "voiceChangedEvent";
  25.  
  26.     //Bellow actions are not implemented
  27.     public static ACTION_GET_BITMAP: string = "getBitmap";
  28.     public static ACTION_SELECT_RANDOM_VOICE: string = "selectRandomVoice";
  29.     public static ACTION_VOICE_CHANGER_ON_OFF: string = "voiceChanger_OnOff";
  30.     public static ACTION_HEAR_MY_VOICE_ON_OFF: string = "hearMyVoice_OnOff";
  31.     public static ACTION_BACKGROUND_ON_OFF: string = "background_OnOff";
  32.     public static ACTION_GET_HEAR_MYSELF_STATUS: string = "getHearMyselfStatus";
  33.     public static ACTION_GET_VOICE_CHANGER_STATUS: string = "getVoiceChangerStatus";
  34.     public static ACTION_GET_MUTE_MIC_STATUS: string = "getMuteMicStatus";
  35.     public static ACTION_GET_BACKGROUND_EFFECT_STATUS: string = "getBackgroundEffectStatus";
  36.     public static ACTION_DATA_STOP_ALL_SOUNDS: string = "stopAllSounds";
  37.  
  38.     private _initResolver: Function;
  39.     private _socket: WebSocket;
  40.     private _voicesList: VoicemodTypes.Voice[];
  41.     private _memesList: VoicemodTypes.Meme[];
  42.     private _currentVoiceEffect: VoicemodTypes.Voice;
  43.  
  44.     constructor() {
  45.  
  46.     }
  47.  
  48.     /********************
  49.     * GETTER / SETTERS *
  50.     ********************/
  51.  
  52.     /**
  53.      * Get all the available voice effects
  54.      */
  55.     public get voices():VoicemodTypes.Voice[] {
  56.         return JSON.parse(JSON.stringify(this._voicesList));
  57.     }
  58.  
  59.     /**
  60.      * Get all the available memes list
  61.      */
  62.     public get memes():VoicemodTypes.Meme[] {
  63.         return JSON.parse(JSON.stringify(this._memesList));
  64.     }
  65.  
  66.     /**
  67.      * Get all the available memes list
  68.      */
  69.     public get currentVoiceEffect():VoicemodTypes.Voice {
  70.         return this._currentVoiceEffect;
  71.     }
  72.  
  73.  
  74.  
  75.     /******************
  76.     * PUBLIC METHODS *
  77.     ******************/
  78.     public connect(ip:string="127.0.0.1", port:number=59129): Promise<void> {
  79.         return new Promise((resolve, reject) => {
  80.             this._initResolver = resolve;
  81.             this._socket = new WebSocket(`ws://${ip}:${port}/vmsd/`);
  82.             this._socket.onopen = () => {
  83.                 console.log('Connected to Voicemod APP');
  84.                 console.log('Voicemod connection succeed');
  85.             };
  86.             this._socket.onmessage = (event:VoicemodTypes.SocketEvent) => this.onSocketMessage(event);
  87.    
  88.             this._socket.onerror = (error) => {
  89.                 console.log('Voicemod connection lost');
  90.                 setTimeout(_=> {
  91.                     this.connect();
  92.                 }, 1000);
  93.                 reject();
  94.             }
  95.         });
  96.     }
  97.  
  98.     /**
  99.      * Activate a voice effect by its name.
  100.      * There's a tolerence on the name matching.
  101.      * If the actual voice effect name is "Game Over", you can activate
  102.      * it with "gameover".
  103.      *
  104.      * @param name      the name of the voice effect to activate
  105.      * @param id        (optional) The ID of the voice effect to activate
  106.      */
  107.     public enableVoiceEffect(name:string, id?:string): void {
  108.         let voice:VoicemodTypes.Voice;
  109.         let rawName = name;
  110.         name = name.trim().toLowerCase().replace(/[^\w\s]/g, '')
  111.         //Search for a voice effect with the requested name
  112.         for (let i = 0; i < this._voicesList.length; i++) {
  113.             if(id) {
  114.                 if (id === this._voicesList[i].voiceID) {
  115.                     voice = this._voicesList[i];
  116.                     break;
  117.                 }
  118.             }else{
  119.                 let nameRef = this._voicesList[i].friendlyName;
  120.                 //Check if the requested name is exactly the same
  121.                 if(rawName == nameRef) {
  122.                     voice = this._voicesList[i];
  123.                     //As this exactly matches the requested name, we can stop searching
  124.                     break;
  125.                 }
  126.                 //Check if requested name is more or less the same
  127.                 if (nameRef.trim().toLowerCase().replace(/[^\w\s]/g, '') === name) {
  128.                     voice = this._voicesList[i];
  129.                 }
  130.             }
  131.         }
  132.  
  133.         if(!voice) {
  134.             console.log("Voicemod: voice effect "+id? id : name+" not found");
  135.         }else{
  136.             this._currentVoiceEffect = voice;
  137.             this.send(VoicemodWebSocket.ACTION_SELECT_VOICE, {voiceID:voice.voiceID});
  138.         }
  139.     }
  140.  
  141.     /**
  142.      * Disables the current voice effect
  143.      */
  144.     public disableVoiceEffect():void {
  145.         this.enableVoiceEffect("clean");
  146.         this._currentVoiceEffect = null;
  147.     }
  148.  
  149.     /**
  150.      * Makes a beep sound
  151.      * If a duration is specified the beep will be stoped after this amoutn of milliseconds.
  152.      *
  153.      * @param duration      beep duration. Set to 0 if you don't want it to stop automatically.
  154.      * @param forcedState   set to 1 to force it to beep, or 0 to force it to not beep
  155.      */
  156.     public beep(duration:number = 500, forcedState:1|0 = null):void {
  157.         let data = {badLanguage:forcedState != null? forcedState : 1};
  158.         this.send(VoicemodWebSocket.ACTION_BEEP_SOUND_ON_OFF, data);
  159.  
  160.         //If asked to beep for a specific duration,
  161.         //stop the beep sound after that duration
  162.         if(duration > 0) {
  163.             setTimeout(_=> {
  164.                 data.badLanguage = 0;
  165.                 this.send(VoicemodWebSocket.ACTION_BEEP_SOUND_ON_OFF, data);
  166.             }, duration);
  167.         }
  168.     }
  169.  
  170.     /**
  171.      * Activate a meme sound by its name.
  172.      * There's a tolerence on the name matching.
  173.      * If the actual meme name is "Game Over", you can activate
  174.      * it with "gameover".
  175.      *
  176.      * @param name      the name of the meme sound to activate
  177.      * @param id        (optional) The "FileName" of the meme to activate
  178.      */
  179.     public playMeme(name:string, id?:string):void {
  180.         let fileID = "";
  181.         let rawName = name;
  182.         name = name.trim().toLowerCase().replace(/[^\w\s]/g, '')
  183.         //Search for a voice effect with the requested name
  184.         for (let i = 0; i < this._memesList.length; i++) {
  185.             if(id) {
  186.                 if (id === this._memesList[i].FileName) {
  187.                     fileID = this._memesList[i].FileName;
  188.                     break;
  189.                 }
  190.             }else{
  191.                 let nameRef = this._memesList[i].Name;
  192.                 //Check if the requested name is exactly the same
  193.                 if(rawName == nameRef) {
  194.                     fileID = this._memesList[i].FileName;
  195.                     //As this exactly matches the requested name, we can stop searching
  196.                     break;
  197.                 }
  198.                 //Check if requested name is more or less the same
  199.                 if (nameRef.trim().toLowerCase().replace(/[^\w\s]/g, '') === name) {
  200.                     fileID = this._memesList[i].FileName;
  201.                 }
  202.             }
  203.         }
  204.  
  205.         if(!fileID) {
  206.             console.log("Voicemod: meme sound "+id? id : name+" not found");
  207.         }else{
  208.             this.send(VoicemodWebSocket.ACTION_PLAY_MEME, {FileName:fileID, IsKeyDown:true});
  209.         }
  210.     }
  211.  
  212.     /**
  213.      * Stops any playing meme sound
  214.      */
  215.     public stopMeme():void {
  216.         this.send(VoicemodWebSocket.ACTION_STOP_ALL_MEME_SOUNDS);
  217.     }
  218.  
  219.  
  220.  
  221.     /*******************
  222.     * PRIVATE METHODS *
  223.     *******************/
  224.  
  225.     /**
  226.      * Sends a data to Voicemod
  227.      */
  228.     private send(actionType: string, data?:any):void {
  229.         let uuid = uuidv4();
  230.         let json:any = {
  231.             "actionID": uuid,
  232.             "actionType": actionType,
  233.             "context": "request:" + uuid,
  234.             "pluginVersion": "2.0.0",
  235.         };
  236.         if(data) {
  237.             json.actionObject = data;
  238.         }
  239.         this._socket.send( JSON.stringify(json) );
  240.     }
  241.  
  242.     /**
  243.      * Called when a message is received from Voicemod app
  244.      */
  245.     private onSocketMessage(event:VoicemodTypes.SocketEvent):void {
  246.         let json:VoicemodTypes.SocketData = JSON.parse(event.data);
  247.         if (json.server) {
  248.             this.send(VoicemodWebSocket.ACTION_REGISTER_PLUGIN);
  249.             return;
  250.         }
  251.  
  252.         switch(json.actionType) {
  253.             case VoicemodWebSocket.ACTION_REGISTER_PLUGIN:
  254.                 //Request all available voice effect list
  255.                 this.send(VoicemodWebSocket.ACTION_GET_VOICES);
  256.                 //Request all available meme sound list
  257.                 this.send(VoicemodWebSocket.ACTION_GET_MEMES);
  258.                 //Request all available bitmaps
  259.                 this.send(VoicemodWebSocket.ACTION_GET_BITMAP);
  260.                 break;
  261.  
  262.             case VoicemodWebSocket.ACTION_GET_VOICES:
  263.                 this._voicesList = json.actionObject.allVoices;
  264.                 this.checkInitComplete();
  265.             break;
  266.            
  267.             case VoicemodWebSocket.ACTION_GET_MEMES:
  268.                 this._memesList = json.actionObject.listOfMemes;
  269.                 this.checkInitComplete();
  270.                 break;
  271.  
  272.             case VoicemodWebSocket.ACTION_GET_BITMAP:
  273.                 //JSON contains nothing much interesting
  274.                 //No idea what those bitmaps are supposed to be...
  275.                 break;
  276.  
  277.             case VoicemodWebSocket.EVENT_TOGGLE_MUTE:
  278.                 //TODO
  279.                 break;
  280.  
  281.             case VoicemodWebSocket.EVENT_TOGGLE_BACKGROUND:
  282.                 //TODO
  283.                 break;
  284.  
  285.             case VoicemodWebSocket.EVENT_TOGGLE_HEAR_MY_VOICE:
  286.                 //TODO
  287.                 break;
  288.  
  289.             case VoicemodWebSocket.EVENT_VOICE_CHANGED_EVENT:
  290.                 //TODO
  291.                 break;
  292.  
  293.             case VoicemodWebSocket.EVENT_TOGGLE_VOICE_CHANGER:
  294.                 //TODO
  295.                 break;
  296.  
  297.             default:
  298.                 console.log("Voicemod: unhandled actionType "+json.actionType);
  299.                 // console.log(json);
  300.         }
  301.     }
  302.  
  303.     /**
  304.      * Check if voices and memes list are laoded and resolves the
  305.      * connect promise.
  306.      */
  307.     private checkInitComplete():void {
  308.         if(this._voicesList && this._memesList) {
  309.             this._initResolver();
  310.         }
  311.     }
  312.  
  313. }
  314.  
  315. declare module VoicemodTypes {
  316.     export interface SocketEvent {
  317.         target:WebSocket;
  318.         type:string;
  319.         data:string;
  320.     }
  321.  
  322.     export interface SocketData {
  323.         actionType: string;
  324.         appVersion: string;
  325.         actionID?: any;
  326.         actionObject: ActionObject;
  327.         context: string;
  328.         server?: string;
  329.     }
  330.  
  331.     export interface ActionObject {
  332.         allVoices?: Voice[];
  333.         listOfMemes?: Meme[];
  334.         favoriteVoices?: Voice[];
  335.         customVoices?: Voice[];
  336.         selectedVoice?: string;
  337.         result?: Result;
  338.     }
  339.  
  340.     export interface Voice {
  341.         voiceID: string;
  342.         friendlyName: string;
  343.     }
  344.  
  345.     export interface Meme {
  346.         FileName:string;
  347.         Profile:string;
  348.         Name:string;
  349.         Type:string;
  350.         Image:string;
  351.         IsCore:boolean;
  352.     }
  353.  
  354.     export interface Result {
  355.         default: string;
  356.     }
  357. }
  358.  
  359.  
RAW Paste Data