tspb commited on
Commit
1627169
·
verified ·
1 Parent(s): 134f09f

Update index.html

Browse files

add stfileselector button and Adapted for Mobile Browser

Files changed (1) hide show
  1. index.html +292 -93
index.html CHANGED
@@ -2,27 +2,186 @@
2
  <html lang="en">
3
  <head>
4
  <meta charset="UTF-8">
 
5
  <title>RISU File Tools</title>
6
  <script src="./pako.min.js"></script>
7
  <script src="./msgpackr.min.js"></script>
8
  <style>
9
- .container { margin: 20px; }
10
- textarea { width: 100%; height: 200px; margin: 10px 0; }
11
- .output { margin-top: 20px; }
12
- pre { white-space: pre-wrap; }
13
- .tool-section { margin-bottom: 30px; padding: 20px; border: 1px solid #ddd; }
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
14
  </style>
15
  </head>
16
  <body>
17
  <div class="container">
18
  <div class="tool-section">
19
  <h1>ST to Risu Converter</h1>
20
- <label for="stInput">Paste ST JSON here:</label>
21
- <textarea id="stInput" placeholder="Paste ST JSON content..."></textarea>
 
 
 
 
 
 
22
 
23
- <label for="risuDefault">Paste Risu Default JSON here:</label>
24
- <textarea id="risuDefault" placeholder="Paste Risu Default JSON content...">
25
- {
26
  "name": "Default",
27
  "apiType": "instructgpt35",
28
  "openAIKey": "",
@@ -233,65 +392,97 @@
233
  "enableCustomFlags": false,
234
  "regex": [],
235
  "image": ""
236
- }
237
- </textarea>
238
 
239
- <button id="convertButton">Convert</button>
 
 
240
 
241
  <div class="output">
242
- <h2>Converted Risu JSON:</h2>
243
- <button id="copyButton">Copy</button>
244
- <button id="saveButton">Save as JSON</button>
245
- <pre id="stOutput"></pre>
 
246
  </div>
247
  </div>
248
 
249
  <div class="tool-section">
250
  <h1>RISU Preset File Tools</h1>
251
- <div>
252
  <h2>Decrypt RISU Preset</h2>
253
- <input type="file" id="fileInput" accept=".risupreset,.risup"/>
254
- <button id="recoverButton">Recover Preset</button>
 
 
255
  </div>
256
 
257
- <div style="margin-top: 20px;">
258
  <h2>Encrypt to RISU Preset</h2>
259
- <input type="file" id="jsonInput" accept=".json"/>
260
- <button id="encryptButton">Create .risup</button>
 
 
261
  </div>
262
 
 
263
  <pre id="output"></pre>
264
  </div>
265
  </div>
266
 
267
  <script>
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
268
 
269
  // Copy button functionality
270
- document.getElementById("copyButton").addEventListener("click", function() {
271
- const outputText = document.getElementById("stOutput").textContent;
272
- navigator.clipboard.writeText(outputText).then(function() {
273
- alert("Copied to clipboard!");
274
- }).catch(function(err) {
275
- alert("Failed to copy text: " + err);
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
276
  });
277
- });
278
-
279
- // Save as JSON button functionality
280
- document.getElementById("saveButton").addEventListener("click", function() {
281
- const outputText = document.getElementById("stOutput").textContent;
282
-
283
- // Ensure the output is valid JSON
284
- try {
285
- const jsonObject = JSON.parse(outputText); // Validate JSON format
286
- const blob = new Blob([JSON.stringify(jsonObject, null, 2)], { type: 'application/json' });
287
- const link = document.createElement('a');
288
- link.href = URL.createObjectURL(blob);
289
- link.download = 'converted_risu.json'; // File name
290
- link.click();
291
- } catch (error) {
292
- alert("The output is not valid JSON.");
293
- }
294
- });
295
 
296
  // ST to Risu Converter Logic
297
  document.getElementById('convertButton').addEventListener('click', function convert() {
@@ -507,68 +698,64 @@
507
  );
508
  }
509
 
510
- async function recoverPresetFromFile(file) {
511
- try {
512
- const arrayBuffer = await file.arrayBuffer();
513
- const uint8Array = new Uint8Array(arrayBuffer);
 
514
 
515
- let finalData;
516
 
517
- if (file.name.endsWith('.risup')) {
518
- // 处理 .risup 文件
519
- const wasmInstance = await initWasm();
520
- const decodedData = await decodeRPack(uint8Array, wasmInstance);
521
- console.log("1. RPack decoded:", decodedData);
522
 
523
- const decompressedData = pako.inflate(decodedData);
524
- console.log("2. Decompressed:", decompressedData);
525
 
526
- const firstDecode = msgpackr.decode(decompressedData);
527
- console.log("3. First msgpack decode:", firstDecode);
528
 
529
- const decryptedData = await decryptBuffer(firstDecode.preset, 'risupreset');
530
- console.log("4. Decrypted data:", new Uint8Array(decryptedData));
531
 
532
- finalData = msgpackr.decode(new Uint8Array(decryptedData));
533
- console.log("5. Final decoded data:", finalData);
534
 
535
- } else if (file.name.endsWith('.risupreset')) {
536
- // 处理 .risupreset 文件
537
- const decompressedData = pako.inflate(uint8Array);
538
- console.log("1. Decompressed:", decompressedData);
539
 
540
- const firstDecode = msgpackr.decode(decompressedData);
541
- console.log("2. First msgpack decode:", firstDecode);
542
 
543
- const encryptedPreset = firstDecode.preset ?? firstDecode.pres;
544
- if (!encryptedPreset) {
545
- throw new Error("Missing `preset` or `pres` field in .risupreset file.");
546
- }
547
 
548
- const decryptedData = await decryptBuffer(encryptedPreset, 'risupreset');
549
- console.log("3. Decrypted data:", new Uint8Array(decryptedData));
550
 
551
- finalData = msgpackr.decode(new Uint8Array(decryptedData));
552
- console.log("4. Final decoded data:", finalData);
 
 
 
553
 
554
- } else {
555
- throw new Error('Unsupported file format');
 
 
 
 
 
556
  }
557
 
558
- // 成功解析数据后显示
559
- console.log("Final decoded data:", finalData);
560
- document.getElementById('output').textContent = JSON.stringify(finalData, null, 2);
561
-
562
- } catch (error) {
563
- // 捕获错误并显示
564
- console.error('Error recovering preset:', error);
565
- document.getElementById('output').textContent = `Error: ${error.message}\n\nStack: ${error.stack}`;
566
- }
567
- }
568
-
569
-
570
  async function createPresetFile(file) {
571
  try {
 
572
  const text = await file.text();
573
  const jsonData = JSON.parse(text);
574
 
@@ -605,9 +792,21 @@ async function recoverPresetFromFile(file) {
605
  } catch (error) {
606
  console.error('Error creating preset:', error);
607
  document.getElementById('output').textContent = `Error: ${error.message}\n\nStack: ${error.stack}`;
 
 
608
  }
609
  }
610
 
 
 
 
 
 
 
 
 
 
 
611
  document.getElementById('recoverButton').addEventListener('click', () => {
612
  const fileInput = document.getElementById('fileInput');
613
  const file = fileInput.files[0];
 
2
  <html lang="en">
3
  <head>
4
  <meta charset="UTF-8">
5
+ <meta name="viewport" content="width=device-width, initial-scale=1.0">
6
  <title>RISU File Tools</title>
7
  <script src="./pako.min.js"></script>
8
  <script src="./msgpackr.min.js"></script>
9
  <style>
10
+ /* 保持之前的所有样式不变 */
11
+ * {
12
+ margin: 0;
13
+ padding: 0;
14
+ box-sizing: border-box;
15
+ }
16
+
17
+ body {
18
+ font-family: -apple-system, BlinkMacSystemFont, 'Segoe UI', Roboto, sans-serif;
19
+ line-height: 1.6;
20
+ padding: 1rem;
21
+ background-color: #f5f5f5;
22
+ }
23
+
24
+ .container {
25
+ max-width: 1200px;
26
+ margin: 0 auto;
27
+ padding: 1rem;
28
+ }
29
+
30
+ .tool-section {
31
+ background: #fff;
32
+ border-radius: 8px;
33
+ box-shadow: 0 2px 4px rgba(0,0,0,0.1);
34
+ padding: 1.5rem;
35
+ margin-bottom: 2rem;
36
+ }
37
+
38
+ h1 {
39
+ font-size: 1.5rem;
40
+ color: #333;
41
+ margin-bottom: 1rem;
42
+ }
43
+
44
+ h2 {
45
+ font-size: 1.2rem;
46
+ color: #444;
47
+ margin: 1rem 0;
48
+ }
49
+
50
+ .input-group {
51
+ margin-bottom: 1rem;
52
+ }
53
+
54
+ label {
55
+ display: block;
56
+ margin-bottom: 0.5rem;
57
+ color: #555;
58
+ }
59
+
60
+ textarea {
61
+ width: 100%;
62
+ min-height: 150px;
63
+ padding: 0.8rem;
64
+ border: 1px solid #ddd;
65
+ border-radius: 4px;
66
+ resize: vertical;
67
+ font-family: monospace;
68
+ margin-bottom: 1rem;
69
+ }
70
+
71
+ .button-group {
72
+ display: flex;
73
+ gap: 0.5rem;
74
+ flex-wrap: wrap;
75
+ margin: 1rem 0;
76
+ }
77
+
78
+ button {
79
+ padding: 0.6rem 1.2rem;
80
+ border: none;
81
+ border-radius: 4px;
82
+ background-color: #007bff;
83
+ color: white;
84
+ cursor: pointer;
85
+ transition: background-color 0.2s;
86
+ }
87
+
88
+ button:hover {
89
+ background-color: #0056b3;
90
+ }
91
+
92
+ .file-input-wrapper {
93
+ display: flex;
94
+ align-items: center;
95
+ gap: 1rem;
96
+ margin-bottom: 1rem;
97
+ flex-wrap: wrap;
98
+ }
99
+
100
+ input[type="file"] {
101
+ max-width: 100%;
102
+ }
103
+
104
+ .output {
105
+ margin-top: 1.5rem;
106
+ padding: 1rem;
107
+ background: #f8f9fa;
108
+ border-radius: 4px;
109
+ }
110
+
111
+ pre {
112
+ white-space: pre-wrap;
113
+ word-wrap: break-word;
114
+ padding: 1rem;
115
+ background: #fff;
116
+ border: 1px solid #ddd;
117
+ border-radius: 4px;
118
+ font-size: 0.9rem;
119
+ overflow-x: auto;
120
+ }
121
+
122
+ @media screen and (max-width: 768px) {
123
+ .container {
124
+ padding: 0.5rem;
125
+ }
126
+
127
+ .tool-section {
128
+ padding: 1rem;
129
+ }
130
+
131
+ h1 {
132
+ font-size: 1.3rem;
133
+ }
134
+
135
+ h2 {
136
+ font-size: 1.1rem;
137
+ }
138
+
139
+ button {
140
+ width: 100%;
141
+ margin-bottom: 0.5rem;
142
+ }
143
+
144
+ .file-input-wrapper {
145
+ flex-direction: column;
146
+ align-items: stretch;
147
+ }
148
+
149
+ input[type="file"] {
150
+ width: 100%;
151
+ }
152
+
153
+ textarea {
154
+ min-height: 120px;
155
+ }
156
+ }
157
+
158
+ .loading {
159
+ display: none;
160
+ text-align: center;
161
+ margin: 1rem 0;
162
+ }
163
+
164
+ .loading.active {
165
+ display: block;
166
+ }
167
  </style>
168
  </head>
169
  <body>
170
  <div class="container">
171
  <div class="tool-section">
172
  <h1>ST to Risu Converter</h1>
173
+ <div class="input-group">
174
+ <label for="stInput">Paste ST JSON here:</label>
175
+ <div class="file-input-wrapper">
176
+ <button id="stfileSelectButton">Choose File</button>
177
+ <input type="file" id="stfileInput" accept=".txt,.json" style="display:none;" />
178
+ </div>
179
+ <textarea id="stInput" placeholder="Paste ST JSON content..."></textarea>
180
+ </div>
181
 
182
+ <div class="input-group">
183
+ <label for="risuDefault">Paste Risu Default JSON here:</label>
184
+ <textarea id="risuDefault" placeholder="Paste Risu Default JSON content...">{
185
  "name": "Default",
186
  "apiType": "instructgpt35",
187
  "openAIKey": "",
 
392
  "enableCustomFlags": false,
393
  "regex": [],
394
  "image": ""
395
+ }</textarea>
396
+ </div>
397
 
398
+ <div class="button-group">
399
+ <button id="convertButton">Convert</button>
400
+ </div>
401
 
402
  <div class="output">
403
+ <div class="button-group">
404
+ <button id="copyButton">Copy</button>
405
+ <button id="saveButton">Save as JSON</button>
406
+ </div>
407
+ <pre id="stOutput"></pre>
408
  </div>
409
  </div>
410
 
411
  <div class="tool-section">
412
  <h1>RISU Preset File Tools</h1>
413
+ <div class="input-group">
414
  <h2>Decrypt RISU Preset</h2>
415
+ <div class="file-input-wrapper">
416
+ <input type="file" id="fileInput" accept=".risupreset,.risup"/>
417
+ <button id="recoverButton">Recover Preset</button>
418
+ </div>
419
  </div>
420
 
421
+ <div class="input-group">
422
  <h2>Encrypt to RISU Preset</h2>
423
+ <div class="file-input-wrapper">
424
+ <input type="file" id="jsonInput" accept=".json"/>
425
+ <button id="encryptButton">Create .risup</button>
426
+ </div>
427
  </div>
428
 
429
+ <div class="loading" id="loadingIndicator">Processing...</div>
430
  <pre id="output"></pre>
431
  </div>
432
  </div>
433
 
434
  <script>
435
+ //st文件选择
436
+ document.getElementById("stfileSelectButton").addEventListener("click", function() {
437
+ // 触发文件选择框
438
+ document.getElementById("stfileInput").click();
439
+ });
440
+
441
+ // 处理文件选择和读取内容
442
+ document.getElementById("stfileInput").addEventListener("change", function(event) {
443
+ const file = event.target.files[0]; // 获取选择的第一个文件
444
+
445
+ if (file) {
446
+ const reader = new FileReader();
447
+
448
+ // 文件读取成功后的回调
449
+ reader.onload = function(e) {
450
+ const fileContent = e.target.result;
451
+ document.getElementById("stInput").value = fileContent; // 填充到textarea中
452
+ };
453
+
454
+ // 读取文件内容
455
+ reader.readAsText(file); // 读取文件为文本
456
+ }
457
+ });
458
 
459
  // Copy button functionality
460
+ document.getElementById("copyButton").addEventListener("click", function() {
461
+ const outputText = document.getElementById("stOutput").textContent;
462
+ navigator.clipboard.writeText(outputText).then(function() {
463
+ alert("Copied to clipboard!");
464
+ }).catch(function(err) {
465
+ alert("Failed to copy text: " + err);
466
+ });
467
+ });
468
+ // 接着前面的script标签内容继续添加代码:
469
+
470
+ // Save as JSON button functionality
471
+ document.getElementById("saveButton").addEventListener("click", function() {
472
+ const outputText = document.getElementById("stOutput").textContent;
473
+
474
+ // Ensure the output is valid JSON
475
+ try {
476
+ const jsonObject = JSON.parse(outputText); // Validate JSON format
477
+ const blob = new Blob([JSON.stringify(jsonObject, null, 2)], { type: 'application/json' });
478
+ const link = document.createElement('a');
479
+ link.href = URL.createObjectURL(blob);
480
+ link.download = 'converted_risu.json'; // File name
481
+ link.click();
482
+ } catch (error) {
483
+ alert("The output is not valid JSON.");
484
+ }
485
  });
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
486
 
487
  // ST to Risu Converter Logic
488
  document.getElementById('convertButton').addEventListener('click', function convert() {
 
698
  );
699
  }
700
 
701
+ async function recoverPresetFromFile(file) {
702
+ try {
703
+ showLoading();
704
+ const arrayBuffer = await file.arrayBuffer();
705
+ const uint8Array = new Uint8Array(arrayBuffer);
706
 
707
+ let finalData;
708
 
709
+ if (file.name.endsWith('.risup')) {
710
+ const wasmInstance = await initWasm();
711
+ const decodedData = await decodeRPack(uint8Array, wasmInstance);
712
+ console.log("1. RPack decoded:", decodedData);
 
713
 
714
+ const decompressedData = pako.inflate(decodedData);
715
+ console.log("2. Decompressed:", decompressedData);
716
 
717
+ const firstDecode = msgpackr.decode(decompressedData);
718
+ console.log("3. First msgpack decode:", firstDecode);
719
 
720
+ const decryptedData = await decryptBuffer(firstDecode.preset, 'risupreset');
721
+ console.log("4. Decrypted data:", new Uint8Array(decryptedData));
722
 
723
+ finalData = msgpackr.decode(new Uint8Array(decryptedData));
724
+ console.log("5. Final decoded data:", finalData);
725
 
726
+ } else if (file.name.endsWith('.risupreset')) {
727
+ const decompressedData = pako.inflate(uint8Array);
728
+ console.log("1. Decompressed:", decompressedData);
 
729
 
730
+ const firstDecode = msgpackr.decode(decompressedData);
731
+ console.log("2. First msgpack decode:", firstDecode);
732
 
733
+ const encryptedPreset = firstDecode.preset ?? firstDecode.pres;
734
+ if (!encryptedPreset) {
735
+ throw new Error("Missing `preset` or `pres` field in .risupreset file.");
736
+ }
737
 
738
+ const decryptedData = await decryptBuffer(encryptedPreset, 'risupreset');
739
+ console.log("3. Decrypted data:", new Uint8Array(decryptedData));
740
 
741
+ finalData = msgpackr.decode(new Uint8Array(decryptedData));
742
+ console.log("4. Final decoded data:", finalData);
743
+ } else {
744
+ throw new Error('Unsupported file format');
745
+ }
746
 
747
+ document.getElementById('output').textContent = JSON.stringify(finalData, null, 2);
748
+ } catch (error) {
749
+ console.error('Error recovering preset:', error);
750
+ document.getElementById('output').textContent = `Error: ${error.message}\n\nStack: ${error.stack}`;
751
+ } finally {
752
+ hideLoading();
753
+ }
754
  }
755
 
 
 
 
 
 
 
 
 
 
 
 
 
756
  async function createPresetFile(file) {
757
  try {
758
+ showLoading();
759
  const text = await file.text();
760
  const jsonData = JSON.parse(text);
761
 
 
792
  } catch (error) {
793
  console.error('Error creating preset:', error);
794
  document.getElementById('output').textContent = `Error: ${error.message}\n\nStack: ${error.stack}`;
795
+ } finally {
796
+ hideLoading();
797
  }
798
  }
799
 
800
+ // 添加loading状态控制
801
+ function showLoading() {
802
+ document.getElementById('loadingIndicator').classList.add('active');
803
+ }
804
+
805
+ function hideLoading() {
806
+ document.getElementById('loadingIndicator').classList.remove('active');
807
+ }
808
+
809
+ // Attach event listeners for the file buttons
810
  document.getElementById('recoverButton').addEventListener('click', () => {
811
  const fileInput = document.getElementById('fileInput');
812
  const file = fileInput.files[0];