Pendrokar commited on
Commit
e1a50fc
β€’
1 Parent(s): 3a99466

verbose xvaserver startup

Browse files
app.py CHANGED
@@ -8,13 +8,13 @@ import threading
8
  import gradio as gr
9
 
10
  def run_xvaserver():
11
- try:
12
- # start the process without waiting for a response
13
- print('Running xVAServer subprocess...\n')
14
- xvaserver = Popen(['python', 'resources/app/server.py'], stdout=PIPE, stderr=PIPE, universal_newlines=True)
15
- except:
16
- print('Could not run xVASynth.')
17
- sys.exit(0)
18
 
19
  # Wait for a moment to ensure the server starts up
20
  time.sleep(10)
@@ -64,11 +64,11 @@ def load_model():
64
  # model_json_path = hf_hub_download(repo_id=model_name, filename="ccby_nvidia_hifi_6670_M.json")
65
  model_path = '/tmp/hfcache/models--Pendrokar--xvapitch_nvidia_6670/snapshots/2e138a7c459fb1cb1182dd7bc66813f5325d30fd/ccby_nvidia_hifi_6670_M.pt'
66
  model_json_path = '/tmp/hfcache/models--Pendrokar--xvapitch_nvidia_6670/snapshots/2e138a7c459fb1cb1182dd7bc66813f5325d30fd/ccby_nvidia_hifi_6670_M.json'
67
- try:
68
- os.symlink(model_path, os.path.join('./models/ccby/', os.path.basename(model_path)))
69
- os.symlink(model_json_path, os.path.join('./models/ccby/', os.path.basename(model_json_path)))
70
- except:
71
- print('Failed creating symlinks, they probably already exist')
72
 
73
  model_type = 'xVAPitch'
74
  language = 'en'
 
8
  import gradio as gr
9
 
10
  def run_xvaserver():
11
+ # try:
12
+ # start the process without waiting for a response
13
+ print('Running xVAServer subprocess...\n')
14
+ xvaserver = Popen(['python', 'resources/app/server.py'], stdout=PIPE, stderr=PIPE, universal_newlines=True)
15
+ # except:
16
+ # print('Could not run xVASynth.')
17
+ # sys.exit(0)
18
 
19
  # Wait for a moment to ensure the server starts up
20
  time.sleep(10)
 
64
  # model_json_path = hf_hub_download(repo_id=model_name, filename="ccby_nvidia_hifi_6670_M.json")
65
  model_path = '/tmp/hfcache/models--Pendrokar--xvapitch_nvidia_6670/snapshots/2e138a7c459fb1cb1182dd7bc66813f5325d30fd/ccby_nvidia_hifi_6670_M.pt'
66
  model_json_path = '/tmp/hfcache/models--Pendrokar--xvapitch_nvidia_6670/snapshots/2e138a7c459fb1cb1182dd7bc66813f5325d30fd/ccby_nvidia_hifi_6670_M.json'
67
+ # try:
68
+ # os.symlink(model_path, os.path.join('./models/ccby/', os.path.basename(model_path)))
69
+ # os.symlink(model_json_path, os.path.join('./models/ccby/', os.path.basename(model_json_path)))
70
+ # except:
71
+ # print('Failed creating symlinks, they probably already exist')
72
 
73
  model_type = 'xVAPitch'
74
  language = 'en'
index.html β†’ resources/app/index.html RENAMED
@@ -24,28 +24,8 @@
24
  <body>
25
  <div id="chromeBar">
26
  <div id="dragBar">xVA Synth</div>
27
- <div id="chromeActions">
28
- <div id="chromeMin">&#x1F5D5;</div>
29
- <div id="chromeMax">&#128470;</div>
30
- <div id="chromeQuit">&#x2716;</div>
31
- </div>
32
  </div>
33
  <div id="appcontent">
34
- <div id="left">
35
- <div class="top" id="topLeft">
36
- <div id="selectedGameDisplay">Select game</div>
37
- <button id="changeGameButton">&#8644;</button>
38
- </div>
39
- <div id="searchContainer">
40
- <input type="text" id="voiceSearchInput" name="" placeholder="Search voices...">
41
- </div>
42
- <div class="content">
43
- <div id="voiceTypeContainer" style="height: calc(95vh - 107px)"></div>
44
- <div style="height: 35px;width: 100%;display: flex;justify-content: center;">
45
- <button id="nexusMenuButton" class="invertedButton" style="width: 280px;max-width: 300px;">Get more voices</button>
46
- </div>
47
- </div>
48
- </div>
49
  <div id="right">
50
  <div id="rightBG1"></div>
51
  <div id="rightBG2"></div>
@@ -270,7 +250,6 @@
270
  </div>
271
  </div>
272
 
273
- </div>
274
  <div id="settingsContainer" style="display:none">
275
  <div class="modal" style="height: 75vh;width: 60vw">
276
  <h2 id="i18n_settings" style="margin-bottom: 0;">Settings</h2>
@@ -1699,7 +1678,7 @@
1699
  </div>
1700
  </div>
1701
 
1702
- <div id="workbenchIcon" title="Workbench">
1703
  <svg version="1.0" xmlns="http://www.w3.org/2000/svg"
1704
  width="512.000000pt" height="512.000000pt" viewBox="0 0 512.000000 512.000000"
1705
  preserveAspectRatio="xMidYMid meet">
@@ -1724,14 +1703,13 @@
1724
  </g>
1725
  </svg>
1726
  </div>
1727
-
1728
- <div id="arpabetIcon" title="ARPAbet">
1729
  <svg width="30" height="25" version="1.1" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" width="400" height="291.8918918918919" viewBox="0, 0, 400,291.8918918918919"><g id="svgg"><path id="path0" d="M72.973 27.879 C 32.451 42.782,17.396 97.297,53.802 97.297 C 79.544 97.297,91.701 72.242,74.370 54.910 C 57.283 37.823,127.302 30.250,150.720 46.652 C 165.423 56.951,178.378 85.094,178.378 106.737 C 178.378 121.690,177.667 122.026,133.043 128.111 C 63.835 137.548,24.390 162.533,18.168 200.875 C 8.105 262.887,127.891 288.561,186.634 236.983 L 205.405 220.502 224.177 236.983 C 279.158 285.258,383.632 260.162,383.764 198.649 C 383.794 184.437,374.252 187.264,365.517 204.054 C 328.367 275.463,232.983 251.601,219.541 167.536 C 214.378 135.247,214.669 135.135,303.691 135.135 L 385.122 135.135 382.638 105.181 C 376.173 27.218,271.272 -9.201,219.131 48.414 C 210.152 58.336,209.281 58.158,185.830 41.628 C 158.995 22.713,104.930 16.127,72.973 27.879 M326.220 52.019 C 339.715 65.513,351.256 94.410,351.321 114.865 C 351.348 123.350,344.670 124.324,286.486 124.324 L 221.622 124.324 221.649 109.459 C 221.751 55.079,291.156 16.954,326.220 52.019 M180.884 170.569 C 188.274 229.709,123.639 272.474,79.427 237.697 C 33.938 201.915,81.663 142.798,157.485 141.005 L 177.133 140.541 180.884 170.569 " stroke="none" fill="#ffffff" fill-rule="evenodd"></path></g></svg>
1730
  </div>
1731
- <div id="embeddingsIcon" title="Embeddings visualiser">
1732
  <svg width="25" height="25" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" viewBox="0, 0, 400,400"><g id="svgg"><path id="path0" d="M150.000 20.230 C 65.534 26.594,5.904 105.137,22.679 187.932 C 41.869 282.642,149.542 329.959,232.409 280.098 L 237.105 277.272 288.552 328.719 L 340.000 380.166 360.083 360.083 L 380.166 340.000 328.719 288.552 L 277.272 237.105 280.098 232.409 C 316.949 171.163,301.885 92.110,245.067 48.568 C 218.394 28.128,183.443 17.709,150.000 20.230 M166.667 70.498 C 215.683 73.046,254.682 119.552,249.348 169.093 C 244.601 213.185,208.627 247.470,164.854 249.622 C 102.308 252.696,55.953 193.244,74.215 133.374 C 85.585 96.097,124.114 68.164,161.333 70.215 C 162.342 70.271,164.742 70.398,166.667 70.498 " stroke="none" fill="#ffffff" fill-rule="evenodd"></path></g></svg>
1733
  </div>
1734
- <div id="pluginsIcon" title="Plugins">
1735
  <svg width="25" height="25" xmlns:xlink="http://www.w3.org/1999/xlink" xmlns="http://www.w3.org/2000/svg" fill-opacity="1" color-rendering="auto" color-interpolation="auto" text-rendering="auto" stroke="white" stroke-linecap="square" stroke-miterlimit="10" shape-rendering="auto" stroke-opacity="1" fill="#ffffff" stroke-dasharray="none" font-weight="normal" stroke-width="1" font-family="'Dialog'" font-style="normal" stroke-linejoin="miter" font-size="12" stroke-dashoffset="0" image-rendering="auto" viewBox="0, 150, 300, 250">
1736
  <defs id="genericDefs"/>
1737
  <g>
@@ -1741,10 +1719,10 @@
1741
  </g>
1742
  </svg>
1743
  </div>
1744
- <div id="batchIcon" title="Batch mode">
1745
  <svg id="batchSVGIcon" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" width="25" height="25" viewBox="0, 0, 400,310.24930747922434"><g id="svgg"><path id="path0" d="M5.549 99.446 C 5.515 149.266,5.829 215.831,6.246 247.368 L 7.004 304.709 198.516 304.709 L 390.028 304.709 390.028 157.523 L 390.028 10.338 282.825 9.602 C 223.864 9.197,137.371 8.865,90.617 8.865 L 5.611 8.864 5.549 99.446 M107.479 67.590 L 107.479 97.507 70.914 97.507 L 34.349 97.507 34.349 67.590 L 34.349 37.673 70.914 37.673 L 107.479 37.673 107.479 67.590 M362.327 67.590 L 362.327 97.507 249.307 97.507 L 136.288 97.507 136.288 67.590 L 136.288 37.673 249.307 37.673 L 362.327 37.673 362.327 67.590 M107.479 157.341 L 107.479 187.258 70.914 187.258 L 34.349 187.258 34.349 157.341 L 34.349 127.424 70.914 127.424 L 107.479 127.424 107.479 157.341 M362.327 157.341 L 362.327 187.258 249.307 187.258 L 136.288 187.258 136.288 157.341 L 136.288 127.424 249.307 127.424 L 362.327 127.424 362.327 157.341 M107.479 247.091 L 107.479 277.008 70.914 277.008 L 34.349 277.008 34.349 247.091 L 34.349 217.175 70.914 217.175 L 107.479 217.175 107.479 247.091 M362.327 247.091 L 362.327 277.008 249.307 277.008 L 136.288 277.008 136.294 257.895 C 136.297 247.382,136.621 233.920,137.015 227.978 L 137.730 217.175 250.029 217.175 L 362.327 217.175 362.327 247.091 " stroke="none" fill="#ffffff" fill-rule="evenodd"></path></g></svg>
1746
  </div>
1747
- <div id="updatesIcon" title="Changelog">
1748
  <svg id="update_nothing" version="1.0" xmlns="http://www.w3.org/2000/svg"
1749
  width="25.000000pt" height="25.000000pt" viewBox="0 0 250.000000 344.000000"
1750
  preserveAspectRatio="xMidYMid meet"><g transform="translate(300.000000,344.000000) scale(0.100000,-0.100000) rotate(90 0 0)"
@@ -1758,13 +1736,10 @@
1758
  0 -348 25 -27 c54 -58 5 -55 955 -55 l875 0 0 -357 0 -358 572 573 573 572
1759
  -573 572 -572 573 0 -358z"/></g></svg>
1760
  </div>
1761
- <div id="patreonIcon" title="Patreon">
1762
- <img src="./assets/patreon.png">
1763
- </div>
1764
- <div id="infoIcon" title="Info">
1765
  <svg version="1.0" xmlns="http://www.w3.org/2000/svg" width="1024.000000pt" height="1024.000000pt" viewBox="0 0 1024.000000 1024.000000" preserveAspectRatio="xMidYMid meet"><g transform="translate(0.000000,1024.000000) scale(0.100000,-0.100000)" fill="#ffffff" stroke="none"><path d="M4920 9273 c-776 -41 -1504 -285 -2137 -715 -72 -49 -192 -137 -265 -196 -171 -136 -504 -469 -640 -639 -514 -646 -816 -1390 -899 -2218 -16 -155 -16 -615 0 -770 84 -830 387 -1575 905 -2225 131 -164 467 -499 634 -632 962 -766 2166 -1066 3378 -843 652 121 1287 413 1824 841 174 138 506 470 644 644 794 997 1091 2288 810 3525 -267 1174 -1048 2190 -2119 2756 -644 340 -1416 511 -2135 472z m640 -658 c708 -97 1329 -373 1855 -825 128 -110 355 -346 458 -475 851 -1069 1008 -2537 403 -3755 -182 -365 -370 -625 -670 -926 -233 -232 -422 -382 -676 -535 -1022 -614 -2304 -665 -3370 -135 -344 172 -619 367 -894 636 -268 262 -450 500 -629 821 -218 390 -358 827 -419 1309 -17 140 -17 640 0 780 103 811 427 1495 977 2059 266 272 502 454 826 634 390 218 862 369 1304 416 55 6 118 13 140 15 96 10 585 -4 695 -19z"/> <path d="M4960 7674 c-143 -24 -221 -54 -321 -120 -146 -97 -256 -255 -300 -434 -17 -70 -17 -248 0 -320 65 -268 273 -475 541 -541 71 -17 249 -17 320 0 285 70 495 293 545 580 19 105 19 137 0 242 -49 281 -253 503 -526 574 -59 15 -214 27 -259 19z"/> <path d="M4870 5724 c-476 -18 -902 -33 -947 -33 l-83 -1 0 -160 0 -160 203 0 c212 0 290 -11 366 -49 50 -26 98 -82 111 -130 7 -27 10 -369 8 -1083 -3 -1040 -3 -1043 -24 -1089 -23 -49 -67 -88 -124 -109 -23 -9 -109 -15 -257 -18 l-223 -4 0 -164 0 -164 1250 0 1250 0 0 164 0 164 -197 5 c-225 5 -281 17 -342 73 -26 23 -42 48 -50 79 -8 31 -11 430 -11 1379 l0 1336 -32 -1 c-18 -1 -422 -17 -898 -35z"/> </g> </svg>
1766
  </div>
1767
- <div id="settingsCog" title="Settings">
1768
  <svg version="1.0" xmlns="http://www.w3.org/2000/svg"
1769
  width="1280.000000pt" height="1280.000000pt" viewBox="0 0 1280.000000 1280.000000"
1770
  preserveAspectRatio="xMidYMid meet">
@@ -1808,30 +1783,12 @@ const electronR = require('@electron/remote')
1808
  const currentWindow = electronR.getCurrentWindow()
1809
  // createElem
1810
  "use strict";function _toConsumableArray(e){if(Array.isArray(e)){for(var t=0,r=Array(e.length);t<e.length;t++)r[t]=e[t];return r}return Array.from(e)}var _typeof="function"==typeof Symbol&&"symbol"==typeof Symbol.iterator?function(e){return typeof e}:function(e){return e&&"function"==typeof Symbol&&e.constructor===Symbol&&e!==Symbol.prototype?"symbol":typeof e};window.createElem=function(){for(var e=arguments.length,t=Array(e),r=0;r<e;r++)t[r]=arguments[r];var n=1;if(Number.isInteger(t[0])){if(!(t[0]>0))throw new Error("Element count must be larger than 0. Actual value: "+t[0]);n=t[0],t.shift()}else if(Number(t[0])===t[0]&&t[0]%1!=0)throw new Error("Floats are not supported for element count.");var o=t[0]?t[0]:"div";if(t.shift(),"string"!=typeof o)throw new Error("Tag name must be a string");var a=document.createElement(o.replace(/(#.*)|(\..*)/g,"")),s=o.match(/#(?:(?![#\.]).)*/),c=o.match(/\.(?:(?![#\.]).)*/g);if(s&&(a.id=s[0].substr(1,s[0].length)),c&&(a.className=c.map(function(e){return e.substr(1,e.length)}).join(" ")),t.length)if("string"==typeof t[0])a.innerHTML=t[0],t.shift();else if(!(Object(t[0])!==t[0]||t[0]instanceof HTMLElement||Array.isArray(t[0]))){for(var i in t[0])!function(){switch(i){case"class":a.className=t[0].class;break;case"style":var e=t[0].style;if(null!=e&&void 0!=e&&e.constructor===Object)a.style.cssText=Object.keys(e).map(function(t){return t.replace(/[A-Z]/g,function(e){return"-"+e.toLowerCase()})+":"+("number"==typeof e[t]?e[t]+"px":e[t])}).join(";");else{if("string"!=typeof e)throw new Error("Style value must be either object or string.");a.style.cssText=e}break;case"events":Object.keys(t[0].events).forEach(function(e){var r=t[0].events[e];Array.isArray(r)?r.forEach(function(t){return a.addEventListener(e,t)}):"function"==typeof r&&a.addEventListener(e,r)});break;default:a.setAttribute(i,t[0][i])}}();t.shift()}var u=function e(t){switch(!0){case t instanceof HTMLElement:a.appendChild(t);break;case Array.isArray(t):t.forEach(e);break;case!!t&&t.constructor===Object:throw new Error("Multiple attributes objects not supported");default:null!=t&&console.warn("Unsupported parameter. Type: "+(void 0===t?"undefined":_typeof(t))+" Value:",t)}};return t.forEach(u),n>1?[].concat(_toConsumableArray(new Array(n))).map(function(e){return a.cloneNode()}):a};
1811
-
1812
- // Chrome
1813
- chromeMin.addEventListener("click", () => currentWindow.minimize())
1814
- chromeMax.addEventListener("click", () => {
1815
- const w = currentWindow
1816
- w.isMaximized() ? w.unmaximize() : w.maximize()
1817
- })
1818
- chromeQuit.addEventListener("click", () => doFetch(`http://localhost:8008/stopServer`, {
1819
- method: "Post",
1820
- body: JSON.stringify({})
1821
- }).then(r=>r.text()).then(() => {
1822
- try {
1823
- window.pythonProcess.kill()
1824
- } catch (e) {}
1825
- currentWindow.close()
1826
- }).catch(e => {
1827
- try {
1828
- window.pythonProcess.kill()
1829
- } catch (e) {}
1830
- currentWindow.close()
1831
- }))
1832
  </script>
1833
  <style id="pluginsCSS" type="text/css"></style>
1834
- <script src="javascript/script.js"></script>
 
 
 
1835
  <script type="text/javascript" src="lib/Three.min.js"></script>
1836
  <script type="text/javascript" src="lib/OrbitControls.js"></script>
1837
  <script type="text/javascript" src="lib/TrackballControls.js"></script>
 
24
  <body>
25
  <div id="chromeBar">
26
  <div id="dragBar">xVA Synth</div>
 
 
 
 
 
27
  </div>
28
  <div id="appcontent">
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
29
  <div id="right">
30
  <div id="rightBG1"></div>
31
  <div id="rightBG2"></div>
 
250
  </div>
251
  </div>
252
 
 
253
  <div id="settingsContainer" style="display:none">
254
  <div class="modal" style="height: 75vh;width: 60vw">
255
  <h2 id="i18n_settings" style="margin-bottom: 0;">Settings</h2>
 
1678
  </div>
1679
  </div>
1680
 
1681
+ <div id="workbenchIcon" class="tool-icon" title="Workbench (Disabled)">
1682
  <svg version="1.0" xmlns="http://www.w3.org/2000/svg"
1683
  width="512.000000pt" height="512.000000pt" viewBox="0 0 512.000000 512.000000"
1684
  preserveAspectRatio="xMidYMid meet">
 
1703
  </g>
1704
  </svg>
1705
  </div>
1706
+ <div id="arpabetIcon" class="tool-icon" title="ARPAbet (Disabled)">
 
1707
  <svg width="30" height="25" version="1.1" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" width="400" height="291.8918918918919" viewBox="0, 0, 400,291.8918918918919"><g id="svgg"><path id="path0" d="M72.973 27.879 C 32.451 42.782,17.396 97.297,53.802 97.297 C 79.544 97.297,91.701 72.242,74.370 54.910 C 57.283 37.823,127.302 30.250,150.720 46.652 C 165.423 56.951,178.378 85.094,178.378 106.737 C 178.378 121.690,177.667 122.026,133.043 128.111 C 63.835 137.548,24.390 162.533,18.168 200.875 C 8.105 262.887,127.891 288.561,186.634 236.983 L 205.405 220.502 224.177 236.983 C 279.158 285.258,383.632 260.162,383.764 198.649 C 383.794 184.437,374.252 187.264,365.517 204.054 C 328.367 275.463,232.983 251.601,219.541 167.536 C 214.378 135.247,214.669 135.135,303.691 135.135 L 385.122 135.135 382.638 105.181 C 376.173 27.218,271.272 -9.201,219.131 48.414 C 210.152 58.336,209.281 58.158,185.830 41.628 C 158.995 22.713,104.930 16.127,72.973 27.879 M326.220 52.019 C 339.715 65.513,351.256 94.410,351.321 114.865 C 351.348 123.350,344.670 124.324,286.486 124.324 L 221.622 124.324 221.649 109.459 C 221.751 55.079,291.156 16.954,326.220 52.019 M180.884 170.569 C 188.274 229.709,123.639 272.474,79.427 237.697 C 33.938 201.915,81.663 142.798,157.485 141.005 L 177.133 140.541 180.884 170.569 " stroke="none" fill="#ffffff" fill-rule="evenodd"></path></g></svg>
1708
  </div>
1709
+ <div id="embeddingsIcon" class="tool-icon" title="Embeddings visualiser (Disabled)">
1710
  <svg width="25" height="25" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" viewBox="0, 0, 400,400"><g id="svgg"><path id="path0" d="M150.000 20.230 C 65.534 26.594,5.904 105.137,22.679 187.932 C 41.869 282.642,149.542 329.959,232.409 280.098 L 237.105 277.272 288.552 328.719 L 340.000 380.166 360.083 360.083 L 380.166 340.000 328.719 288.552 L 277.272 237.105 280.098 232.409 C 316.949 171.163,301.885 92.110,245.067 48.568 C 218.394 28.128,183.443 17.709,150.000 20.230 M166.667 70.498 C 215.683 73.046,254.682 119.552,249.348 169.093 C 244.601 213.185,208.627 247.470,164.854 249.622 C 102.308 252.696,55.953 193.244,74.215 133.374 C 85.585 96.097,124.114 68.164,161.333 70.215 C 162.342 70.271,164.742 70.398,166.667 70.498 " stroke="none" fill="#ffffff" fill-rule="evenodd"></path></g></svg>
1711
  </div>
1712
+ <div id="pluginsIcon" class="tool-icon" title="Plugins (Disabled)">
1713
  <svg width="25" height="25" xmlns:xlink="http://www.w3.org/1999/xlink" xmlns="http://www.w3.org/2000/svg" fill-opacity="1" color-rendering="auto" color-interpolation="auto" text-rendering="auto" stroke="white" stroke-linecap="square" stroke-miterlimit="10" shape-rendering="auto" stroke-opacity="1" fill="#ffffff" stroke-dasharray="none" font-weight="normal" stroke-width="1" font-family="'Dialog'" font-style="normal" stroke-linejoin="miter" font-size="12" stroke-dashoffset="0" image-rendering="auto" viewBox="0, 150, 300, 250">
1714
  <defs id="genericDefs"/>
1715
  <g>
 
1719
  </g>
1720
  </svg>
1721
  </div>
1722
+ <div id="batchIcon" class="tool-icon" title="Batch mode (Disabled)">
1723
  <svg id="batchSVGIcon" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" width="25" height="25" viewBox="0, 0, 400,310.24930747922434"><g id="svgg"><path id="path0" d="M5.549 99.446 C 5.515 149.266,5.829 215.831,6.246 247.368 L 7.004 304.709 198.516 304.709 L 390.028 304.709 390.028 157.523 L 390.028 10.338 282.825 9.602 C 223.864 9.197,137.371 8.865,90.617 8.865 L 5.611 8.864 5.549 99.446 M107.479 67.590 L 107.479 97.507 70.914 97.507 L 34.349 97.507 34.349 67.590 L 34.349 37.673 70.914 37.673 L 107.479 37.673 107.479 67.590 M362.327 67.590 L 362.327 97.507 249.307 97.507 L 136.288 97.507 136.288 67.590 L 136.288 37.673 249.307 37.673 L 362.327 37.673 362.327 67.590 M107.479 157.341 L 107.479 187.258 70.914 187.258 L 34.349 187.258 34.349 157.341 L 34.349 127.424 70.914 127.424 L 107.479 127.424 107.479 157.341 M362.327 157.341 L 362.327 187.258 249.307 187.258 L 136.288 187.258 136.288 157.341 L 136.288 127.424 249.307 127.424 L 362.327 127.424 362.327 157.341 M107.479 247.091 L 107.479 277.008 70.914 277.008 L 34.349 277.008 34.349 247.091 L 34.349 217.175 70.914 217.175 L 107.479 217.175 107.479 247.091 M362.327 247.091 L 362.327 277.008 249.307 277.008 L 136.288 277.008 136.294 257.895 C 136.297 247.382,136.621 233.920,137.015 227.978 L 137.730 217.175 250.029 217.175 L 362.327 217.175 362.327 247.091 " stroke="none" fill="#ffffff" fill-rule="evenodd"></path></g></svg>
1724
  </div>
1725
+ <div id="updatesIcon" class="tool-icon" title="Changelog (Disabled)">
1726
  <svg id="update_nothing" version="1.0" xmlns="http://www.w3.org/2000/svg"
1727
  width="25.000000pt" height="25.000000pt" viewBox="0 0 250.000000 344.000000"
1728
  preserveAspectRatio="xMidYMid meet"><g transform="translate(300.000000,344.000000) scale(0.100000,-0.100000) rotate(90 0 0)"
 
1736
  0 -348 25 -27 c54 -58 5 -55 955 -55 l875 0 0 -357 0 -358 572 573 573 572
1737
  -573 572 -572 573 0 -358z"/></g></svg>
1738
  </div>
1739
+ <div id="infoIcon" class="tool-icon" title="Info (Disabled)">
 
 
 
1740
  <svg version="1.0" xmlns="http://www.w3.org/2000/svg" width="1024.000000pt" height="1024.000000pt" viewBox="0 0 1024.000000 1024.000000" preserveAspectRatio="xMidYMid meet"><g transform="translate(0.000000,1024.000000) scale(0.100000,-0.100000)" fill="#ffffff" stroke="none"><path d="M4920 9273 c-776 -41 -1504 -285 -2137 -715 -72 -49 -192 -137 -265 -196 -171 -136 -504 -469 -640 -639 -514 -646 -816 -1390 -899 -2218 -16 -155 -16 -615 0 -770 84 -830 387 -1575 905 -2225 131 -164 467 -499 634 -632 962 -766 2166 -1066 3378 -843 652 121 1287 413 1824 841 174 138 506 470 644 644 794 997 1091 2288 810 3525 -267 1174 -1048 2190 -2119 2756 -644 340 -1416 511 -2135 472z m640 -658 c708 -97 1329 -373 1855 -825 128 -110 355 -346 458 -475 851 -1069 1008 -2537 403 -3755 -182 -365 -370 -625 -670 -926 -233 -232 -422 -382 -676 -535 -1022 -614 -2304 -665 -3370 -135 -344 172 -619 367 -894 636 -268 262 -450 500 -629 821 -218 390 -358 827 -419 1309 -17 140 -17 640 0 780 103 811 427 1495 977 2059 266 272 502 454 826 634 390 218 862 369 1304 416 55 6 118 13 140 15 96 10 585 -4 695 -19z"/> <path d="M4960 7674 c-143 -24 -221 -54 -321 -120 -146 -97 -256 -255 -300 -434 -17 -70 -17 -248 0 -320 65 -268 273 -475 541 -541 71 -17 249 -17 320 0 285 70 495 293 545 580 19 105 19 137 0 242 -49 281 -253 503 -526 574 -59 15 -214 27 -259 19z"/> <path d="M4870 5724 c-476 -18 -902 -33 -947 -33 l-83 -1 0 -160 0 -160 203 0 c212 0 290 -11 366 -49 50 -26 98 -82 111 -130 7 -27 10 -369 8 -1083 -3 -1040 -3 -1043 -24 -1089 -23 -49 -67 -88 -124 -109 -23 -9 -109 -15 -257 -18 l-223 -4 0 -164 0 -164 1250 0 1250 0 0 164 0 164 -197 5 c-225 5 -281 17 -342 73 -26 23 -42 48 -50 79 -8 31 -11 430 -11 1379 l0 1336 -32 -1 c-18 -1 -422 -17 -898 -35z"/> </g> </svg>
1741
  </div>
1742
+ <div id="settingsCog" class="tool-icon" title="Settings (Disabled)">
1743
  <svg version="1.0" xmlns="http://www.w3.org/2000/svg"
1744
  width="1280.000000pt" height="1280.000000pt" viewBox="0 0 1280.000000 1280.000000"
1745
  preserveAspectRatio="xMidYMid meet">
 
1783
  const currentWindow = electronR.getCurrentWindow()
1784
  // createElem
1785
  "use strict";function _toConsumableArray(e){if(Array.isArray(e)){for(var t=0,r=Array(e.length);t<e.length;t++)r[t]=e[t];return r}return Array.from(e)}var _typeof="function"==typeof Symbol&&"symbol"==typeof Symbol.iterator?function(e){return typeof e}:function(e){return e&&"function"==typeof Symbol&&e.constructor===Symbol&&e!==Symbol.prototype?"symbol":typeof e};window.createElem=function(){for(var e=arguments.length,t=Array(e),r=0;r<e;r++)t[r]=arguments[r];var n=1;if(Number.isInteger(t[0])){if(!(t[0]>0))throw new Error("Element count must be larger than 0. Actual value: "+t[0]);n=t[0],t.shift()}else if(Number(t[0])===t[0]&&t[0]%1!=0)throw new Error("Floats are not supported for element count.");var o=t[0]?t[0]:"div";if(t.shift(),"string"!=typeof o)throw new Error("Tag name must be a string");var a=document.createElement(o.replace(/(#.*)|(\..*)/g,"")),s=o.match(/#(?:(?![#\.]).)*/),c=o.match(/\.(?:(?![#\.]).)*/g);if(s&&(a.id=s[0].substr(1,s[0].length)),c&&(a.className=c.map(function(e){return e.substr(1,e.length)}).join(" ")),t.length)if("string"==typeof t[0])a.innerHTML=t[0],t.shift();else if(!(Object(t[0])!==t[0]||t[0]instanceof HTMLElement||Array.isArray(t[0]))){for(var i in t[0])!function(){switch(i){case"class":a.className=t[0].class;break;case"style":var e=t[0].style;if(null!=e&&void 0!=e&&e.constructor===Object)a.style.cssText=Object.keys(e).map(function(t){return t.replace(/[A-Z]/g,function(e){return"-"+e.toLowerCase()})+":"+("number"==typeof e[t]?e[t]+"px":e[t])}).join(";");else{if("string"!=typeof e)throw new Error("Style value must be either object or string.");a.style.cssText=e}break;case"events":Object.keys(t[0].events).forEach(function(e){var r=t[0].events[e];Array.isArray(r)?r.forEach(function(t){return a.addEventListener(e,t)}):"function"==typeof r&&a.addEventListener(e,r)});break;default:a.setAttribute(i,t[0][i])}}();t.shift()}var u=function e(t){switch(!0){case t instanceof HTMLElement:a.appendChild(t);break;case Array.isArray(t):t.forEach(e);break;case!!t&&t.constructor===Object:throw new Error("Multiple attributes objects not supported");default:null!=t&&console.warn("Unsupported parameter. Type: "+(void 0===t?"undefined":_typeof(t))+" Value:",t)}};return t.forEach(u),n>1?[].concat(_toConsumableArray(new Array(n))).map(function(e){return a.cloneNode()}):a};
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1786
  </script>
1787
  <style id="pluginsCSS" type="text/css"></style>
1788
+ <script src="javascript/editor.js"></script>
1789
+ <script src="javascript/textarea.js"></script>
1790
+ <script src="javascript/speech2speech.js"></script>
1791
+ <script src="javascript/noelectron.js"></script>
1792
  <script type="text/javascript" src="lib/Three.min.js"></script>
1793
  <script type="text/javascript" src="lib/OrbitControls.js"></script>
1794
  <script type="text/javascript" src="lib/TrackballControls.js"></script>
resources/app/javascript/script.js ADDED
@@ -0,0 +1,1730 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ "use strict"
2
+ window.appVersion = "v3.0.3"
3
+
4
+ window.PRODUCTION = module.filename.includes("resources")
5
+ const path = window.PRODUCTION ? "./resources/app" : "."
6
+ window.path = path
7
+
8
+ const fs = require("fs")
9
+ const zipdir = require('zip-dir')
10
+ const {shell, ipcRenderer, clipboard} = require("electron")
11
+ const doFetch = require("node-fetch")
12
+ const {xVAAppLogger} = require("./javascript/appLogger.js")
13
+ window.appLogger = new xVAAppLogger(`./app.log`, window.appVersion)
14
+ process.on(`uncaughtException`, (data, origin) => {window.appLogger.log(`uncaughtException: ${data}`);window.appLogger.log(`uncaughtException: ${origin}`)})
15
+ window.onerror = (event, source, lineno, colno, error) => {window.appLogger.log(`onerror: ${error.stack}`)}
16
+ require("./javascript/i18n.js")
17
+ require("./javascript/util.js")
18
+ require("./javascript/nexus.js")
19
+ require("./javascript/dragdrop_model_install.js")
20
+ require("./javascript/embeddings.js")
21
+ require("./javascript/totd.js")
22
+ require("./javascript/arpabet.js")
23
+ require("./javascript/style_embeddings.js")
24
+ const {Editor} = require("./javascript/editor.js")
25
+ require("./javascript/textarea.js")
26
+ const {saveUserSettings, deleteFolderRecursive} = require("./javascript/settingsMenu.js")
27
+ const xVASpeech = require("./javascript/speech2speech.js")
28
+ require("./javascript/batch.js")
29
+ require("./javascript/outputFiles.js")
30
+ require("./javascript/workbench.js")
31
+ const er = require('@electron/remote')
32
+ window.electronBrowserWindow = er.getCurrentWindow()
33
+ const child = require("child_process").execFile
34
+ const spawn = require("child_process").spawn
35
+
36
+ // Newly introduced in v3. I will slowly start moving global context variables into this, and update code throughout to reference this
37
+ // instead of old variables such as window.games, window.currentModel, etc.
38
+ window.appState = {}
39
+
40
+
41
+ // Start the server
42
+ if (window.PRODUCTION) {
43
+ window.pythonProcess = spawn(`${path}/cpython_${window.userSettings.installation}/server.exe`, {stdio: "ignore"})
44
+ }
45
+
46
+ const {PluginsManager} = require("./javascript/plugins_manager.js")
47
+ window.pluginsContext = {}
48
+ window.pluginsManager = new PluginsManager(window.path, window.appLogger, window.appVersion)
49
+ window.pluginsManager.runPlugins(window.pluginsManager.pluginsModules["start"]["pre"], event="pre start")
50
+
51
+
52
+ let themeColour
53
+ let secondaryThemeColour
54
+ const oldCError = console.error
55
+ console.error = (...rest) => {
56
+ window.appLogger.log(`console.error: ${rest}`)
57
+ oldCError(rest)
58
+ }
59
+
60
+ window.addEventListener("error", function (e) {window.appLogger.log(`error: ${e.error.stack}`)})
61
+ window.addEventListener('unhandledrejection', function (e) {window.appLogger.log(`unhandledrejection: ${e.stack}`)})
62
+
63
+
64
+ setTimeout(() => {
65
+ window.electron = require("electron")
66
+ }, 1000)
67
+
68
+
69
+ window.games = {}
70
+ window.models = {}
71
+ window.sequenceEditor = new Editor()
72
+ window.currentModel = undefined
73
+ window.currentModelButton = undefined
74
+ window.watchedModelsDirs = []
75
+
76
+ window.appLogger.log(`Settings: ${JSON.stringify(window.userSettings)}`)
77
+
78
+ // Set up folders
79
+ try {fs.mkdirSync(`${path}/models`)} catch (e) {/*Do nothing*/}
80
+ try {fs.mkdirSync(`${path}/output`)} catch (e) {/*Do nothing*/}
81
+ try {fs.mkdirSync(`${path}/assets`)} catch (e) {/*Do nothing*/}
82
+
83
+ // Clean up temp files
84
+ const clearOldTempFiles = () => {
85
+ fs.readdir(`${__dirname.replace("/javascript", "")}/output`, (err, files) => {
86
+ if (err) {
87
+ window.appLogger.log(`Error cleaning up temp files: ${err}`)
88
+ }
89
+ if (files && files.length) {
90
+ files.filter(f => f.startsWith("temp-")).forEach(file => {
91
+ fs.unlink(`${__dirname.replace("/javascript", "")}/output/${file}`, err => err&&console.log(err))
92
+ })
93
+ }
94
+ })
95
+ }
96
+ clearOldTempFiles()
97
+
98
+ let fileRenameCounter = 0
99
+ let fileChangeCounter = 0
100
+ window.isGenerating = false
101
+
102
+
103
+
104
+
105
+ window.registerModel = (modelsPath, gameFolder, model, {gameId, voiceId, voiceName, voiceDescription, gender, variant, modelType, emb_i}) => {
106
+ // Add game, if the game hasn't been added yet
107
+ let audioPreviewPath
108
+ try {
109
+ audioPreviewPath = `${modelsPath}/${model.games.find(({gameId}) => gameId==gameFolder).voiceId}`
110
+ } catch (e) {}
111
+ if (!window.games.hasOwnProperty(gameId)) {
112
+
113
+ const gameAsset = fs.readdirSync(`${path}/assets`).find(f => f==gameId+".json")
114
+ if (gameAsset && gameAsset.length && gameAsset[0]) {
115
+ const gameTheme = JSON.parse(fs.readFileSync(`${path}/assets/${gameAsset}`))
116
+
117
+ window.games[gameId] = {
118
+ models: [],
119
+ gameTheme,
120
+ gameAsset
121
+ }
122
+
123
+ } else {
124
+ window.appLogger.log(`Something not right with loading model: ${voiceId} . The asset file for its game (${gameId}) could not be found here: ${path}/assets. You need a ${gameId}.json file. Loading a generic theme for this voice's game/category.`)
125
+
126
+ const dummyGameTheme = {
127
+ "gameName": gameId,
128
+ "assetFile": "other.jpg",
129
+ "themeColourPrimary": "aaaaaa",
130
+ "themeColourSecondary": null,
131
+ "gameCode": "x",
132
+ "nexusGamePageIDs": []
133
+ }
134
+ const dummyGameAsset = "other.json"
135
+ window.games[gameId] = {
136
+ models: [],
137
+ dummyGameTheme,
138
+ dummyGameAsset
139
+ }
140
+ audioPreviewPath = `${modelsPath}/${model.games[0].voiceId}`
141
+ }
142
+ }
143
+
144
+ // Catch duplicates, for when/if a model is registered for multiple games, but there's already the same model in that game, from another version
145
+ // const existingDuplicates = []
146
+ // window.games[gameId].models.forEach((item,i) => {
147
+ // if (item.voiceId==voiceId) {
148
+ // existingDuplicates.push([item, i])
149
+ // }
150
+ // })
151
+
152
+ // Check if a variant has already been added for this voice name, for this game
153
+ let foundVariantIndex = undefined
154
+ window.games[gameId].models.forEach((item,i) => {
155
+ if (foundVariantIndex!=undefined) return
156
+
157
+ if (item.voiceName.toLowerCase().trim()==voiceName.toLowerCase().trim()) {
158
+ foundVariantIndex = i
159
+ }
160
+ })
161
+
162
+ // Add the initial model metadata, if no existing variant has been added (will happen most of the time)
163
+ if (!foundVariantIndex) {
164
+ const modelData = {
165
+ gameId,
166
+ modelsPath,
167
+ voiceName,
168
+ lang_capabilities: model.lang_capabilities,
169
+ embOverABaseModel: model.embOverABaseModel,
170
+ variants: []
171
+ }
172
+ window.games[gameId].models.push(modelData)
173
+ foundVariantIndex = window.games[gameId].models.length-1
174
+ }
175
+
176
+ const variantData = {
177
+ author: model.author,
178
+ version: model.version,
179
+ modelVersion: model.modelVersion,
180
+ modelType: model.modelType,
181
+ base_speaker_emb: model.modelType=="xVAPitch" ? model.games[0].base_speaker_emb : undefined,
182
+ voiceId,
183
+ audioPreviewPath,
184
+ hifi: undefined,
185
+ num_speakers: model.emb_size,
186
+ emb_i,
187
+ variantName: variant ? variant.replace("Default :", "Default:").replace("Default:", "").trim() : "Default",
188
+ voiceDescription,
189
+ lang: model.lang,
190
+ gender,
191
+ modelType: modelType||model.modelType,
192
+ model,
193
+ }
194
+ const potentialHiFiPath = `${modelsPath}/${voiceId}.hg.pt`
195
+ if (fs.existsSync(potentialHiFiPath)) {
196
+ variantData.hifi = potentialHiFiPath
197
+ }
198
+
199
+ const isDefaultVariant = !variant || variant.toLowerCase().startsWith("default")
200
+
201
+ if (isDefaultVariant) {
202
+ // Place first in the list, if it's default
203
+ window.games[gameId].models[foundVariantIndex].audioPreviewPath = audioPreviewPath
204
+ window.games[gameId].models[foundVariantIndex].variants.splice(0,0,variantData)
205
+ } else {
206
+ window.games[gameId].models[foundVariantIndex].variants.push(variantData)
207
+ }
208
+
209
+
210
+ // // Using the detected duplicates, use only the latest version
211
+ // if (existingDuplicates.length) {
212
+ // if (existingDuplicates[0][0].modelVersion<model.modelVersion) {
213
+ // window.games[gameId].models.splice(existingDuplicates[0][1], 1)
214
+ // window.games[gameId].models.push(modelData)
215
+ // }
216
+ // } else {
217
+ // window.games[gameId].models.push(modelData)
218
+ // }
219
+ }
220
+
221
+ window.loadAllModels = (forceUpdate=false) => {
222
+ return new Promise(resolve => {
223
+
224
+ if (!forceUpdate && window.nexusState.installQueue.length) {
225
+ return
226
+ }
227
+
228
+ let gameFolder
229
+ let modelPathsKeys = Object.keys(window.userSettings).filter(key => key.includes("modelspath_"))
230
+ window.games = {}
231
+
232
+ // Do the current game first, and stop blocking the render process
233
+ if (window.currentGame) {
234
+ const currentGameFolder = window.userSettings[`modelspath_${window.currentGame.gameId}`]
235
+ gameFolder = currentGameFolder
236
+ try {
237
+ const files = fs.readdirSync(modelsPath).filter(f => f.endsWith(".json"))
238
+ files.forEach(fileName => {
239
+ try {
240
+ if (!models.hasOwnProperty(`${gameFolder}/${fileName}`)) {
241
+ models[`${gameFolder}/${fileName}`] = null
242
+ }
243
+ const model = JSON.parse(fs.readFileSync(`${modelsPath}/${fileName}`, "utf8"))
244
+ model.games.forEach(({gameId, voiceId, voiceName, voiceDescription, gender, variant, modelType, emb_i}) => {
245
+ window.registerModel(currentGameFolder, gameFolder, model, {gameId, voiceId, voiceName, voiceDescription, gender, variant, modelType, emb_i})
246
+ })
247
+
248
+ } catch (e) {
249
+ console.log(e)
250
+ // window.appLogger.log(`${window.i18n.ERR_LOADING_MODELS_FOR_GAME_WITH_FILENAME.replace("_1", gameFolder)} `+fileName)
251
+ // window.appLogger.log(e)
252
+ // window.appLogger.log(e.stack)
253
+ }
254
+ })
255
+ } catch (e) {
256
+ window.appLogger.log(`${window.i18n.ERR_LOADING_MODELS_FOR_GAME}: `+ gameFolder)
257
+ window.appLogger.log(e)
258
+ }
259
+ resolve() // Continue the rest but asynchronously
260
+ }
261
+
262
+
263
+ modelPathsKeys.forEach(modelsPathKey => {
264
+ const modelsPath = window.userSettings[modelsPathKey]
265
+ try {
266
+ const files = fs.readdirSync(modelsPath).filter(f => f.endsWith(".json"))
267
+
268
+ if (!files.length) {
269
+ return
270
+ }
271
+
272
+ files.forEach(fileName => {
273
+
274
+ gameFolder = modelsPathKey.split("_")[1]
275
+
276
+ try {
277
+ if (!models.hasOwnProperty(`${gameFolder}/${fileName}`)) {
278
+ models[`${gameFolder}/${fileName}`] = null
279
+ }
280
+
281
+ const model = JSON.parse(fs.readFileSync(`${modelsPath}/${fileName}`, "utf8"))
282
+ model.games.forEach(({gameId, voiceId, voiceName, voiceDescription, gender, variant, modelType, emb_i}) => {
283
+ window.registerModel(modelsPath, gameFolder, model, {gameId, voiceId, voiceName, voiceDescription, gender, variant, modelType, emb_i})
284
+ })
285
+ } catch (e) {
286
+ console.log(e)
287
+ setTimeout(() => {
288
+ window.errorModal(`${fileName}<br><br>${e.stack}`)
289
+ }, 1000)
290
+ window.appLogger.log(`${window.i18n.ERR_LOADING_MODELS_FOR_GAME_WITH_FILENAME.replace("_1", gameFolder)} `+fileName)
291
+ window.appLogger.log(e)
292
+ window.appLogger.log(e.stack)
293
+ }
294
+ })
295
+ } catch (e) {
296
+ window.appLogger.log(`${window.i18n.ERR_LOADING_MODELS_FOR_GAME}: `+ gameFolder)
297
+ window.appLogger.log(e)
298
+ }
299
+ })
300
+ window.updateGameList(false)
301
+ resolve()
302
+ })
303
+ }
304
+
305
+
306
+ // Change variant
307
+ let oldVariantSelection = undefined // For reverting, if versioning checks fail
308
+ variant_select.addEventListener("change", () => {
309
+
310
+ const model = window.games[window.currentGame.gameId].models.find(model => model.voiceName== window.currentModel.voiceName)
311
+ const variant = model.variants.find(variant => variant.variantName==variant_select.value)
312
+
313
+ const appVersionOk = window.checkVersionRequirements(variant.version, appVersion)
314
+ if (!appVersionOk) {
315
+ window.errorModal(`${window.i18n.MODEL_REQUIRES_VERSION} v${variant.version}<br><br>${window.i18n.THIS_APP_VERSION}: ${window.appVersion}`)
316
+ variant_select.value = oldVariantSelection
317
+ return
318
+ }
319
+
320
+ generateVoiceButton.dataset.modelQuery = JSON.stringify({
321
+ outputs: parseInt(model.outputs),
322
+ model: model.embOverABaseModel ? window.userSettings[`modelspath_${model.embOverABaseModel.split("/")[0]}`]+`/${model.embOverABaseModel.split("/")[1]}` : `${model.modelsPath}/${variant.voiceId}`,
323
+ modelType: variant.modelType,
324
+ version: variant.version,
325
+ model_speakers: model.num_speakers,
326
+ base_lang: model.lang || "en"
327
+ })
328
+ oldVariantSelection = variant_select.value
329
+
330
+ titleInfoVoiceID.innerHTML = variant.voiceId
331
+ titleInfoGender.innerHTML = variant.gender || "?"
332
+ titleInfoAppVersion.innerHTML = variant.version || "?"
333
+ titleInfoModelVersion.innerHTML = variant.modelVersion || "?"
334
+ titleInfoModelType.innerHTML = variant.modelType || "?"
335
+ titleInfoLanguage.innerHTML = variant.lang || window.currentModel.games[0].lang || "en"
336
+ titleInfoAuthor.innerHTML = variant.author || "?"
337
+
338
+ generateVoiceButton.click()
339
+ })
340
+
341
+
342
+
343
+ // Change game
344
+ window.changeGame = (meta) => {
345
+
346
+ titleInfo.style.display = "none"
347
+ window.currentGame = meta
348
+ themeColour = meta.themeColourPrimary
349
+ secondaryThemeColour = meta.themeColourSecondary
350
+ let titleID = meta.gameCode
351
+
352
+ generateVoiceButton.disabled = true
353
+ generateVoiceButton.innerHTML = window.i18n.GENERATE_VOICE
354
+ selectedGameDisplay.innerHTML = meta.gameName
355
+
356
+ // Change the app title
357
+ titleName.innerHTML = window.i18n.SELECT_VOICE_TYPE
358
+ if (window.games[window.currentGame.gameId] == undefined) {
359
+ titleName.innerHTML = `${window.i18n.NO_MODELS_IN}: ${window.userSettings[`modelspath_${window.currentGame.gameId}`]}`
360
+ }
361
+
362
+ const gameFolder = meta.gameId
363
+ const gameName = meta.gameName
364
+
365
+ setting_models_path_container.style.display = "flex"
366
+ setting_out_path_container.style.display = "flex"
367
+ setting_models_path_label.innerHTML = `<i style="display:inline">${gameName}</i><span>${window.i18n.SETTINGS_MODELS_PATH}</span>`
368
+ setting_models_path_input.value = window.userSettings[`modelspath_${gameFolder}`]
369
+ setting_out_path_label.innerHTML = `<i style="display:inline">${gameName}</i> ${window.i18n.SETTINGS_OUTPUT_PATH}`
370
+ setting_out_path_input.value = window.userSettings[`outpath_${gameFolder}`]
371
+
372
+ window.setTheme(window.currentGame)
373
+ try {
374
+ window.displayAllModels()
375
+ } catch (e) {console.log(e)}
376
+
377
+ try {fs.mkdirSync(`${path}/output/${meta.gameId}`)} catch (e) {/*Do nothing*/}
378
+ localStorage.setItem("lastGame", JSON.stringify(meta))
379
+
380
+ // Populate models
381
+ voiceTypeContainer.innerHTML = ""
382
+ voiceSamples.innerHTML = ""
383
+
384
+ const buttons = []
385
+ const totalNumVoices = (window.games[meta.gameId] ? window.games[meta.gameId].models : []).reduce((p,c)=>p+c.variants.length, 0)
386
+ voiceSearchInput.placeholder = window.i18n.SEARCH_N_VOICES.replace("_", window.games[meta.gameId] ? totalNumVoices : "0")
387
+ voiceSearchInput.value = ""
388
+
389
+ if (!window.games[meta.gameId]) {
390
+ return
391
+ }
392
+
393
+ (window.games[meta.gameId] ? window.games[meta.gameId].models : []).forEach(({modelsPath, audioPreviewPath, gameId, variants, voiceName, embOverABaseModel}) => {
394
+
395
+ const {voiceId, voiceDescription, hifi, model} = variants[0]
396
+ const modelVersion = variants[0].version
397
+
398
+ const button = createElem("div.voiceType", voiceName)
399
+ button.style.background = `#${themeColour}`
400
+ if (embOverABaseModel) {
401
+ button.style.fontStyle = "italic"
402
+ }
403
+ if (window.userSettings.do_model_version_highlight && parseFloat(modelVersion)<window.userSettings.model_version_highlight) {
404
+ button.style.border = `2px solid #${themeColour}`
405
+ button.style.padding = "0"
406
+ button.style.background = "none"
407
+ }
408
+ button.dataset.modelId = voiceId
409
+ if (secondaryThemeColour) {
410
+ button.style.color = `#${secondaryThemeColour}`
411
+ button.style.textShadow = `none`
412
+ }
413
+
414
+ // Quick voice set preview, if there is a preview file
415
+ button.addEventListener("contextmenu", () => {
416
+ window.appLogger.log(`${audioPreviewPath}.wav`)
417
+ const audioPreview = createElem("audio", {autoplay: false}, createElem("source", {
418
+ src: `${audioPreviewPath}.wav`
419
+ }))
420
+ audioPreview.style.height = "25px"
421
+ audioPreview.setSinkId(window.userSettings.base_speaker)
422
+ })
423
+
424
+ if (embOverABaseModel) {
425
+ const gameOfBaseModel = embOverABaseModel.split("/")[0]
426
+ if (gameOfBaseModel=="<base>") {
427
+ // For included base v3 models
428
+ modelsPath = `${window.path}/python/xvapitch/${embOverABaseModel.split("/")[1]}`
429
+ } else {
430
+ // For any other model
431
+ const gameModelsPath = `${window.userSettings[`outpath_${gameOfBaseModel}`]}`
432
+ modelsPath = `${gameModelsPath}/${embOverABaseModel.split("/")[1]}`
433
+ }
434
+ }
435
+
436
+ button.addEventListener("click", event => window.selectVoice(event, variants, hifi, gameId, voiceId, model, button, audioPreviewPath, modelsPath, meta, embOverABaseModel))
437
+ buttons.push(button)
438
+ })
439
+
440
+ buttons.sort((a,b) => a.innerHTML.toLowerCase()<b.innerHTML.toLowerCase()?-1:1)
441
+ .forEach(button => voiceTypeContainer.appendChild(button))
442
+
443
+ }
444
+
445
+
446
+ window.selectVoice = (event, variants, hifi, gameId, voiceId, model, button, audioPreviewPath, modelsPath, meta, embOverABaseModel) => {
447
+ // Just for easier packaging of the voice models for publishing - yes, lazy
448
+ if (event.ctrlKey && event.shiftKey) {
449
+ window.packageVoice(event.altKey, variants, {modelsPath, gameId})
450
+ }
451
+
452
+ variant_select.innerHTML = ""
453
+ oldVariantSelection = undefined
454
+ if (variants.length==1) {
455
+ variantElements.style.display = "none"
456
+ } else {
457
+ variantElements.style.display = "flex"
458
+ variants.forEach(variant => {
459
+ const option = createElem("option", {value: variant.variantName})
460
+ option.innerHTML = variant.variantName
461
+ variant_select.appendChild(option)
462
+ if (!oldVariantSelection) {
463
+ oldVariantSelection = variant.variantName
464
+ }
465
+ })
466
+ }
467
+
468
+
469
+ if (hifi) {
470
+ // Remove the bespoke hifi option if there was one already there
471
+ Array.from(vocoder_select.children).forEach(opt => {
472
+ if (opt.innerHTML=="Bespoke HiFi GAN") {
473
+ vocoder_select.removeChild(opt)
474
+ }
475
+ })
476
+ bespoke_hifi_bolt.style.opacity = 1
477
+ const option = createElem("option", "Bespoke HiFi GAN")
478
+ option.value = `${gameId}/${voiceId}.hg.pt`
479
+ vocoder_select.appendChild(option)
480
+ } else {
481
+ bespoke_hifi_bolt.style.opacity = 0
482
+ // Set the vocoder select to quick-and-dirty if bespoke hifi-gan was selected
483
+ if (vocoder_select.value.includes(".hg.")) {
484
+ vocoder_select.value = "qnd"
485
+ window.changeVocoder("qnd")
486
+ }
487
+ // Remove the bespoke hifi option if there was one already there
488
+ Array.from(vocoder_select.children).forEach(opt => {
489
+ if (opt.innerHTML=="Bespoke HiFi GAN") {
490
+ vocoder_select.removeChild(opt)
491
+ }
492
+ })
493
+ }
494
+
495
+ window.currentModel = model
496
+ window.currentModel.voiceId = voiceId
497
+ window.currentModel.voiceName = button.innerHTML
498
+ window.currentModel.hifi = hifi
499
+ window.currentModel.audioPreviewPath = audioPreviewPath
500
+ window.currentModelButton = button
501
+
502
+
503
+ generateVoiceButton.dataset.modelQuery = null
504
+
505
+ // The model is already loaded. Don't re-load it.
506
+ if (generateVoiceButton.dataset.modelIDLoaded == voiceId) {
507
+ generateVoiceButton.innerHTML = window.i18n.GENERATE_VOICE
508
+ generateVoiceButton.dataset.modelQuery = "null"
509
+
510
+ } else {
511
+ generateVoiceButton.innerHTML = window.i18n.LOAD_MODEL
512
+ generateVoiceButton.dataset.modelQuery = JSON.stringify({
513
+ outputs: parseInt(model.outputs),
514
+ model: model.embOverABaseModel ? window.userSettings[`modelspath_${model.embOverABaseModel.split("/")[0]}`]+`/${model.embOverABaseModel.split("/")[1]}` : `${modelsPath}/${model.voiceId}`,
515
+ modelType: model.modelType,
516
+ version: model.version,
517
+ model_speakers: model.emb_size,
518
+ cmudict: model.cmudict,
519
+ base_lang: model.lang || "en"
520
+ })
521
+ generateVoiceButton.dataset.modelIDToLoad = voiceId
522
+ }
523
+ generateVoiceButton.disabled = false
524
+
525
+ titleName.innerHTML = button.innerHTML
526
+ titleInfo.style.display = "flex"
527
+ titleInfoName.innerHTML = window.currentModel.voiceName
528
+ titleInfoVoiceID.innerHTML = voiceId
529
+ titleInfoGender.innerHTML = window.currentModel.games[0].gender || "?"
530
+ titleInfoAppVersion.innerHTML = window.currentModel.version || "?"
531
+ titleInfoModelVersion.innerHTML = window.currentModel.modelVersion || "?"
532
+ titleInfoModelType.innerHTML = window.currentModel.modelType || "?"
533
+ titleInfoLanguage.innerHTML = window.currentModel.lang || window.currentModel.games[0].lang || "en"
534
+ titleInfoAuthor.innerHTML = window.currentModel.author || "?"
535
+ titleInfoLicense.innerHTML = window.currentModel.license || window.i18n.UNKNOWN
536
+
537
+ title.dataset.modelId = voiceId
538
+ keepSampleButton.style.display = "none"
539
+ samplePlayPause.style.display = "none"
540
+
541
+ // Voice samples
542
+ voiceSamples.innerHTML = ""
543
+
544
+ window.initMainPagePagination(`${window.userSettings[`outpath_${meta.gameId}`]}/${button.dataset.modelId}`)
545
+ window.refreshRecordsList()
546
+ }
547
+
548
+ titleInfo.addEventListener("click", () => titleDetails.style.display = titleDetails.style.display=="none" ? "block" : "none")
549
+ window.addEventListener("click", event => {
550
+ if (event.target!=titleInfo && event.target!=titleDetails && event.target.parentNode && event.target.parentNode!=titleDetails && event.target.parentNode.parentNode!=titleDetails) {
551
+ titleDetails.style.display = "none"
552
+ }
553
+ })
554
+ titleDetails.style.display = "none"
555
+
556
+
557
+ window.loadModel = () => {
558
+ return new Promise(resolve => {
559
+ if (window.batch_state.state) {
560
+ window.errorModal(window.i18n.BATCH_ERR_IN_PROGRESS)
561
+ return
562
+ }
563
+
564
+ const body = JSON.parse(generateVoiceButton.dataset.modelQuery)
565
+
566
+ const appVersionOk = window.checkVersionRequirements(body.version, appVersion)
567
+ if (!appVersionOk) {
568
+ window.errorModal(`${window.i18n.MODEL_REQUIRES_VERSION} v${body.version}<br><br>${window.i18n.THIS_APP_VERSION}: ${window.appVersion}`)
569
+ return
570
+ }
571
+
572
+
573
+ window.appLogger.log(`${window.i18n.LOADING_VOICE}: ${JSON.parse(generateVoiceButton.dataset.modelQuery).model}`)
574
+ window.batch_state.lastModel = JSON.parse(generateVoiceButton.dataset.modelQuery).model.split("/").reverse()[0]
575
+
576
+ body["pluginsContext"] = JSON.stringify(window.pluginsContext)
577
+
578
+ spinnerModal(`${window.i18n.LOADING_VOICE}`)
579
+ doFetch(`http://localhost:8008/loadModel`, {
580
+ method: "Post",
581
+ body: JSON.stringify(body)
582
+ }).then(r=>r.text()).then(res => {
583
+
584
+ window.currentModel.loaded = true
585
+ generateVoiceButton.dataset.modelQuery = null
586
+ generateVoiceButton.innerHTML = window.i18n.GENERATE_VOICE
587
+ generateVoiceButton.dataset.modelIDLoaded = generateVoiceButton.dataset.modelIDToLoad
588
+
589
+ // Set the editor pitch/energy dropdowns to pitch, and freeze them, if energy is not supported by the model
590
+ window.appState.currentModelEmbeddings = {}
591
+ if (window.currentModel.modelType.toLowerCase()=="xvapitch" && !window.currentModel.isBaseModel) {
592
+ vocoder_options_container.style.display = "none"
593
+ base_lang_select.disabled = false
594
+ style_emb_select.disabled = false
595
+ window.loadStyleEmbsForVoice(window.currentModel)
596
+ mic_SVG.children[0].style.fill = "white"
597
+ base_lang_select.value = window.currentModel.lang
598
+ } else {
599
+ vocoder_options_container.style.display = "inline-block"
600
+ base_lang_select.disabled = true
601
+ style_emb_select.disabled = true
602
+ mic_SVG.children[0].style.fill = "grey"
603
+ }
604
+ if (window.currentModel.modelType.toLowerCase()=="fastpitch") {
605
+ seq_edit_view_select.value = "pitch"
606
+ seq_edit_edit_select.value = "pitch"
607
+ seq_edit_view_select.disabled = true
608
+ seq_edit_edit_select.disabled = true
609
+ } else {
610
+ seq_edit_view_select.value = "pitch_energy"
611
+ seq_edit_view_select.disabled = false
612
+ seq_edit_edit_select.disabled = false
613
+ }
614
+
615
+ window.populateLanguagesDropdownsFromModel(base_lang_select, window.currentModel)
616
+ base_lang_select.value = window.currentModel.lang
617
+
618
+ if (window.userSettings.defaultToHiFi && window.currentModel.hifi) {
619
+ vocoder_select.value = Array.from(vocoder_select.children).find(opt => opt.innerHTML=="Bespoke HiFi GAN").value
620
+ window.changeVocoder(vocoder_select.value).then(() => dialogueInput.focus())
621
+ } else if (window.userSettings.vocoder.includes(".hg.pt")) {
622
+ window.changeVocoder("qnd").then(() => dialogueInput.focus())
623
+ } else {
624
+ closeModal(null, [workbenchContainer]).then(() => dialogueInput.focus())
625
+ }
626
+ resolve()
627
+ }).catch(e => {
628
+ console.log(e)
629
+ if (e.code =="ENOENT") {
630
+ closeModal(null, [modalContainer, workbenchContainer]).then(() => {
631
+ window.errorModal(window.i18n.ERR_SERVER)
632
+ resolve()
633
+ })
634
+ }
635
+ })
636
+ })
637
+ }
638
+
639
+ // Return true/false for if the prompt is the same - BUT: allow phoneme swaps
640
+ window.checkIfPromptIsTheSame = (sequence) => {
641
+
642
+ // False if there was no previous prompt
643
+ if (!window.sequenceEditor.historyState.length) {
644
+ return false
645
+ }
646
+
647
+ const lastPrompt = window.sequenceEditor.historyState.at(-1)
648
+
649
+ // False if they're different lengths
650
+ if (sequence.length != lastPrompt.length) {
651
+ return false
652
+ }
653
+
654
+ // Split into words (and phonemes)
655
+ const currentParts = sequence.split(" ")
656
+ const lastParts = lastPrompt.split(" ")
657
+
658
+ for (let si=0; si<currentParts.length; si++) {
659
+ // False if a word is different, but not if it's an ARPAbet symbol
660
+ const cleaned = currentParts[si].replace(/[^a-zA-Z]/g, "")
661
+ if (currentParts[si]!=lastParts[si] && !window.ARPAbetSymbols.includes(cleaned)) {
662
+ return false
663
+ }
664
+ }
665
+
666
+ return true
667
+ }
668
+
669
+ window.synthesizeSample = () => {
670
+
671
+ const game = window.currentGame.gameId
672
+
673
+ if (window.isGenerating) {
674
+ return
675
+ }
676
+ if (!window.speech2speechState.s2s_running) {
677
+ clearOldTempFiles()
678
+ }
679
+
680
+ let sequence = dialogueInput.value.replace("…", "...").replace("’", "'")
681
+ if (window.userSettings.spacePadding && !window.sequenceEditor.isEditingFromFile) { // Pad start and end of the input sequence with spaces
682
+ sequence = " "+sequence.trim()+" "
683
+ }
684
+ window.sequenceEditor.isEditingFromFile = false
685
+
686
+ if (sequence.length==0) {
687
+ return
688
+ }
689
+ window.isGenerating = true
690
+
691
+ window.pluginsManager.runPlugins(window.pluginsManager.pluginsModules["generate-voice"]["pre"], event="pre generate-voice")
692
+
693
+ if (window.wavesurfer) {
694
+ try {
695
+ window.wavesurfer.stop()
696
+ } catch (e) {
697
+ console.log(e)
698
+ }
699
+ wavesurferContainer.style.opacity = 0
700
+ }
701
+ toggleSpinnerButtons()
702
+
703
+ const voiceType = title.dataset.modelId
704
+ const outputFileName = dialogueInput.value.slice(0, 260).replace(/\n/g, " ").replace(/[\/\\:\*?<>"|]*/g, "").replace(/^[\.\s]+/, "")
705
+
706
+ try {fs.unlinkSync(localStorage.getItem("tempFileLocation"))} catch (e) {/*Do nothing*/}
707
+
708
+ // For some reason, the samplePlay audio element does not update the source when the file name is the same
709
+ const tempFileNum = `${Math.random().toString().split(".")[1]}`
710
+ let tempFileLocation = `${path}/output/temp-${tempFileNum}.wav`
711
+ let pitch = []
712
+ let duration = []
713
+ let energy = []
714
+ let emAngry = []
715
+ let emHappy = []
716
+ let emSad = []
717
+ let emSurprise = []
718
+ let editorStyles = {}
719
+ let isFreshRegen = true
720
+ let old_sequence = undefined
721
+
722
+ if (editorContainer.innerHTML && editorContainer.innerHTML.length && generateVoiceButton.dataset.modelIDLoaded==window.sequenceEditor.currentVoice) {
723
+ if (window.sequenceEditor.audioInput || window.sequenceEditor.sequence && sequence!=window.sequenceEditor.inputSequence) {
724
+ old_sequence = window.sequenceEditor.inputSequence
725
+ }
726
+ }
727
+ // Don't use the old_sequence if running speech-to-speech
728
+ if (window.speech2speechState.s2s_running) {
729
+ old_sequence = undefined
730
+ window.speech2speechState.s2s_running = false
731
+ }
732
+
733
+ // Check if editing an existing line (otherwise it's a fresh new line)
734
+ const languageHasChanged = window.sequenceEditor.base_lang && window.sequenceEditor.base_lang != base_lang_select.value
735
+ const promptHasChanged = !window.checkIfPromptIsTheSame(sequence)
736
+ if (!promptHasChanged && !languageHasChanged && !window.arpabetMenuState.hasChangedARPAbet && !window.styleEmbsMenuState.hasChangedEmb &&
737
+ (speech2speechState.s2s_autogenerate || (editorContainer.innerHTML && editorContainer.innerHTML.length && (window.userSettings.keepEditorOnVoiceChange || generateVoiceButton.dataset.modelIDLoaded==window.sequenceEditor.currentVoice)))) {
738
+
739
+ speech2speechState.s2s_autogenerate = false
740
+ pitch = window.sequenceEditor.pitchNew.map(v=> v==undefined?0:v)
741
+ duration = window.sequenceEditor.dursNew.map(v => v*pace_slid.value).map(v=> v==undefined?0:v)
742
+ energy = window.sequenceEditor.energyNew ? window.sequenceEditor.energyNew.map(v => v==undefined?0:v).filter(v => !isNaN(v)) : []
743
+ if (window.currentModel.modelType=="xVAPitch") {
744
+ emAngry = window.sequenceEditor.emAngryNew ? window.sequenceEditor.emAngryNew.map(v => v==undefined?0:v).filter(v => !isNaN(v)) : []
745
+ emHappy = window.sequenceEditor.emHappyNew ? window.sequenceEditor.emHappyNew.map(v => v==undefined?0:v).filter(v => !isNaN(v)) : []
746
+ emSad = window.sequenceEditor.emSadNew ? window.sequenceEditor.emSadNew.map(v => v==undefined?0:v).filter(v => !isNaN(v)) : []
747
+ emSurprise = window.sequenceEditor.emSurpriseNew ? window.sequenceEditor.emSurpriseNew.map(v => v==undefined?0:v).filter(v => !isNaN(v)) : []
748
+
749
+ if (window.sequenceEditor.registeredStyleKeys) {
750
+ window.sequenceEditor.registeredStyleKeys.forEach(styleKey => {
751
+ editorStyles[styleKey] = {
752
+ embedding: window.appState.currentModelEmbeddings[styleKey][1],
753
+ sliders: window.sequenceEditor.styleValuesNew[styleKey].map(v => v==undefined?0:v).filter(v => !isNaN(v))// : []
754
+ }
755
+ })
756
+ }
757
+ }
758
+ isFreshRegen = false
759
+ }
760
+
761
+ window.arpabetMenuState.hasChangedARPAbet = false
762
+ window.styleEmbsMenuState.hasChangedEmb = false
763
+ window.sequenceEditor.currentVoice = generateVoiceButton.dataset.modelIDLoaded
764
+
765
+ const speaker_i = window.currentModel.games[0].emb_i
766
+ const pace = (window.userSettings.keepPaceOnNew && isFreshRegen)?pace_slid.value:1
767
+
768
+ window.appLogger.log(`${window.i18n.SYNTHESIZING}: ${sequence}`)
769
+
770
+ doFetch(`http://localhost:8008/synthesize`, {
771
+ method: "Post",
772
+ body: JSON.stringify({
773
+ sequence, pitch, duration, energy, emAngry, emHappy, emSad, emSurprise, editorStyles, speaker_i, pace,
774
+ base_lang: base_lang_select.value,
775
+ base_emb: style_emb_select.value||"",
776
+ modelType: window.currentModel.modelType,
777
+ old_sequence, // For partial re-generation
778
+ device: window.userSettings.installation=="cpu"?"cpu":(window.userSettings.useGPU?"cuda:0":"cpu"),
779
+ // device: window.userSettings.useGPU?"gpu":"cpu", // Switch to this once DirectML is installed
780
+ useSR: useSRCkbx.checked,
781
+ useCleanup: useCleanupCkbx.checked,
782
+ outfile: tempFileLocation,
783
+ pluginsContext: JSON.stringify(window.pluginsContext),
784
+ vocoder: window.currentModel.modelType=="xVAPitch" ? "n/a" : window.userSettings.vocoder,
785
+ waveglowPath: vocoder_select.value=="256_waveglow" ? window.userSettings.waveglow_path : window.userSettings.bigwaveglow_path
786
+ })
787
+ }).then(r=>r.text()).then(res => {
788
+ window.isGenerating = false
789
+
790
+ if (res=="ENOENT" || res.startsWith("ERR:")) {
791
+ console.log(res)
792
+ if (res.startsWith("ERR:")) {
793
+ if (res.includes("ARPABET_NOT_IN_LIST")) {
794
+ const symbolNotInList = res.split(":").reverse()[0]
795
+ window.errorModal(`${window.i18n.SOMETHING_WENT_WRONG}<br><br>${window.i18n.ERR_ARPABET_NOT_EXIST.replace("_1", symbolNotInList)}`)
796
+ } else {
797
+ window.errorModal(`${window.i18n.SOMETHING_WENT_WRONG}<br><br>${res.replace("ERR:","").replaceAll(/\n/g, "<br>")}`)
798
+ }
799
+ } else {
800
+ window.appLogger.log(res)
801
+ window.errorModal(`${window.i18n.BATCH_MODEL_NOT_FOUND}.${vocoder_select.value.includes("waveglow")?" "+window.i18n.BATCH_DOWNLOAD_WAVEGLOW:""}`)
802
+ }
803
+ toggleSpinnerButtons()
804
+ return
805
+ }
806
+
807
+ dialogueInput.focus()
808
+ window.sequenceEditor.historyState.push(sequence)
809
+
810
+ if (window.userSettings.clear_text_after_synth) {
811
+ dialogueInput.value = ""
812
+ }
813
+
814
+ res = res.split("\n")
815
+ let pitchData = res[0]
816
+ let durationsData = res[1]
817
+ let energyData = res[2]
818
+ let em_angryData = res[3]
819
+ let em_happyData = res[4]
820
+ let em_sadData = res[5]
821
+ let em_surpriseData = res[6]
822
+ const editorStyles = res[7]&&res[7].length ? JSON.parse(res[7]) : undefined
823
+ let cleanedSequence = res[8].split("|").map(c=>c.replaceAll("{", "").replaceAll("}", "").replace(/\s/g, "_"))
824
+ const start_index = res[9]
825
+ const end_index = res[10]
826
+ pitchData = pitchData.split(",").map(v => parseFloat(v))
827
+
828
+ // For use in adjusting editor range
829
+ const maxPitchVal = pitchData.reduce((p,c)=>Math.max(p, Math.abs(c)), 0)
830
+ if (maxPitchVal>window.sequenceEditor.default_pitchSliderRange) {
831
+ window.sequenceEditor.pitchSliderRange = maxPitchVal
832
+ } else {
833
+ window.sequenceEditor.pitchSliderRange = window.sequenceEditor.default_pitchSliderRange
834
+ }
835
+
836
+ em_angryData = em_angryData.length ? em_angryData.split(",").map(v => parseFloat(v)).filter(v => !isNaN(v)) : []
837
+ em_happyData = em_happyData.length ? em_happyData.split(",").map(v => parseFloat(v)).filter(v => !isNaN(v)) : []
838
+ em_sadData = em_sadData.length ? em_sadData.split(",").map(v => parseFloat(v)).filter(v => !isNaN(v)) : []
839
+ em_surpriseData = em_surpriseData.length ? em_surpriseData.split(",").map(v => parseFloat(v)).filter(v => !isNaN(v)) : []
840
+
841
+ if (energyData.length) {
842
+ energyData = energyData.split(",").map(v => parseFloat(v)).filter(v => !isNaN(v))
843
+
844
+ // For use in adjusting editor range
845
+ const maxEnergyVal = energyData.reduce((p,c)=>Math.max(p, c), 0)
846
+ const minEnergyVal = energyData.reduce((p,c)=>Math.min(p, c), 100)
847
+
848
+ if (minEnergyVal<window.sequenceEditor.default_MIN_ENERGY) {
849
+ window.sequenceEditor.MIN_ENERGY = minEnergyVal
850
+ } else {
851
+ window.sequenceEditor.MIN_ENERGY = window.sequenceEditor.default_MIN_ENERGY
852
+ }
853
+ if (maxEnergyVal>window.sequenceEditor.default_MAX_ENERGY) {
854
+ window.sequenceEditor.MAX_ENERGY = maxEnergyVal
855
+ } else {
856
+ window.sequenceEditor.MAX_ENERGY = window.sequenceEditor.default_MAX_ENERGY
857
+ }
858
+
859
+ } else {
860
+ energyData = []
861
+ }
862
+ durationsData = durationsData.split(",").map(v => isFreshRegen ? parseFloat(v) : parseFloat(v)/pace_slid.value)
863
+
864
+ const doTheRest = () => {
865
+
866
+ window.sequenceEditor.base_lang = base_lang_select.value
867
+ window.sequenceEditor.inputSequence = sequence
868
+ window.sequenceEditor.sequence = cleanedSequence
869
+
870
+ if (pitch.length==0 || isFreshRegen) {
871
+ window.sequenceEditor.resetPitch = pitchData
872
+ window.sequenceEditor.resetDurs = durationsData
873
+ window.sequenceEditor.resetEnergy = energyData
874
+ window.sequenceEditor.resetEmAngry = em_angryData
875
+ window.sequenceEditor.resetEmHappy = em_happyData
876
+ window.sequenceEditor.resetEmSad = em_sadData
877
+ window.sequenceEditor.resetEmSurprise = em_surpriseData
878
+ }
879
+
880
+ window.sequenceEditor.letters = cleanedSequence
881
+ window.sequenceEditor.pitchNew = pitchData.map(p=>p)
882
+ window.sequenceEditor.dursNew = durationsData.map(v=>v)
883
+ window.sequenceEditor.energyNew = energyData.map(v=>v)
884
+ if (window.currentModel.modelType=="xVAPitch") {
885
+ window.sequenceEditor.emAngryNew = em_angryData.map(v=>v)
886
+ window.sequenceEditor.emHappyNew = em_happyData.map(v=>v)
887
+ window.sequenceEditor.emSadNew = em_sadData.map(v=>v)
888
+ window.sequenceEditor.emSurpriseNew = em_surpriseData.map(v=>v)
889
+ window.sequenceEditor.loadStylesData(editorStyles)
890
+ }
891
+ window.sequenceEditor.init()
892
+ const pitchRange = window.userSettings.pitchrangeoverride ? window.userSettings.pitchrangeoverride : window.sequenceEditor.pitchSliderRange
893
+ window.sequenceEditor.update(window.currentModel.modelType, pitchRange)
894
+
895
+ window.sequenceEditor.sliderBoxes.forEach((box, i) => {box.setValueFromValue(window.sequenceEditor.dursNew[i])})
896
+ window.sequenceEditor.autoInferTimer = null
897
+ window.sequenceEditor.hasChanged = false
898
+
899
+
900
+ toggleSpinnerButtons()
901
+ if (keepSampleButton.dataset.newFileLocation && keepSampleButton.dataset.newFileLocation.startsWith("BATCH_EDIT")) {
902
+ console.log("_debug_")
903
+ } else {
904
+ if (window.userSettings[`outpath_${game}`]) {
905
+ keepSampleButton.dataset.newFileLocation = `${window.userSettings[`outpath_${game}`]}/${voiceType}/${outputFileName}.wav`
906
+ } else {
907
+ keepSampleButton.dataset.newFileLocation = `${__dirname.replace(/\\/g,"/")}/output/${voiceType}/${outputFileName}.wav`
908
+ }
909
+ }
910
+ keepSampleButton.disabled = false
911
+ window.tempFileLocation = tempFileLocation
912
+
913
+
914
+ // Wavesurfer
915
+ if (!window.wavesurfer) {
916
+ window.initWaveSurfer(`${__dirname.replace("/javascript", "")}/output/${tempFileLocation.split("/").reverse()[0]}`)
917
+ } else {
918
+ window.wavesurfer.load(`${__dirname.replace("/javascript", "")}/output/${tempFileLocation.split("/").reverse()[0]}`)
919
+ }
920
+
921
+ window.wavesurfer.on("ready", () => {
922
+
923
+ wavesurferContainer.style.opacity = 1
924
+
925
+ if (window.userSettings.autoPlayGen) {
926
+
927
+ if (window.userSettings.playChangedAudio) {
928
+ const playbackStartEnd = window.sequenceEditor.getChangedTimeStamps(start_index, end_index, window.wavesurfer.getDuration())
929
+ if (playbackStartEnd) {
930
+ wavesurfer.play(playbackStartEnd[0], playbackStartEnd[1])
931
+ } else {
932
+ wavesurfer.play()
933
+ }
934
+ } else {
935
+ wavesurfer.play()
936
+ }
937
+ window.sequenceEditor.adjustedLetters = new Set()
938
+ samplePlayPause.innerHTML = window.i18n.PAUSE
939
+ }
940
+ })
941
+
942
+ // Persistance across sessions
943
+ localStorage.setItem("tempFileLocation", tempFileLocation)
944
+ }
945
+
946
+
947
+ if (window.userSettings.audio.ffmpeg) {
948
+ const options = {
949
+ hz: window.userSettings.audio.hz,
950
+ padStart: window.userSettings.audio.padStart,
951
+ padEnd: window.userSettings.audio.padEnd,
952
+ bit_depth: window.userSettings.audio.bitdepth,
953
+ amplitude: window.userSettings.audio.amplitude,
954
+ pitchMult: window.userSettings.audio.pitchMult,
955
+ tempo: window.userSettings.audio.tempo,
956
+ deessing: window.userSettings.audio.deessing,
957
+ nr: window.userSettings.audio.nr,
958
+ nf: window.userSettings.audio.nf,
959
+ useNR: window.userSettings.audio.useNR,
960
+ useSR: useSRCkbx.checked,
961
+ useCleanup: useCleanupCkbx.checked,
962
+ }
963
+
964
+ const extraInfo = {
965
+ game: window.currentGame.gameId,
966
+ voiceId: window.currentModel.voiceId,
967
+ voiceName: window.currentModel.voiceName,
968
+ inputSequence: sequence,
969
+ letters: cleanedSequence,
970
+ pitch: pitchData.map(p=>p),
971
+ energy: energyData.map(p=>p),
972
+ em_angry: em_angryData.map(p=>p),
973
+ em_happy: em_happyData.map(p=>p),
974
+ em_sad: em_sadData.map(p=>p),
975
+ em_surprise: em_surpriseData.map(p=>p),
976
+ durations: durationsData.map(v=>v)
977
+ }
978
+
979
+ doFetch(`http://localhost:8008/outputAudio`, {
980
+ method: "Post",
981
+ body: JSON.stringify({
982
+ input_path: tempFileLocation,
983
+ output_path: tempFileLocation.replace(".wav", `_ffmpeg.${window.userSettings.audio.format}`),
984
+ pluginsContext: JSON.stringify(window.pluginsContext),
985
+ extraInfo: JSON.stringify(extraInfo),
986
+ isBatchMode: false,
987
+ options: JSON.stringify(options)
988
+ })
989
+ }).then(r=>r.text()).then(res => {
990
+ if (res.length && res!="-") {
991
+ console.log("res", res)
992
+ window.errorModal(`${window.i18n.SOMETHING_WENT_WRONG}<br><br>${res}`).then(() => toggleSpinnerButtons())
993
+ } else {
994
+ tempFileLocation = tempFileLocation.replace(".wav", `_ffmpeg.${window.userSettings.audio.format}`)
995
+ doTheRest()
996
+ }
997
+ }).catch(res => {
998
+ console.log(res)
999
+ window.appLogger.log(`outputAudio error: ${res}`)
1000
+ // closeModal().then(() => {
1001
+ window.errorModal(`${window.i18n.SOMETHING_WENT_WRONG}<br><br>${res}`)
1002
+ // })
1003
+ })
1004
+ } else {
1005
+ doTheRest()
1006
+ }
1007
+
1008
+
1009
+ }).catch(res => {
1010
+ window.isGenerating = false
1011
+ console.log(res)
1012
+ window.appLogger.log(res)
1013
+ window.errorModal(window.i18n.SOMETHING_WENT_WRONG)
1014
+ toggleSpinnerButtons()
1015
+ })
1016
+ }
1017
+
1018
+ generateVoiceButton.addEventListener("click", () => {
1019
+ try {fs.mkdirSync(window.userSettings[`outpath_${game}`])} catch (e) {/*Do nothing*/}
1020
+ try {fs.mkdirSync(`${window.userSettings[`outpath_${game}`]}/${voiceId}`)} catch (e) {/*Do nothing*/}
1021
+
1022
+ if (generateVoiceButton.dataset.modelQuery && generateVoiceButton.dataset.modelQuery!="null") {
1023
+ window.loadModel()
1024
+ } else {
1025
+ window.synthesizeSample()
1026
+ }
1027
+ })
1028
+
1029
+
1030
+
1031
+
1032
+ window.saveFile = (from, to, skipUIRecord=false) => {
1033
+ to = to.split("%20").join(" ")
1034
+ to = to.replace(".wav", `.${window.userSettings.audio.format}`)
1035
+
1036
+ // Make the containing folder if it does not already exist
1037
+ let containerFolderPath = to.split("/")
1038
+ containerFolderPath = containerFolderPath.slice(0,containerFolderPath.length-1).join("/")
1039
+
1040
+ try {fs.mkdirSync(containerFolderPath)} catch (e) {/*Do nothing*/}
1041
+
1042
+ // For plugins
1043
+ const pluginData = {
1044
+ game: window.currentGame.gameId,
1045
+ voiceId: window.currentModel.voiceId,
1046
+ voiceName: window.currentModel.voiceName,
1047
+ inputSequence: window.sequenceEditor.inputSequence,
1048
+ letters: window.sequenceEditor.letters,
1049
+ pitch: window.sequenceEditor.pitchNew,
1050
+ durations: window.sequenceEditor.dursNew,
1051
+ vocoder: vocoder_select.value,
1052
+ from, to
1053
+ }
1054
+ const options = {
1055
+ hz: window.userSettings.audio.hz,
1056
+ padStart: window.userSettings.audio.padStart,
1057
+ padEnd: window.userSettings.audio.padEnd,
1058
+ bit_depth: window.userSettings.audio.bitdepth,
1059
+ amplitude: window.userSettings.audio.amplitude,
1060
+ pitchMult: window.userSettings.audio.pitchMult,
1061
+ tempo: window.userSettings.audio.tempo,
1062
+ deessing: window.userSettings.audio.deessing,
1063
+ nr: window.userSettings.audio.nr,
1064
+ nf: window.userSettings.audio.nf,
1065
+ useNR: window.userSettings.audio.useNR,
1066
+ useSR: useSRCkbx.checked
1067
+ }
1068
+ pluginData.audioOptions = options
1069
+ window.pluginsManager.runPlugins(window.pluginsManager.pluginsModules["keep-sample"]["pre"], event="pre keep-sample", pluginData)
1070
+
1071
+ const jsonDataOut = {
1072
+ modelType: window.currentModel.modelType,
1073
+ modelVersion: window.currentModel.modelVersion,
1074
+ version: window.currentModel.version,
1075
+ inputSequence: dialogueInput.value.trim(),
1076
+ pacing: parseFloat(pace_slid.value),
1077
+ letters: window.sequenceEditor.letters,
1078
+ currentVoice: window.sequenceEditor.currentVoice,
1079
+ resetEnergy: window.sequenceEditor.resetEnergy,
1080
+ resetPitch: window.sequenceEditor.resetPitch,
1081
+ resetDurs: window.sequenceEditor.resetDurs,
1082
+ resetEmAngry: window.sequenceEditor.resetEmAngry,
1083
+ resetEmHappy: window.sequenceEditor.resetEmHappy,
1084
+ resetEmSad: window.sequenceEditor.resetEmSad,
1085
+ resetEmSurprise: window.sequenceEditor.resetEmSurprise,
1086
+ styleValuesReset: window.sequenceEditor.styleValuesReset,
1087
+ ampFlatCounter: window.sequenceEditor.ampFlatCounter,
1088
+ inputSequence: window.sequenceEditor.inputSequence,
1089
+ sequence: window.sequenceEditor.sequence,
1090
+ pitchNew: window.sequenceEditor.pitchNew,
1091
+ energyNew: window.sequenceEditor.energyNew,
1092
+ dursNew: window.sequenceEditor.dursNew,
1093
+ emAngryNew: window.sequenceEditor.emAngryNew,
1094
+ emHappyNew: window.sequenceEditor.emHappyNew,
1095
+ emSadNew: window.sequenceEditor.emSadNew,
1096
+ emSurpriseNew: window.sequenceEditor.emSurpriseNew,
1097
+ styleValuesNew: window.sequenceEditor.styleValuesNew,
1098
+ }
1099
+
1100
+ let outputFileName = to.split("/").reverse()[0].split(".").reverse().slice(1, 1000)
1101
+ const toExt = to.split(".").reverse()[0]
1102
+
1103
+ if (window.userSettings.filenameNumericalSeq) {
1104
+ outputFileName = outputFileName[0]+"."+outputFileName.slice(1,1000).reverse().join(".")
1105
+ } else {
1106
+ outputFileName = outputFileName.reverse().join(".")
1107
+ }
1108
+ to = `${to.split("/").reverse().slice(1,10000).reverse().join("/")}/${outputFileName}`
1109
+
1110
+
1111
+ const allFiles = fs.readdirSync(`${path}/output`).filter(fname => fname.includes(from.split("/").reverse()[0].split(".")[0]))
1112
+ const toFolder = to.split("/").reverse().slice(1, 1000).reverse().join("/")
1113
+
1114
+
1115
+ allFiles.forEach(fname => {
1116
+ const ext = fname.split(".").reverse()[0]
1117
+ fs.copyFile(`${path}/output/${fname}`, `${toFolder}/${outputFileName}.${ext}`, err => {
1118
+ if (err) {
1119
+ console.log(err)
1120
+ window.appLogger.log(`Error in saveFile->outputAudio[no ffmpeg]: ${err}`)
1121
+ if (!fs.existsSync(from)) {
1122
+ window.appLogger.log(`${window.i18n.TEMP_FILE_NOT_EXIST}: ${from}`)
1123
+ }
1124
+ if (!fs.existsSync(toFolder)) {
1125
+ window.appLogger.log(`${window.i18n.OUT_DIR_NOT_EXIST}: ${toFolder}`)
1126
+ }
1127
+ } else {
1128
+ if (window.userSettings.outputJSON && window.sequenceEditor.letters.length) {
1129
+ fs.writeFileSync(`${to}.${toExt}.json`, JSON.stringify(jsonDataOut, null, 4))
1130
+ }
1131
+ if (!skipUIRecord) {
1132
+ window.initMainPagePagination(`${window.userSettings[`outpath_${window.currentGame.gameId}`]}/${window.currentModel.voiceId}`)
1133
+ window.refreshRecordsList()
1134
+ }
1135
+ window.pluginsManager.runPlugins(window.pluginsManager.pluginsModules["keep-sample"]["post"], event="post keep-sample", pluginData)
1136
+ }
1137
+ })
1138
+ })
1139
+ }
1140
+
1141
+ window.keepSampleFunction = shiftClick => {
1142
+ if (keepSampleButton.dataset.newFileLocation) {
1143
+
1144
+ const skipUIRecord = keepSampleButton.dataset.newFileLocation.includes("BATCH_EDIT")
1145
+ let fromLocation = window.tempFileLocation
1146
+ let toLocation = keepSampleButton.dataset.newFileLocation.replace("BATCH_EDIT", "")
1147
+
1148
+ if (!skipUIRecord) {
1149
+ toLocation = toLocation.split("/")
1150
+ toLocation[toLocation.length-1] = toLocation[toLocation.length-1].replace(/[\/\\:\*?<>"|]*/g, "")
1151
+ toLocation[toLocation.length-1] = toLocation[toLocation.length-1].replace(/\.wav$/, "").slice(0, window.userSettings.max_filename_chars).replace(/\.$/, "")
1152
+ }
1153
+
1154
+
1155
+ // Numerical file name counter
1156
+ if (!skipUIRecord && window.userSettings.filenameNumericalSeq) {
1157
+ let existingFiles = []
1158
+ try {
1159
+ existingFiles = fs.readdirSync(toLocation.slice(0, toLocation.length-1).join("/")).filter(fname => !fname.endsWith(".json"))
1160
+ } catch (e) {
1161
+ console.log(e)
1162
+ }
1163
+ existingFiles = existingFiles.filter(fname => fname.includes(toLocation[toLocation.length-1]))
1164
+ existingFiles = existingFiles.map(fname => {
1165
+ const parts = fname.split(".")
1166
+ parts.reverse()
1167
+ if (parts.length>2 && parts.reverse()[0].length) {
1168
+ if (parseInt(parts[0]) != NaN) {
1169
+ return parseInt(parts[0])
1170
+ }
1171
+ }
1172
+ return null
1173
+ })
1174
+ existingFiles = existingFiles.filter(val => !!val)
1175
+ if (existingFiles.length==0) {
1176
+ existingFiles.push(0)
1177
+ }
1178
+
1179
+ if (existingFiles.length) {
1180
+ existingFiles = existingFiles.sort((a,b) => {a<b?-1:1})
1181
+ toLocation[toLocation.length-1] = `${toLocation[toLocation.length-1]}.${String(existingFiles[existingFiles.length-1]+1).padStart(4, "0")}`
1182
+ }
1183
+ }
1184
+
1185
+
1186
+ if (!skipUIRecord) {
1187
+ toLocation[toLocation.length-1] += ".wav"
1188
+ toLocation = toLocation.join("/")
1189
+ }
1190
+
1191
+
1192
+ const outFolder = toLocation.split("/").reverse().slice(2, 100).reverse().join("/")
1193
+ if (!fs.existsSync(outFolder)) {
1194
+ return void window.errorModal(`${window.i18n.OUT_DIR_NOT_EXIST}:<br><br><i>${outFolder}</i><br><br>${window.i18n.YOU_CAN_CHANGE_IN_SETTINGS}`)
1195
+ }
1196
+
1197
+ // File name conflict
1198
+ const alreadyExists = fs.existsSync(toLocation)
1199
+ if (alreadyExists || shiftClick) {
1200
+
1201
+ const promptText = alreadyExists ? window.i18n.FILE_EXISTS_ADJUST : window.i18n.ENTER_FILE_NAME
1202
+
1203
+ createModal("prompt", {
1204
+ prompt: promptText,
1205
+ value: toLocation.split("/").reverse()[0].replace(".wav", `.${window.userSettings.audio.format}`)
1206
+ }).then(newFileName => {
1207
+
1208
+ let toLocationOut = toLocation.split("/").reverse()
1209
+ toLocationOut[0] = newFileName.replace(`.${window.userSettings.audio.format}`, "") + `.${window.userSettings.audio.format}`
1210
+ let outDir = toLocationOut
1211
+ outDir.shift()
1212
+
1213
+ newFileName = (newFileName.replace(`.${window.userSettings.audio.format}`, "") + `.${window.userSettings.audio.format}`).replace(/[\/\\:\*?<>"|]*/g, "")
1214
+ toLocationOut.reverse()
1215
+ toLocationOut.push(newFileName)
1216
+
1217
+ if (fs.existsSync(outDir.slice(0, outDir.length-1).join("/"))) {
1218
+ const existingFiles = fs.readdirSync(outDir.slice(0, outDir.length-1).join("/"))
1219
+ const existingFileConflict = existingFiles.filter(name => name==newFileName)
1220
+
1221
+
1222
+ const finalOutLocation = toLocationOut.join("/")
1223
+
1224
+ if (existingFileConflict.length) {
1225
+ // Remove the entry from the output files' preview
1226
+ Array.from(voiceSamples.querySelectorAll("div.sample")).forEach(sampleElem => {
1227
+ let sourceSrc = sampleElem.children[0].children[0].innerText
1228
+ sourceSrc = sourceSrc.split("/").reverse()
1229
+ const finalFileName = finalOutLocation.split("/").reverse()
1230
+
1231
+ if (sourceSrc[0] == finalFileName[0]) {
1232
+ sampleElem.parentNode.removeChild(sampleElem)
1233
+ }
1234
+ })
1235
+
1236
+ // Remove the old file and write the new one in
1237
+ fs.unlink(finalOutLocation, err => {
1238
+ if (err) {
1239
+ console.log(err)
1240
+ window.appLogger.log(`Error in keepSample: ${err}`)
1241
+ }
1242
+ window.saveFile(fromLocation, finalOutLocation, skipUIRecord)
1243
+ })
1244
+ return
1245
+ } else {
1246
+ window.saveFile(fromLocation, toLocationOut.join("/"), skipUIRecord)
1247
+ return
1248
+ }
1249
+ }
1250
+ window.saveFile(fromLocation, toLocationOut.join("/"), skipUIRecord)
1251
+ })
1252
+
1253
+ } else {
1254
+ window.saveFile(fromLocation, toLocation, skipUIRecord)
1255
+ }
1256
+ }
1257
+ }
1258
+ keepSampleButton.addEventListener("click", event => keepSampleFunction(event.shiftKey))
1259
+
1260
+
1261
+
1262
+ // Weird recursive intermittent promises to repeatedly check if the server is up yet - but it works!
1263
+ window.serverIsUp = false
1264
+ const serverStartingMessage = `${window.i18n.LOADING}...<br>${window.i18n.MAY_TAKE_A_MINUTE}<br><br>${window.i18n.STARTING_PYTHON}...`
1265
+ window.doWeirdServerStartupCheck = () => {
1266
+ const check = () => {
1267
+ return new Promise(topResolve => {
1268
+ if (window.serverIsUp) {
1269
+ topResolve()
1270
+ } else {
1271
+ (new Promise((resolve, reject) => {
1272
+ // Gather the model paths to send to the server
1273
+ const modelsPaths = {}
1274
+ Object.keys(window.userSettings).filter(key => key.includes("modelspath_")).forEach(key => {
1275
+ modelsPaths[key.split("_")[1]] = window.userSettings[key]
1276
+ })
1277
+
1278
+ doFetch(`http://localhost:8008/checkReady`, {
1279
+ method: "Post",
1280
+ body: JSON.stringify({
1281
+ device: (window.userSettings.useGPU&&window.userSettings.installation=="gpu")?"gpu":"cpu",
1282
+ modelsPaths: JSON.stringify(modelsPaths)
1283
+ })
1284
+ }).then(r => r.text()).then(r => {
1285
+ closeModal([document.querySelector("#activeModal"), modalContainer], [totdContainer, EULAContainer], true).then(() => {
1286
+ window.pluginsManager.updateUI()
1287
+ if (!window.pluginsManager.hasRunPostStartPlugins) {
1288
+ window.pluginsManager.hasRunPostStartPlugins = true
1289
+ window.pluginsManager.runPlugins(window.pluginsManager.pluginsModules["start"]["post"], event="post start")
1290
+ window.electronBrowserWindow.setProgressBar(-1)
1291
+ window.checkForWorkshopInstallations()
1292
+ }
1293
+ })
1294
+ window.serverIsUp = true
1295
+ if (window.userSettings.installation=="cpu") {
1296
+
1297
+ if (useGPUCbx.checked) {
1298
+ doFetch(`http://localhost:8008/setDevice`, {
1299
+ method: "Post",
1300
+ body: JSON.stringify({device: "cpu"})
1301
+ })
1302
+ }
1303
+ useGPUCbx.checked = false
1304
+ useGPUCbx.disabled = true
1305
+ window.userSettings.useGPU = false
1306
+ saveUserSettings()
1307
+ }
1308
+
1309
+ resolve()
1310
+ }).catch((err) => {
1311
+ reject()
1312
+ })
1313
+ })).catch(() => {
1314
+ setTimeout(async () => {
1315
+ await check()
1316
+ topResolve()
1317
+ }, 100)
1318
+ })
1319
+ }
1320
+ })
1321
+ }
1322
+
1323
+ check()
1324
+ }
1325
+ window.doWeirdServerStartupCheck()
1326
+
1327
+ modalContainer.addEventListener("click", event => {
1328
+ try {
1329
+ if (event.target==modalContainer && activeModal.dataset.type!="spinner") {
1330
+ closeModal()
1331
+ }
1332
+ } catch (e) {}
1333
+ })
1334
+
1335
+
1336
+ // Cached UI stuff
1337
+ // =========
1338
+ dialogueInput.addEventListener("keyup", (event) => {
1339
+ localStorage.setItem("dialogueInput", " "+dialogueInput.value.trim()+" ")
1340
+ window.sequenceEditor.hasChanged = true
1341
+ })
1342
+
1343
+ const dialogueInputCache = localStorage.getItem("dialogueInput")
1344
+
1345
+ if (dialogueInputCache) {
1346
+ dialogueInput.value = dialogueInputCache
1347
+ }
1348
+
1349
+ // =========
1350
+
1351
+
1352
+
1353
+
1354
+
1355
+
1356
+
1357
+
1358
+ vocoder_select.value = window.userSettings.vocoder.includes(".hg.") ? "qnd" : window.userSettings.vocoder
1359
+ window.changeVocoder = vocoder => {
1360
+ return new Promise(resolve => {
1361
+ spinnerModal(window.i18n.CHANGING_MODELS)
1362
+ doFetch(`http://localhost:8008/setVocoder`, {
1363
+ method: "Post",
1364
+ body: JSON.stringify({
1365
+ vocoder,
1366
+ modelPath: vocoder=="256_waveglow" ? window.userSettings.waveglow_path : window.userSettings.bigwaveglow_path
1367
+ })
1368
+ }).then(r=>r.text()).then((res) => {
1369
+ closeModal().then(() => {
1370
+ setTimeout(() => {
1371
+ if (res=="ENOENT") {
1372
+ vocoder_select.value = window.userSettings.vocoder
1373
+ window.errorModal(`${window.i18n.BATCH_MODEL_NOT_FOUND}.${vocoder.includes("waveglow")?" "+window.i18n.BATCH_DOWNLOAD_WAVEGLOW:""}`)
1374
+ resolve()
1375
+ } else {
1376
+ window.batch_state.lastVocoder = vocoder
1377
+ window.userSettings.vocoder = vocoder
1378
+ saveUserSettings()
1379
+ resolve()
1380
+ }
1381
+ }, 300)
1382
+ })
1383
+ })
1384
+ })
1385
+ }
1386
+ vocoder_select.addEventListener("change", () => window.changeVocoder(vocoder_select.value))
1387
+
1388
+ useSRCkbx.addEventListener("click", () => {
1389
+ let userHasSeenThisAlready = localStorage.getItem("useSRHintSeen")
1390
+ if (useSRCkbx.checked && !userHasSeenThisAlready) {
1391
+ window.confirmModal(window.i18n.USE_SR_HINT).then(resp => {
1392
+ if (resp) {
1393
+ localStorage.setItem("useSRHintSeen", "true")
1394
+ }
1395
+ })
1396
+ }
1397
+
1398
+ })
1399
+
1400
+ dialogueInput.addEventListener("contextmenu", event => {
1401
+ event.preventDefault()
1402
+ ipcRenderer.send('show-context-menu')
1403
+ })
1404
+ ipcRenderer.on('context-menu-command', (e, command) => {
1405
+ if (command=="context-copy") {
1406
+ if (dialogueInput.selectionStart != dialogueInput.selectionEnd) {
1407
+ clipboard.writeText(dialogueInput.value.slice(dialogueInput.selectionStart, dialogueInput.selectionEnd))
1408
+ }
1409
+ } else if (command=="context-paste") {
1410
+ if (clipboard.readText().length) {
1411
+ let newString = dialogueInput.value.slice(0, dialogueInput.selectionStart) + clipboard.readText() + dialogueInput.value.slice(dialogueInput.selectionEnd, dialogueInput.value.length)
1412
+ dialogueInput.value = newString
1413
+ }
1414
+ }
1415
+ })
1416
+
1417
+
1418
+ window.setupModal(workbenchIcon, workbenchContainer, () => window.initVoiceWorkbench())
1419
+
1420
+
1421
+ // Info
1422
+ // ====
1423
+ window.setupModal(infoIcon, infoContainer)
1424
+
1425
+
1426
+ // Patreon
1427
+ // =======
1428
+ // window.setupModal(patreonIcon, patreonContainer, () => {
1429
+ // const data = fs.readFileSync(`${path}/patreon.txt`, "utf8") + ", minermanb"
1430
+ // creditsList.innerHTML = data
1431
+ // })
1432
+
1433
+
1434
+ // Updates
1435
+ // =======
1436
+ app_version.innerHTML = window.appVersion
1437
+ updatesVersions.innerHTML = `${window.i18n.THIS_APP_VERSION}: ${window.appVersion}`
1438
+
1439
+ const checkForUpdates = () => {
1440
+ doFetch("http://danruta.co.uk/xvasynth_updates.txt").then(r=>r.json()).then(data => {
1441
+ fs.writeFileSync(`${path}/updates.json`, JSON.stringify(data), "utf8")
1442
+ checkUpdates.innerHTML = window.i18n.CHECK_FOR_UPDATES
1443
+ window.showUpdates()
1444
+ }).catch(() => {
1445
+ checkUpdates.innerHTML = window.i18n.CANT_REACH_SERVER
1446
+ })
1447
+ }
1448
+ window.showUpdates = () => {
1449
+ window.updatesLog = fs.readFileSync(`${path}/updates.json`, "utf8")
1450
+ window.updatesLog = JSON.parse(window.updatesLog)
1451
+ const sortedLogVersions = Object.keys(window.updatesLog).map( a => a.split('.').map( n => +n+100000 ).join('.') ).sort()
1452
+ .map( a => a.split('.').map( n => +n-100000 ).join('.') )
1453
+
1454
+ const appVersion = window.appVersion.replace("v", "")
1455
+ const appIsUpToDate = sortedLogVersions.indexOf(appVersion)==(sortedLogVersions.length-1) || sortedLogVersions.indexOf(appVersion)==-1
1456
+
1457
+ if (!appIsUpToDate) {
1458
+ update_nothing.style.display = "none"
1459
+ update_something.style.display = "block"
1460
+ updatesVersions.innerHTML = `${window.i18n.THIS_APP_VERSION}: ${appVersion}. ${window.i18n.AVAILABLE}: ${sortedLogVersions[sortedLogVersions.length-1]}`
1461
+ } else {
1462
+ updatesVersions.innerHTML = `${window.i18n.THIS_APP_VERSION}: ${appVersion}. ${window.i18n.UPTODATE}`
1463
+ }
1464
+
1465
+ updatesLogList.innerHTML = ""
1466
+ sortedLogVersions.reverse().forEach(version => {
1467
+ const versionLabel = createElem("h2", version)
1468
+ const logItem = createElem("div", versionLabel)
1469
+ window.updatesLog[version].split("\n").forEach(line => {
1470
+ logItem.appendChild(createElem("div", line))
1471
+ })
1472
+ updatesLogList.appendChild(logItem)
1473
+ })
1474
+ }
1475
+ checkForUpdates()
1476
+ window.setupModal(updatesIcon, updatesContainer)
1477
+
1478
+ checkUpdates.addEventListener("click", () => {
1479
+ checkUpdates.innerHTML = window.i18n.CHECKING_FOR_UPDATES
1480
+ checkForUpdates()
1481
+ })
1482
+ window.showUpdates()
1483
+
1484
+
1485
+ // Batch generation
1486
+ // ========
1487
+ window.setupModal(batchIcon, batchGenerationContainer)
1488
+
1489
+ // Settings
1490
+ // ========
1491
+ window.setupModal(settingsCog, settingsContainer)
1492
+
1493
+ // Change Game
1494
+ // ===========
1495
+ window.setupModal(changeGameButton, gameSelectionContainer)
1496
+ changeGameButton.addEventListener("click", () => searchGameInput.focus())
1497
+
1498
+ window.gameAssets = {}
1499
+
1500
+ window.updateGameList = (doLoadAllModels=true) => {
1501
+ gameSelectionListContainer.innerHTML = ""
1502
+ const fileNames = fs.readdirSync(`${window.path}/assets`)
1503
+
1504
+ let totalVoices = 0
1505
+ let totalGames = new Set()
1506
+
1507
+ const itemsToSort = []
1508
+ // const gameIDs = doLoadAllModels ? fileNames.filter(fn=>fn.endsWith(".json")) : Object.keys(window.games).map(gID => gID+".json")
1509
+ const gameIDs = fileNames.filter(fn=>fn.endsWith(".json"))
1510
+
1511
+ gameIDs.forEach(gameId => {
1512
+
1513
+ const metadata = fs.existsSync(`${window.path}/assets/${gameId}`) ? JSON.parse(fs.readFileSync(`${window.path}/assets/${gameId}`)) : window.games[gameId.replace(".json", "")].dummyGameTheme
1514
+ gameId = gameId.replace(".json", "")
1515
+ metadata.gameId = gameId
1516
+ const assetFile = metadata.assetFile
1517
+
1518
+ const gameSelection = createElem("div.gameSelection")
1519
+ gameSelection.style.background = `url("assets/${assetFile}")`
1520
+
1521
+ const gameName = metadata.gameName
1522
+ const gameSelectionContent = createElem("div.gameSelectionContent")
1523
+
1524
+
1525
+ let numVoices = 0
1526
+ const modelsPath = window.userSettings[`modelspath_${gameId}`]
1527
+ if (fs.existsSync(modelsPath)) {
1528
+ const files = fs.readdirSync(modelsPath)
1529
+ numVoices = files.filter(fn => fn.includes(".json")).length
1530
+ totalVoices += numVoices
1531
+ }
1532
+ if (numVoices==0) {
1533
+ gameSelectionContent.style.background = "rgba(150,150,150,0.7)"
1534
+ } else {
1535
+ gameSelectionContent.classList.add("gameSelectionContentToHover")
1536
+ totalGames.add(gameId)
1537
+ }
1538
+
1539
+ gameSelectionContent.appendChild(createElem("div", `${numVoices} ${(numVoices>1||numVoices==0)?window.i18n.VOICE_PLURAL:window.i18n.VOICE}`))
1540
+ gameSelectionContent.appendChild(createElem("div", gameName))
1541
+
1542
+ gameSelection.appendChild(gameSelectionContent)
1543
+
1544
+ window.gameAssets[gameId] = metadata
1545
+ gameSelectionContent.addEventListener("click", () => {
1546
+ voiceSearchInput.focus()
1547
+ searchGameInput.value = ""
1548
+ changeGame(metadata)
1549
+ closeModal(gameSelectionContainer)
1550
+ Array.from(gameSelectionListContainer.children).forEach(elem => elem.style.display="flex")
1551
+ })
1552
+
1553
+ itemsToSort.push([numVoices, gameSelection])
1554
+
1555
+ const modelsDir = window.userSettings[`modelspath_${gameId}`]
1556
+ if (!window.watchedModelsDirs.includes(modelsDir)) {
1557
+ window.watchedModelsDirs.push(modelsDir)
1558
+
1559
+ try {
1560
+ fs.watch(modelsDir, {recursive: false, persistent: true}, (eventType, filename) => {
1561
+ if (window.userSettings.autoReloadVoices) {
1562
+ if (doLoadAllModels) {
1563
+ loadAllModels().then(() => changeGame(metadata))
1564
+ }
1565
+ }
1566
+ })
1567
+ } catch (e) {
1568
+ // console.log(e)
1569
+ }
1570
+ }
1571
+ })
1572
+
1573
+
1574
+ itemsToSort.sort((a,b) => a[0]<b[0]?1:-1).forEach(([numVoices, elem]) => {
1575
+ gameSelectionListContainer.appendChild(elem)
1576
+ })
1577
+
1578
+ searchGameInput.addEventListener("keyup", (event) => {
1579
+
1580
+ if (event.key=="Enter") {
1581
+ const voiceElems = Array.from(gameSelectionListContainer.children).filter(elem => elem.style.display=="flex")
1582
+ if (voiceElems.length==1) {
1583
+ voiceElems[0].children[0].click()
1584
+ searchGameInput.value = ""
1585
+ }
1586
+ }
1587
+
1588
+ const voiceElems = Array.from(gameSelectionListContainer.children)
1589
+ if (searchGameInput.value.length) {
1590
+ voiceElems.forEach(elem => {
1591
+ if (elem.children[0].children[1].innerHTML.toLowerCase().includes(searchGameInput.value)) {
1592
+ elem.style.display="flex"
1593
+ } else {
1594
+ elem.style.display="none"
1595
+ }
1596
+ })
1597
+
1598
+ } else {
1599
+ voiceElems.forEach(elem => elem.style.display="block")
1600
+ }
1601
+ })
1602
+
1603
+ searchGameInput.placeholder = window.i18n.SEARCH_N_GAMES_WITH_N2_VOICES.replace("_1", Array.from(totalGames).length).replace("_2", totalVoices)
1604
+
1605
+ if (doLoadAllModels) {
1606
+ loadAllModels().then(() => {
1607
+ // Load the last selected game
1608
+ const lastGame = localStorage.getItem("lastGame")
1609
+
1610
+ if (lastGame) {
1611
+ changeGame(JSON.parse(lastGame))
1612
+ }
1613
+ })
1614
+ }
1615
+ }
1616
+ window.updateGameList()
1617
+
1618
+
1619
+ // Embeddings
1620
+ // ==========
1621
+ window.setupModal(embeddingsIcon, embeddingsContainer, () => {
1622
+ setTimeout(() => {
1623
+ if (window.embeddingsState.isReady) {
1624
+ window.embeddings_updateSize()
1625
+ }
1626
+ }, 100)
1627
+ window.embeddings_updateSize()
1628
+ window.embeddingsState.isOpen = true
1629
+ if (!window.embeddingsState.ready) {
1630
+ setTimeout(() => {
1631
+ window.embeddingsState.ready = true
1632
+ window.initEmbeddingsScene()
1633
+ setTimeout(() => {
1634
+ window.computeEmbsAndDimReduction(true)
1635
+ }, 300)
1636
+ }, 100)
1637
+ }
1638
+ }, () => {
1639
+ window.embeddingsState.isOpen = false
1640
+ })
1641
+
1642
+ // Arpabet
1643
+ // =======
1644
+ window.setupModal(arpabetIcon, arpabetContainer, () => setTimeout(()=> !window.arpabetMenuState.hasInitialised && window.refreshDictionariesList(), 100))
1645
+
1646
+
1647
+ // Plugins
1648
+ // =======
1649
+ window.setupModal(pluginsIcon, pluginsContainer)
1650
+
1651
+
1652
+ window.setupModal(style_emb_manage_btn, styleEmbeddingsContainer, window.styleEmbsModalOpenCallback)
1653
+
1654
+
1655
+ // Other
1656
+ // =====
1657
+ window.setupModal(reset_what_open_btn, resetContainer)
1658
+ window.setupModal(i18n_batch_metadata_open_btn, batchMetadataCSVContainer)
1659
+
1660
+ voiceSearchInput.addEventListener("keyup", () => {
1661
+
1662
+ if (event.key=="Enter") {
1663
+ const voiceElems = Array.from(voiceTypeContainer.children).filter(elem => elem.style.display=="block")
1664
+ if (voiceElems.length==1) {
1665
+ voiceElems[0].click()
1666
+ generateVoiceButton.click()
1667
+ voiceSearchInput.value = ""
1668
+ }
1669
+ }
1670
+
1671
+ const voiceElems = Array.from(voiceTypeContainer.children)
1672
+
1673
+ if (voiceSearchInput.value.length) {
1674
+ voiceElems.forEach(elem => {
1675
+ if (elem.innerHTML.toLowerCase().includes(voiceSearchInput.value)) {
1676
+ elem.style.display="block"
1677
+ } else {
1678
+ elem.style.display="none"
1679
+ }
1680
+ })
1681
+
1682
+ } else {
1683
+ voiceElems.forEach(elem => elem.style.display="block")
1684
+ }
1685
+ })
1686
+
1687
+ // Splash/EULA
1688
+ splashNextButton1.addEventListener("click", () => {
1689
+ splash_screen1.style.display = "none"
1690
+ splash_screen2.style.display = "flex"
1691
+ })
1692
+ EULA_closeButon.addEventListener("click", () => {
1693
+ if (EULA_accept_ckbx.checked) {
1694
+ closeModal(EULAContainer)
1695
+ window.userSettings.EULA_accepted_2023 = true
1696
+ saveUserSettings()
1697
+
1698
+ if (!window.totd_state.startupChecked) {
1699
+ window.showTipIfEnabledAndNewDay().then(() => {
1700
+ if (!serverIsUp) {
1701
+ spinnerModal(serverStartingMessage)
1702
+ }
1703
+ })
1704
+ }
1705
+
1706
+ if (!serverIsUp && totdContainer.style.display=="none") {
1707
+ window.spinnerModal(serverStartingMessage)
1708
+ }
1709
+ }
1710
+ })
1711
+ if (!Object.keys(window.userSettings).includes("EULA_accepted_2023") || !window.userSettings.EULA_accepted_2023) {
1712
+ EULAContainer.style.opacity = 0
1713
+ EULAContainer.style.display = "flex"
1714
+ requestAnimationFrame(() => requestAnimationFrame(() => EULAContainer.style.opacity = 1))
1715
+ requestAnimationFrame(() => requestAnimationFrame(() => chromeBar.style.opacity = 1))
1716
+ } else {
1717
+ window.showTipIfEnabledAndNewDay().then(() => {
1718
+ // If not, or the user closed the window quickly, show the server is starting message if still booting up
1719
+ if (!window.serverIsUp) {
1720
+ spinnerModal(serverStartingMessage)
1721
+ }
1722
+ })
1723
+ }
1724
+
1725
+
1726
+ // Links
1727
+ document.querySelectorAll('a[href^="http"]').forEach(a => a.addEventListener("click", e => {
1728
+ event.preventDefault()
1729
+ shell.openExternal(a.href)
1730
+ }))
main.js β†’ resources/app/main.js RENAMED
File without changes
package.json β†’ resources/app/package.json RENAMED
@@ -16,12 +16,6 @@
16
  "electron-packager": "^17.1.2"
17
  },
18
  "dependencies": {
19
- "@electron/remote": "^2.0.9",
20
- "discord-rich-presence": "0.0.8",
21
- "fs-extra": "^9.1.0",
22
- "node-fetch": "^2.1.2",
23
- "node-nvidia-smi": "^1.0.0",
24
- "unzipper": "^0.10.11",
25
- "zip-dir": "^2.0.0"
26
  }
27
  }
 
16
  "electron-packager": "^17.1.2"
17
  },
18
  "dependencies": {
19
+ "@electron/remote": "^2.0.9"
 
 
 
 
 
 
20
  }
21
  }
patreon.txt β†’ resources/app/patreon.txt RENAMED
File without changes
plugins.txt β†’ resources/app/plugins.txt RENAMED
File without changes
repositories.json β†’ resources/app/repositories.json RENAMED
File without changes
requirements_cpu.txt β†’ resources/app/requirements_cpu.txt RENAMED
File without changes
style.css β†’ resources/app/style.css RENAMED
@@ -59,6 +59,10 @@ button:disabled {
59
  filter: drop-shadow(1px 1px 1px rgba(0, 0, 0, 1))
60
  }
61
 
 
 
 
 
62
  body {
63
  margin: 0;
64
  overflow: hidden;
@@ -80,7 +84,7 @@ body {
80
  #right {
81
  height: 100%;
82
  flex-grow: 1;
83
- width: 50vw;
84
  }
85
 
86
  #left {
@@ -89,13 +93,15 @@ body {
89
  }
90
 
91
  #right {
92
- width: calc(100vw - 300px);
 
 
 
93
  z-index: 1;
94
  }
95
 
96
  #rightBG1,
97
  #rightBG2 {
98
- width: calc(100vw - 300px);
99
  background: linear-gradient(0deg, grey 0, rgba(0, 0, 0, 0)), grey;
100
  background-repeat: no-repeat !important;
101
  background-position-x: 100% !important;
@@ -510,7 +516,7 @@ audio {
510
  }
511
 
512
  #dialogueInput {
513
- width: calc(95vw - 300px) !important;
514
  margin-left: 1vw;
515
  }
516
 
 
59
  filter: drop-shadow(1px 1px 1px rgba(0, 0, 0, 1))
60
  }
61
 
62
+ .tool-icon {
63
+ filter: invert();
64
+ }
65
+
66
  body {
67
  margin: 0;
68
  overflow: hidden;
 
84
  #right {
85
  height: 100%;
86
  flex-grow: 1;
87
+ width: 100vw;
88
  }
89
 
90
  #left {
 
93
  }
94
 
95
  #right {
96
+ background: linear-gradient(0deg, #999 0, rgba(0, 0, 0, 0)), black;
97
+ background-repeat: no-repeat !important;
98
+ background-position-x: 100% !important;
99
+ background-size: cover !important;
100
  z-index: 1;
101
  }
102
 
103
  #rightBG1,
104
  #rightBG2 {
 
105
  background: linear-gradient(0deg, grey 0, rgba(0, 0, 0, 0)), grey;
106
  background-repeat: no-repeat !important;
107
  background-position-x: 100% !important;
 
516
  }
517
 
518
  #dialogueInput {
519
+ color: #000 !important;
520
  margin-left: 1vw;
521
  }
522
 
updates.json β†’ resources/app/updates.json RENAMED
File without changes