/* eslint-disable no-unused-vars */ const fs = require('fs'); const path = require('path'); const axios = require('axios'); const Sockette = require('sockette'); const { webFrame, ipcRenderer, shell } = require('electron'); const io = require('socket.io-client'); const GoogleTTS = require('node-google-tts-api'); const tts = new GoogleTTS(); const { Socket } = require('socket.io-client'); const main = ipcRenderer.sendSync('environment'); const resourcesPath = main.resourcesPath; const settingsPath = main.settingsPath.toString(); const pythonPath = main.pythonPath.toString(); const settings = main.settings; // TODO: remove gooogle voices txt and use api instead const googleVoices = fs.readFileSync(path.join(__dirname, './config/googleVoices.txt')).toString().split('\r\n'); // TODO: remove amazon voices txt and use api instead (sakura project has it) const amazonVoices = fs.readFileSync(path.join(__dirname, './config/amazonVoices.txt')).toString().split('\r\n'); const customEmotesListSavePath = main.isPackaged === true ? path.join(resourcesPath, './custom-emotes.json') : path.join(resourcesPath, './config/custom-emotes.json'); // html elements const root = document.documentElement; const ttsSelector = document.body.querySelector('#TTSSelector'); const amazonVoiceSelect = document.querySelector('#amazonVoice'); // obtain the html reference of the amazon voices comboBox const notificationAudioDevices = document.querySelector('#notificationAudioDevice'); // obtain the html reference of the installedTTS comboBox const devicesDropdown = document.querySelector('#devicesDropdown'); const notificationSound = document.querySelector('#notification'); // obtain the html reference of the sound comboBox const sttModel = document.querySelector('#sttModel'); // obtain the html reference of the sound comboBox const ttsAudioDevices = document.querySelector('#ttsAudioDevice'); // obtain the html reference of the installedTTS comboBox const notificationSoundAudioDevices = document.querySelector('#notificationSoundAudioDevice'); // obtain the html reference of the installedTTS comboBox const emojiPicker = document.body.querySelector('emoji-picker'); const lol = document.body.querySelector('country-flag-emoji-polyfill'); // laod local javascript files const chat = require(path.join(__dirname, './js/chat')); const messageTemplates = require(path.join(__dirname, './js/messageTemplates')); const languageObject = require(path.join(__dirname, './js/languages')); const logger = require(path.join(__dirname, './js/logger')); const sound = require(path.join(__dirname, './js/sound')); const config = require(path.join(__dirname, './js/settings')); const { TokenAutocomplete } = require(path.join(__dirname, './js/token-autocomplete')); const betterTTVAutocomplete = new TokenAutocomplete({ name: 'sample', selector: '#sample', noMatchesText: 'No matching results...', initialTokens: [...settings.TWITCH.BETTERTTV_CHANNELS] }); const test = settings.TWITCH.BETTERTTV_CHANNELS; console.log(test); const mediaDevices = require(path.join(__dirname, './js/mediaDevices')); const notificationSounds = path.join(resourcesPath, main.isPackaged ? './sounds/notifications' : '../sounds/notifications'); const sttModels = path.join(resourcesPath, main.isPackaged ? './speech_to_text_models' : '../speech_to_text_models'); function reset() { ipcRenderer.send('restart'); } const server = require(path.join(__dirname, './js/server')); const backend = require(path.join(__dirname, './js/backend')); const socket = io(`http://localhost:${settings.GENERAL.PORT}`); // Connect to your Socket.IO server let twitch = null; twitch = settings.TWITCH.USE_TWITCH ? require(path.join(__dirname, './js/twitch')) : ''; let dlive = null; dlive = settings.DLIVE.USE_DLIVE ? require(path.join(__dirname, './js/dlive')) : ''; let youtube = null; youtube = settings.YOUTUBE.USE_YOUTUBE ? require(path.join(__dirname, './js/youtube')) : ''; let trovo = null; trovo = settings.TROVO.USE_TROVO ? require(path.join(__dirname, './js/trovo')) : ''; const Polly = settings.AMAZON.USE_AMAZON ? require(path.join(__dirname, './js/amazon')) : ''; const google = settings.GOOGLE.USE_GOOGLE ? require(path.join(__dirname, './js/google')) : ''; const theme = require(path.join(__dirname, './js/theme')); const auth = require(path.join(__dirname, './js/auth')); let ttsRequestCount = 0; ttsRequestCount = 0; let customEmojis = []; customEmojis = []; let messageId = 0; messageId = 0; let customEmojiList = []; // initialize values config.getGeneralSettings(); const TTSVolume = 1; const notificationSoundVolume = 1; const StartDateAndTime = Date.now(); const speakButton = document.querySelector('#speakBtn'); const amazonCredentials = { accessKeyId: settings.AMAZON.ACCESS_KEY, secretAccessKey: settings.AMAZON.ACCESS_SECRET }; // Check for installed sounds fs.readdir(notificationSounds, (err, files) => { if (err) { console.error(err); } files.forEach((file, i) => { // Create a new option element. const option = document.createElement('option'); // Set the options value and text. option.value = i; option.innerHTML = file; // Add the option to the sound selector. notificationSound.appendChild(option); }); // set the saved notification sound notificationSound.selectedIndex = settings.AUDIO.NOTIFICATION_SOUND; }); // Check for installed stt models fs.readdir(sttModels, (err, files) => { if (err) { console.error(err); } for (const file of files) { if (file.includes('.txt')) { continue; } // Create a new option element. const option = document.createElement('option'); // Set the options value and text. option.value = file; option.innerHTML = file; // Add the option to the sound selector. sttModel.appendChild(option); } // set the saved notification sound sttModel.value = settings.STT.LANGUAGE; }); // TODO: refactor obtaining audio devices. async function getAudioDevices() { if (!navigator.mediaDevices || !navigator.mediaDevices.enumerateDevices) { return; } const devices = await navigator.mediaDevices.enumerateDevices(); const audioOutputDevices = devices.filter(device => device.kind === 'audiooutput'); audioOutputDevices.forEach(device => { const option1 = document.createElement('option'); const option2 = document.createElement('option'); option1.text = device.label || `Output ${device.deviceId}`; option2.text = device.label || `Output ${device.deviceId}`; option1.value = device.deviceId; option2.value = device.deviceId; ttsAudioDevices.appendChild(option1); notificationSoundAudioDevices.appendChild(option2); }); ttsAudioDevices.selectedIndex = settings.AUDIO.SELECTED_TTS_AUDIO_DEVICE; notificationSoundAudioDevices.selectedIndex = settings.AUDIO.SELECTED_NOTIFICATION_AUDIO_DEVICE; } getAudioDevices(); function setSelectedLanguageinSelect(languageSelect, language) { const button = languageSelect.querySelector('.SmallButton'); const languageElement = document.createElement('span'); languageElement.classList = `fi fi-${language.ISO3166} fis pop-selection`; languageElement.setAttribute('tip', language.name); button.innerHTML = ''; button.appendChild(languageElement); addSingleTooltip(languageElement); } function setLanguagesinSelectx(languageSelector, language) { const languageSelect = document.querySelector(languageSelector); // obtain the html reference of the google voices comboBox const languageSelectContent = languageSelect.querySelector('.pop-content'); languageSelectContent.addEventListener('click', e => { const parent = e.target.parentElement.id; language = getLanguageProperties(e.target.getAttribute('value')); if (parent === 'SEND_TRANSLATION_IN') { settings.LANGUAGE.SEND_TRANSLATION_IN = language.IETF; } else { settings.LANGUAGE.SEND_TRANSLATION_OUT = language.IETF; } fs.writeFileSync(settingsPath, JSON.stringify(settings)); setSelectedLanguageinSelect(languageSelect, language); }); for (const language in languageObject.languages) { if (Object.prototype.hasOwnProperty.call(languageObject.languages, language)) { const IETF = languageObject.languages[language].IETF; const ISO639 = languageObject.languages[language].ISO639; const ISO3166 = languageObject.languages[language].ISO3166; const option = document.createElement('div'); option.classList = 'language-select'; const languageElement = document.createElement('span'); languageElement.classList = `fi fi-${ISO3166} fis`; languageElement.style.pointerEvents = 'none'; option.setAttribute('tip', language); const text = document.createElement('span'); text.style.pointerEvents = 'none'; text.innerHTML = ` - ${ISO639}`; option.setAttribute('value', IETF); languageSelectContent.appendChild(option); option.appendChild(languageElement); option.appendChild(text); addSingleTooltip(option); } } setSelectedLanguageinSelect(languageSelect, language); } setLanguagesinSelectx('.pop.in', getLanguageProperties(settings.LANGUAGE.SEND_TRANSLATION_IN)); setLanguagesinSelectx('.pop.out', getLanguageProperties(settings.LANGUAGE.SEND_TRANSLATION_OUT)); function setLanguagesinSelect(languageSelector, setting) { const languageSelect = document.querySelector(languageSelector); // obtain the html reference of the google voices comboBox for (const language in languageObject.languages) { if (Object.prototype.hasOwnProperty.call(languageObject.languages, language)) { const IETF = languageObject.languages[language].IETF; const ISO639 = languageObject.languages[language].ISO639; const option = document.createElement('option'); option.value = IETF; option.innerHTML = `${ISO639} : ${language}`; languageSelect.appendChild(option); } } languageSelect.selectedIndex = setting; } setLanguagesinSelect('#language', settings.GENERAL.LANGUAGE_INDEX); setLanguagesinSelect('#defaultLanguage', settings.TTS.PRIMARY_TTS_LANGUAGE_INDEX); setLanguagesinSelect('#secondaryLanguage', settings.TTS.SECONDARY_TTS_LANGUAGE_INDEX); setLanguagesinSelect('#TRANSLATE_TO', settings.LANGUAGE.TRANSLATE_TO_INDEX); function addVoiceService(name) { function addToselect(select) { const ttsService = document.querySelector(select); const option = document.createElement('option'); ttsService.appendChild(option); option.value = name; option.innerHTML = name; } addToselect('#primaryTTSService'); addToselect('#secondaryTTSService'); } function determineTootlTipPosition(element) { const horizontal = document.body.clientWidth / 2; const vertical = document.body.clientHeight / 2; element.tip.style.left = `${element.mouse.x}px`; element.tip.style.top = `${element.mouse.y}px`; const tipPosition = element.tip.getBoundingClientRect(); if (element.position.x < horizontal && element.position.y < vertical) { element.tip.style.top = `${parseInt(element.tip.style.top) + 25}px`; element.tip.style.left = `${parseInt(element.tip.style.left) + 10}px`; } if (element.position.x < horizontal && element.position.y > vertical) { element.tip.style.top = `${parseInt(element.tip.style.top) - tipPosition.height}px`; element.tip.style.left = `${parseInt(element.tip.style.left) + 10}px`; } if (element.position.x > horizontal && element.position.y < vertical) { element.tip.style.top = `${parseInt(element.tip.style.top) + 25}px`; element.tip.style.left = `${parseInt(element.tip.style.left) - tipPosition.width}px`; } if (element.position.x > horizontal && element.position.y > vertical) { element.tip.style.top = `${parseInt(element.tip.style.top) - tipPosition.height}px`; element.tip.style.left = `${parseInt(element.tip.style.left) - tipPosition.width}px`; } element.tip.style.visibility = 'visible'; } // Small tooltip function addSingleTooltip(el) { const tip = document.createElement('div'); const body = document.querySelector('.container'); const element = el; tip.classList.add('tooltip'); tip.innerText = el.getAttribute('tip'); if (el.src) { const image = document.createElement('img'); image.src = el.src; tip.appendChild(image); } body.appendChild(tip); tip.pointerEvents = 'none'; element.onmousemove = e => { determineTootlTipPosition({ position: element.getBoundingClientRect(), mouse: { x: e.x, y: e.y }, tip }); }; element.onmouseleave = e => { tip.style.visibility = 'hidden'; }; } Array.from(document.body.querySelectorAll('[tip]')).forEach(el => { addSingleTooltip(el); }); function showChatMessage(article) { let body = null; if (article !== undefined) { body = document.getElementById('chatBox'); body.appendChild(article); } const messages = document.body.querySelectorAll('.msg-container'); const lastMessage = messages[messages.length - 1]; lastMessage.scrollIntoView({ block: 'end', behavior: 'smooth' }); // const messageId = article.id; // languageElement.setAttribute('id', article.id); // console.log(article); const username = article.querySelector('.username').innerHTML; const image = article.querySelector('.user-img').src; const statusCircle = article.querySelector('.status-circle').src; const message = article.querySelector('.msg-box').innerHTML; const postTime = article.querySelector('.post-time').innerHTML; socket.emit('chat-out', { messageId, username, image, statusCircle, message, postTime }); } function getPostTime() { const date = new Date(); document.body.querySelectorAll('.container').innerHTML = date.getHours(); const hours = date.getHours(); const ampm = hours >= 12 ? 'PM' : 'AM'; const minutes = (date.getMinutes() < 10 ? '0' : '') + date.getMinutes(); const time = `${hours}:${minutes} ${ampm}`; return time; } function showPreviewChatMessage() { const message = messageTemplates.messageTemplate; document.querySelector('#mini-mid').innerHTML += message; const messages = Array.from(document.body.querySelectorAll('#mini-mid')); const lastMessage = messages[messages.length - 1]; lastMessage.scrollIntoView({ behavior: 'smooth' }); } showPreviewChatMessage(); function hideText(button, field) { document.body.querySelector(button).addEventListener('click', () => { const passwordInput = document.querySelector(field); if (passwordInput.type === 'password') { passwordInput.type = 'lol'; } else { passwordInput.type = 'password'; } }); } hideText('.password-toggle-btn1', '#TWITCH_OAUTH_TOKEN'); hideText('.password-toggle-btn2', '#TROVO_OAUTH_TOKEN'); hideText('.password-toggle-btn4', '#AMAZON_ACCESS_KEY'); hideText('.password-toggle-btn5', '#AMAZON_ACCESS_SECRET'); hideText('.password-toggle-btn6', '#GOOGLE_API_KEY'); function setZoomLevel(currentZoom, zoomIn) { let newZoom = currentZoom.toFixed(2); if (zoomIn === true && currentZoom < 4.95) { newZoom = (currentZoom + 0.05).toFixed(2); } if (zoomIn === false && currentZoom > 0.25) { newZoom = (currentZoom - 0.05).toFixed(2); } webFrame.setZoomFactor(parseFloat(newZoom)); settings.GENERAL.ZOOMLEVEL = newZoom; fs.writeFileSync(settingsPath, JSON.stringify(settings)); document.body.querySelector('#ZOOMLEVEL').value = (settings.GENERAL.ZOOMLEVEL * 100).toFixed(0); } function getLanguageProperties(languageToDetect) { try { const filteredLanguage = Object.keys(languageObject.languages).reduce(function (accumulator, currentValue) { if ( languageObject.languages[currentValue].IETF === languageToDetect || languageObject.languages[currentValue].ISO639 === languageToDetect || languageObject.languages[currentValue].ISO3166 === languageToDetect ) { accumulator[currentValue] = languageObject.languages[currentValue]; } return accumulator; }, {}); const language = { name: Object.getOwnPropertyNames(filteredLanguage)[0], ISO3166: filteredLanguage[Object.keys(filteredLanguage)[0]].ISO3166, ISO639: filteredLanguage[Object.keys(filteredLanguage)[0]].ISO639, IETF: filteredLanguage[Object.keys(filteredLanguage)[0]].IETF }; return language; } catch (e) { // console.error(error); return 'error'; } } let customEmotes = null; if (fs.existsSync(customEmotesListSavePath)) { const file = fs.readFileSync(customEmotesListSavePath); customEmotes = JSON.parse(file); customEmojiList = [...customEmojiList, ...customEmotes]; } emojiPicker.customEmoji = customEmojiList; function saveCustomEmotesToFile(emotes) { const data = JSON.stringify(emotes); customEmojiList = [...customEmojiList, data]; const savePath = main.isPackaged === true ? path.join(resourcesPath, './custom-emotes.json') : path.join(resourcesPath, './config/custom-emotes.json'); fs.writeFile(savePath, data, error => { if (error) { console.error(error); throw error; } }); } function countWords(str) { return str.trim().split(/\s+/).length; } // function saveSettingsToFile(settings) { // const data = JSON.stringify(settings); // const savePath = // main.isPackaged === true ? path.join(resourcesPath, './settings.json') : path.join(resourcesPath, './config/settings.json'); // fs.writeFile(savePath, data, error => { // if (error) { // console.error(error); // throw error; // } // }); // } /* Copyright 2017 Google Inc. Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance with the License. You may obtain a copy of the License at http://www.apache.org/licenses/LICENSE-2.0 Unless required by applicable law or agreed to in writing, software distributed under the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the License for the specific language governing permissions and limitations under the License. */ // var videoElement = document.querySelector('video'); // var audioSelect = document.querySelector('select#audioSource'); // var videoSelect = document.querySelector('select#videoSource'); // audioSelect.onchange = getStream; // videoSelect.onchange = getStream; // getStream().then(getDevices).then(gotDevices); // function getDevices() { // // AFAICT in Safari this only gets default devices until gUM is called :/ // return navigator.mediaDevices.enumerateDevices(); // } // function gotDevices(deviceInfos) { // window.deviceInfos = deviceInfos; // make available to console // console.log('Available input and output devices:', deviceInfos); // for (const deviceInfo of deviceInfos) { // const option = document.createElement('option'); // option.value = deviceInfo.deviceId; // if (deviceInfo.kind === 'audioinput') { // option.text = deviceInfo.label || `Microphone ${audioSelect.length + 1}`; // audioSelect.appendChild(option); // } else if (deviceInfo.kind === 'videoinput') { // option.text = deviceInfo.label || `Camera ${videoSelect.length + 1}`; // videoSelect.appendChild(option); // } // } // } // function getStream() { // if (window.stream) { // window.stream.getTracks().forEach(track => { // track.stop(); // }); // } // const audioSource = audioSelect.value; // const videoSource = videoSelect.value; // const constraints = { // audio: { deviceId: audioSource ? { exact: audioSource } : undefined }, // video: { deviceId: videoSource ? { exact: videoSource } : undefined } // }; // return navigator.mediaDevices.getUserMedia(constraints).then(gotStream).catch(handleError); // } // function gotStream(stream) { // window.stream = stream; // make stream available to console // audioSelect.selectedIndex = [...audioSelect.options].findIndex(option => option.text === stream.getAudioTracks()[0].label); // videoSelect.selectedIndex = [...videoSelect.options].findIndex(option => option.text === stream.getVideoTracks()[0].label); // videoElement.srcObject = stream; // } // function handleError(error) { // console.error('Error: ', error); // } // const settingxs = { // video: true // }; // navigator.mediaDevices // .getUserMedia(settingxs) // .then(stream => { // const video = document.getElementById('video'); // video.srcObject = stream; // video.play(); // }) // .catch(err => { // console.log(err); // alert('Não há permissões para acessar a webcam.'); // });