LennardTFD

Untitled

Aug 16th, 2020
57
0
Never
Not a member of Pastebin yet? Sign Up, it unlocks many cool features!
  1. // ==UserScript==
  2. // @name         Chatter to Speech
  3. // @namespace    https://www.leitstellenspiel.de/
  4. // @version      1.7
  5. // @description  Einsatzfunk zu Sprache
  6. // @author       LennardTFD
  7. // @match        https://www.leitstellenspiel.de/
  8. // @match        https://www.missionchief.com/
  9. // @match        https://www.meldkamerspel.com/
  10. // @updateURL    https://github.com/LennardTFD/LeitstellenspielScripte/raw/master/LSS_ChatterToSpeech/chatterToSpeech.user.js
  11. // @downloadURL  https://github.com/LennardTFD/LeitstellenspielScripte/raw/master/LSS_ChatterToSpeech/chatterToSpeech.user.js
  12. // @grant        none
  13. // ==/UserScript==
  14.  
  15. var SIREN_URL = "MYAUDIOURL";
  16. //Deaktiviert Sound Ausgabe für Status. Beispiel: [1, 2, 3, 4]
  17. var DISABLECHATTERFORSTATUS = [];
  18. var translationLanguage = ""; //Empty, IT
  19.  
  20. //VOICES CHROME
  21. // 1 = English Male
  22. // 2 = English Female
  23. // 3 = German Female
  24. // 4 = English Female
  25. // 5 = English Female UK
  26. // 15 = Dutch Female
  27. //Get Current Page and select Language for Chatter
  28. var url = window.location.host;
  29. var lang = "";
  30. switch(url)
  31. {
  32.     case "www.leitstellenspiel.de":
  33.         lang = "de-DE";
  34.         break;
  35.     case "www.missionchief.com":
  36.         lang = "en-US";
  37.         break;
  38.     case "www.missionchief.co.uk":
  39.         lang = "en-GB";
  40.         break;
  41.     case "www.meldkamerspel.com":
  42.         lang = "nl-NL";
  43.         break;
  44.     case "www.operatorratunkowy.pl":
  45.         lang = "pl-PL";
  46.         break;
  47.     default:
  48.         lang = "en-US";
  49.         break;
  50. }
  51.  
  52. async function getTranslations()
  53. {
  54.     return new Promise(resolve => {
  55.         $.ajax({
  56.             url: "https://raw.githubusercontent.com/LennardTFD/LeitstellenspielScripte/master/LSS_ChatterToSpeech/translations.json",
  57.             method: "GET",
  58.         }).done((res) => {
  59.             console.log("Got Data!");
  60.             resolve(JSON.parse(res));
  61.         });
  62.     });
  63. }
  64.  
  65. let translations;
  66. async function init() {
  67.     if(translationLanguage != "")
  68.     {
  69.         translations = await getTranslations();
  70.     }
  71. }
  72.  
  73. init();
  74.  
  75. //Import background siren
  76. $("body").append('<audio loop="false" width="0" height="0" id="sound" src="' + SIREN_URL + '" type="audio/mp3" ></audio>');
  77.  
  78.  
  79. //Words which need corrected pronunciation
  80. var wordsToPronounce = [
  81.     ["RTW", "R T W"], ["NEF", "N E F"], ["BNAW", "Baby N A W"], ["NAW", "N A W "], ["KTW", "K T W "], ["OrgL", "Org L "], ["GRTW", "G R T W"],
  82.  
  83.     ["ELW", "E L W "], ["DLK", "D L K "], ["HLF", "H L F "], ["LF", "L F "], ["TLF", " T L F "], ["KatS", " Kat Schutz "],
  84.     ["AnH", " Anhänger "], ["DekonP", "Dekon P "], ["GW", "G W "], ["WLF", "W L F "], ["AB", "A B"], ["MTF", "M T F"], ["MTW", "M T W"],
  85.  
  86.     ["RTB", "R T B"], ["MZB", "M Z B"],
  87.     ["FuStW", "Funkstreife "], ["GruKw", "Gru K W "],
  88.  
  89.     ["Brandmeldeanlage", "B M A "], ["KH", ""]
  90. ];
  91.  
  92. //Phrases to randomly use for diffrent Status
  93. /*
  94. var phrases = {
  95.     "0": ["Blitz, Blitz, Blitz. Notruf von %UNIT%", "Notruf von %UNIT%", "%UNIT% Notruf", "Unterstützung zu %UNIT%", "Unterstützung zu %ADDRESS%!"],
  96.     "1": ["Hier %UNIT%. Wir rücken ein", "%UNIT% Status 1", "%UNIT% rückt ein", "%UNIT% sind auf dem Weg zur Wache", "%UNIT%. Einsatzstelle übergeben. Alle Einheiten können einrücken", "%UNIT%. Einsatz beendet", "%UNIT% Einsatz beendet. Wir rücken ab", "%UNIT% wieder frei"],
  97.     "2": ["%UNIT% zurück auf Wache", "%UNIT% auf Wache", "%UNIT% in der Fahrzeughalle", "%UNIT% Status 2", "%UNIT% meldet frei auf Wache"],
  98.     "3": ["%UNIT% auf Anfahrt", "%UNIT% rückt aus!", "%UNIT%. Wir rücken aus", "Hier %UNIT%. Wir rollen!", "%UNIT% rollt", "Hier %UNIT%. Wir rücken aus", "%UNIT% auf Anfahrt", "%UNIT% sind auf Anfahrt", "Hier %UNIT%. Sind auf Anfahrt", "%UNIT% Status 3",
  99.         "%UNIT% auf Anfahrt zum Einsatz", "%UNIT% aufgesessen", "%UNIT% zu %ADDRESS%", "%UNIT% auf Anfahrt zu %MISSION%", "%UNIT% fährt zu %MISSION% an %ADDRESS%", "%UNIT% verstanden", "Hier %UNIT%, verstanden", "%UNIT% zu %MISSION% an %ADDRESS%",
  100.         "%UNIT%, %MISSION%, %ADDRESS%", "%ADDRESS%, %UNIT%", "%MISSION% für %UNIT% an %ADDRESS%", "%UNIT%, %ADDRESS%, %MISSION%"],
  101.     "4": ["%UNIT% an Einsatzstelle eingetroffen!", "%UNIT% hat Einsatzstelle erreicht", "%UNIT% Status 4", "%UNIT% . Status wechsel auf die 4", "%UNIT%. Am Einsatzort eingetroffen", "%UNIT% hat %MISSION% erreicht", "%UNIT% an %ADDRESS% angekommen"],
  102.     "5": ["Leitstelle für %UNIT%. Kommen!", "Leitstelle für %UNIT%", "Leitstelle von %UNIT%", "Einmal Leitstelle für %UNIT%", "Sprechwunsch für %UNIT%"],
  103.     "6": ["%UNIT% geht außer Dienst", "%UNIT% nicht einsatzbereit", "%UNIT% nicht besetzt", "%UNIT% kann nicht ausrücken", "%UNIT% unbesetzt", "Wir machen Feierabend. %UNIT%"],
  104.     "7": ["Hier %UNIT%. Mit Sonderrechten ins Krankenhaus", "%UNIT% Status 7", "Hier %UNIT%. Wir wechseln auf Status 7", "Status 7 für %UNIT%", "%UNIT% hat Patienten aufgenommen", "%UNIT% wir fahren zu %BUILDING%",
  105.         "%UNIT% bringt Patienten zu %BUILDING%", "%UNIT% mit Sonderrechten nach %BUILDING%", "%BUILDING% für %UNIT%", "Voranmeldung bei %BUILDING% für %UNIT%"],
  106.     "8": ["Hier %UNIT%. Laden aus", "%UNIT% lädt aus", "%UNIT% Status 8", "Status 8 für %UNIT%"],
  107.     "9": ["%UNIT% wartet auf Abholung", "%UNIT% steht bereit", "%UNIT% kann abgeholt werden", "%UNIT% auf Status 9"]
  108. };
  109. */
  110. var phrases = {
  111.     "de-DE":{
  112.         "0": ["Blitz, Blitz, Blitz. Notruf von %UNIT%", "Notruf von %UNIT%", "%UNIT% Notruf", "Unterstützung zu %UNIT%", "Unterstützung zu %ADDRESS%!"],
  113.         "1": ["Hier %UNIT%. Wir rücken ein", "%UNIT% Status 1", "%UNIT% rückt ein", "%UNIT% sind auf dem Weg zur Wache", "%UNIT%. Einsatzstelle übergeben. Alle Einheiten können einrücken", "%UNIT%. Einsatz beendet", "%UNIT% Einsatz beendet. Wir rücken ab", "%UNIT% wieder frei"],
  114.         "2": ["%UNIT% zurück auf Wache", "%UNIT% auf Wache", "%UNIT% in der Fahrzeughalle", "%UNIT% Status 2", "%UNIT% meldet frei auf Wache"],
  115.         "3": ["%UNIT% auf Anfahrt", "%UNIT% rückt aus!", "%UNIT%. Wir rücken aus", "Hier %UNIT%. Wir rollen!", "%UNIT% rollt", "Hier %UNIT%. Wir rücken aus", "%UNIT% auf Anfahrt", "%UNIT% sind auf Anfahrt", "Hier %UNIT%. Sind auf Anfahrt", "%UNIT% Status 3",
  116.             "%UNIT% auf Anfahrt zum Einsatz", "%UNIT% aufgesessen", "%UNIT% zu %ADDRESS%", "%UNIT% auf Anfahrt zu %MISSION%", "%UNIT% fährt zu %MISSION% an %ADDRESS%", "%UNIT% verstanden", "Hier %UNIT%, verstanden", "%UNIT% zu %MISSION% an %ADDRESS%",
  117.             "%UNIT%, %MISSION%, %ADDRESS%", "%ADDRESS%, %UNIT%", "%MISSION% für %UNIT% an %ADDRESS%", "%UNIT%, %ADDRESS%, %MISSION%"],
  118.         "4": ["%UNIT% an Einsatzstelle eingetroffen!", "%UNIT% hat Einsatzstelle erreicht", "%UNIT% Status 4", "%UNIT% . Status wechsel auf die 4", "%UNIT%. Am Einsatzort eingetroffen", "%UNIT% hat %MISSION% erreicht", "%UNIT% an %ADDRESS% angekommen"],
  119.         "5": ["Leitstelle für %UNIT%. Kommen!", "Leitstelle für %UNIT%", "Leitstelle von %UNIT%", "Einmal Leitstelle für %UNIT%", "Sprechwunsch für %UNIT%"],
  120.         "6": ["%UNIT% geht außer Dienst", "%UNIT% nicht einsatzbereit", "%UNIT% nicht besetzt", "%UNIT% kann nicht ausrücken", "%UNIT% unbesetzt", "Wir machen Feierabend. %UNIT%"],
  121.         "7": ["Hier %UNIT%. Mit Sonderrechten ins Krankenhaus", "%UNIT% Status 7", "Hier %UNIT%. Wir wechseln auf Status 7", "Status 7 für %UNIT%", "%UNIT% hat Patienten aufgenommen", "%UNIT% wir fahren zu %BUILDING%",
  122.             "%UNIT% bringt Patienten zu %BUILDING%", "%UNIT% mit Sonderrechten nach %BUILDING%", "%BUILDING% für %UNIT%", "Voranmeldung bei %BUILDING% für %UNIT%"],
  123.         "8": ["Hier %UNIT%. Laden aus", "%UNIT% lädt aus", "%UNIT% Status 8", "Status 8 für %UNIT%"],
  124.         "9": ["%UNIT% wartet auf Abholung", "%UNIT% steht bereit", "%UNIT% kann abgeholt werden", "%UNIT% auf Status 9"]
  125.     },
  126.     "en-US":{
  127.         "0": ["Mayday! Mayday! Mayday! %UNIT%", "Emergency call %UNIT%", "%UNIT% Status 0", "Reinforcements to %UNIT%", "Reinforcements to %ADDRESS%!"],
  128.         "1": ["Here %UNIT%. Returning to Station", "%UNIT% Status 1", "%UNIT% ending call", "%UNIT% on way back to station", "%UNIT%. Handed over scene. All Units can head back", "%UNIT%. Scene is clear", "%UNIT% Dispatch finished", "%UNIT% available again"],
  129.         "2": ["%UNIT% back on Station", "%UNIT% on Station", "%UNIT% in Garage", "%UNIT% Status 2", "%UNIT% available on Station"],
  130.         "3": ["%UNIT% enroute", "%UNIT% heading out!", "%UNIT% is enroute", "Here %UNIT%. Heading to scene", "%UNIT% on Status 3", "%UNIT% heading to %ADDRESS%", "%UNIT% enroute to %MISSION%",
  131.             "%UNIT% is driving to %MISSION% at %ADDRESS%", "%UNIT% understood", "%UNIT%, copy", "%UNIT% to %MISSION% near %ADDRESS%", "%UNIT%, %MISSION%, %ADDRESS%", "%ADDRESS%, %UNIT%",
  132.             "%MISSION% for %UNIT% at %ADDRESS%", "%UNIT%, %ADDRESS%, %MISSION%"],
  133.         "4": ["%UNIT% arrived!", "%UNIT% on Scene", "%UNIT% Status 4", "%UNIT% . Changing to Status 4", "%UNIT%. We are on Scene", "%UNIT% arrived at %MISSION%", "%UNIT% on %ADDRESS%"],
  134.         "5": ["Dispatch. How copy?", "Dispatch for %UNIT%", "%UNIT% calling Dispatch", "%UNIT% requesting Dispatch"],
  135.         "6": ["%UNIT% out of order", "%UNIT% unavailable", "%UNIT% unoccupied", "%UNIT% no can do!", "%UNIT% on Status 6"],
  136.         "7": ["Here %UNIT%. Heading to hospital", "%UNIT% Status 7", "Here %UNIT%. We are changing to Status 7", "Status 7 for %UNIT%", "%UNIT% picked up patienten", "%UNIT% heading to %BUILDING%",
  137.             "%UNIT% is transporting patient to %BUILDING%", "%UNIT% transporting to %BUILDING%", "%BUILDING% for %UNIT%", "Registration at %BUILDING% for %UNIT%"],
  138.         "8": ["Here %UNIT%. Unloading", "%UNIT% is unloading", "%UNIT% Status 8", "Status 8 for %UNIT%"],
  139.         "9": ["%UNIT% awaiting pickup", "%UNIT% ready for pickup", "%UNIT% can be picked up", "%UNIT% on Status 9"]
  140.     },
  141.     "nl-NL": {
  142.         "0": [""],
  143.         "1": [""],
  144.         "2": [""],
  145.         "4": [""],
  146.         "5": [""],
  147.         "6": [""],
  148.         "7": [""],
  149.         "8": [""],
  150.         "9": [""]
  151.     },
  152.     "pl-PL": {
  153.         "0": [""],
  154.         "1": [""],
  155.         "2": [""],
  156.         "4": [""],
  157.         "5": [""],
  158.         "6": [""],
  159.         "7": [""],
  160.         "8": [""],
  161.         "9": [""]
  162.     }
  163. }
  164.  
  165. ////////////////////////////Duplicating Pharses
  166.  
  167. phrases["en-GB"] = phrases["en-US"];
  168.  
  169. ////////////////////////////////////////////////
  170. //Voices used. Duplicate voice sets increase their frequency
  171. var voices = ["Deutsch Male", "Deutsch Male", "Deutsch Female"];
  172.  
  173. var audio = document.getElementById('sound');
  174. audio.volume = 0.04;
  175. var isSpeaking = false;
  176.  
  177. //Queue of last Status changes
  178. var chatterQueue = [];
  179.  
  180. function chatParser(missionInfo)
  181. {
  182.  
  183.     var unit = missionInfo[0];
  184.     var status = missionInfo[1];
  185.     var address = missionInfo[2];
  186.     var mission = missionInfo[3];
  187.  
  188.  
  189.     if(translationLanguage != "")
  190.     {
  191.         let newMission = translations[lang][translationLanguage][mission];
  192.         if(newMission != undefined)
  193.         {
  194.             mission = newMission;
  195.         }
  196.     }
  197.  
  198.     var building = missionInfo[4];
  199.  
  200.     if(String(parseInt(address)).length == 5)
  201.     {
  202.         //address = address.split(" ");
  203.         //TODO turn 41642 in 41 6 4 2
  204.     }
  205.  
  206.     //Replace unit names with correct pronunciation
  207.     for(var i = 0; i < wordsToPronounce.length; i++)
  208.     {
  209.         unit = unit.replace(wordsToPronounce[i][0], wordsToPronounce[i][1]);
  210.     }
  211.     //removes "/" and "-" from call signs
  212.     unit = unit.replace(/\//gi, "\b");
  213.     unit = unit.replace(/-/gi, "\b");
  214.  
  215.     //Select a random phrase from phrases list depending of Language
  216.     var pharse = phrases[lang][status][Math.floor(Math.random()*phrases[lang][status].length)];
  217.  
  218.     //Replace Unit Wildcard with calling unit
  219.     pharse = pharse.replace("%UNIT%", unit);
  220.  
  221.     //If Status 3 or 4
  222.     if(status == "3" || status == "4")
  223.     {
  224.         //Diese Parameter treffen nur auf Status 3 und 4 Einsätze zu
  225.         //Replace Address wildcard with mission address
  226.         pharse = pharse.replace("%ADDRESS%", address);
  227.     }
  228.     //If Status 7
  229.     else if(status == "7")
  230.     {
  231.         //If no building name is available replace with default value
  232.         if(building == undefined)
  233.         {
  234.             building = "Krankenhaus"
  235.         }
  236.         //Replace Building wildcard with building unit is driving to
  237.         pharse = pharse.replace("%BUILDING%", building);
  238.     }
  239.  
  240.     //Replace mission wildcard with mission name
  241.     pharse = pharse.replace("%MISSION%", mission);
  242.  
  243.     if(status == "3")
  244.     {
  245.         //Play background sound when en route
  246.         if(Math.floor((Math.random() * 2) + 1) == 1)
  247.         {
  248.             startBackground();
  249.         }
  250.     }
  251.  
  252.     return pharse;
  253. }
  254.  
  255.  
  256. function workOffQueue()
  257. {
  258.     //If there are unfinished chatter messages AND there is currently no other speech
  259.     if(chatterQueue.length > 0 && !isSpeaking)
  260.     {
  261.         //Make queue smaller if there is to much old chatter
  262.         if(chatterQueue.length > 10)
  263.         {
  264.             chatterQueue = chatterQueue.splice(0,4);
  265.         }
  266.  
  267.         isSpeaking = true;
  268.         var curr = chatterQueue[0];
  269.         chatter(chatParser(curr));
  270.         chatterQueue.shift();
  271.     }
  272.     //If there is currently chatter
  273.     else if(chatterQueue != 0)
  274.     {
  275.         //retry 1 second later
  276.         setTimeout(workOffQueue, 1000);
  277.     }
  278. }
  279.  
  280.  
  281. function addToQueue(unit, status, address, missionName, buildingName)
  282. {
  283.     //Add new chatter message to working queue
  284.     if(DISABLECHATTERFORSTATUS.includes(parseInt(status))) return;
  285.     chatterQueue.push([unit, status, address, missionName, buildingName]);
  286. }
  287.  
  288. function startBackground()
  289. {
  290.     //Play background Sound
  291.     audio.play();
  292. }
  293. function stopBackground()
  294. {
  295.     //Stop background sound
  296.     audio.pause();
  297.     isSpeaking = false;
  298. }
  299.  
  300. function chatter(msg)
  301. {
  302.     var t2s = new SpeechSynthesisUtterance();
  303.     t2s.text = msg;
  304.     t2s.lang = lang;
  305.  
  306.     var speed = parseFloat((Math.random() * (0.0 - 0.1500) + 0.0200).toFixed(4));
  307.     t2s.rate = 1.2 + speed;
  308.  
  309.     t2s.onend = () => {stopBackground()};
  310.     t2s.onstart = () => {isSpeaking = true;};
  311.  
  312.     //select random speed
  313.  
  314.     //Select random speeker
  315.     var talker = voices[Math.floor(Math.random()*voices.length)];
  316.     //Play chatter Audio
  317.     //responsiveVoice.speak(msg, talker, {rate: (1.2 + speed), onStart: function(){isSpeaking = true}, onend: stopBackground});
  318.     speechSynthesis.speak(t2s);
  319. }
  320.  
  321. var mutationObserver = new MutationObserver(function(mutations) {
  322.     mutations.forEach(function(mutation) {
  323.  
  324.         var node = mutation.addedNodes[0];
  325.         if(node == undefined)
  326.         {
  327.             return;
  328.         }
  329.         //Dont play sound if chatter comes from alliance
  330.         var aliance = $(node).attr("class");
  331.         if(aliance.includes("radio_message_alliance"))
  332.         {
  333.             return;
  334.         }
  335.         //Select Status from new chatter message
  336.         var status = $(node).find("span").html();
  337.         //select calling unit
  338.         var unit = $(node).find("[href^='/vehicles/']").html();
  339.  
  340.         var missionName = undefined;
  341.         var missionAddress = undefined;
  342.         var buildingName = undefined;
  343.  
  344.         switch(status)
  345.         {
  346.             //If status 3 or 4
  347.             case "3":
  348.             case "4":
  349.                 //Get Mission reference
  350.                 var missionId = ($(node).find("[href^='/missions/']")[0].href).split("/missions/")[1];
  351.                 var missionInList = $("#missions-panel-body").find("[href*='" + missionId + "']");
  352.                 var missionData = missionInList.parent().find(".map_position_mover");
  353.                 //Grab Mission Name
  354.                 missionName = (missionData.html()).split(",")[0];
  355.                 if(missionName.includes("</small>"))
  356.                 {
  357.                     var occ = missionName.indexOf("</small>");
  358.                     missionName = missionName.slice(occ + 9, missionName.length - 1);
  359.                     //Grab Mission Address
  360.                     missionAddress = (missionData.find("small:eq(1)").html()).split(",")[0];
  361.                 }
  362.                 else
  363.                 {
  364.                     //Grab Mission Address
  365.                     missionAddress = (missionData.find("small").html()).split(",")[0];
  366.                 }
  367.  
  368.  
  369.                 //console.log(unit + ": " + missionName + " | " + missionAddress);
  370.                 break;
  371.             //If Status 7
  372.             case "7":
  373.                 //Grab building name
  374.                 buildingName = $(node).find("[href^='/buildings/']").html();
  375.                 //console.log("!!!!!!STATUS 7!!!!! BUILDING: " + buildingName);
  376.                 break;
  377.         }
  378.         //console.log(status + " | " + unit);
  379.         //If is real chatter
  380.         if(unit != undefined && status != undefined)
  381.         {
  382.             //Add new chatter to queue
  383.             addToQueue(unit, status, missionAddress, missionName, buildingName);
  384.             //Start working on queue
  385.             workOffQueue();
  386.         }
  387.  
  388.     });
  389. });
  390.  
  391. //Listen for new Incomming Status updates
  392. mutationObserver.observe($("#radio_messages")[0], {
  393.     childList: true
  394. });
  395. //Listen for new FMS5 and similars
  396. mutationObserver.observe($("#radio_messages_important")[0], {
  397.     childList: true
  398. });
  399.  
Add Comment
Please, Sign In to add comment