Kkcd106 commited on
Commit
c46e28c
·
verified ·
1 Parent(s): efb88ac

Update index.html

Browse files
Files changed (1) hide show
  1. index.html +61 -25
index.html CHANGED
@@ -41,6 +41,7 @@
41
  color: #fff;
42
  font-size: 14px;
43
  cursor: pointer;
 
44
  }
45
  button {
46
  padding: 12px 20px;
@@ -64,6 +65,7 @@
64
  padding: 10px 16px;
65
  border-radius: 8px;
66
  border: 1px solid #334155;
 
67
  }
68
  .btn-audio {
69
  background: #8b5cf6;
@@ -75,17 +77,20 @@
75
  font-weight: bold;
76
  }
77
  .btn-audio:hover { background: #7c3aed; }
78
- .speed-control {
 
79
  display: flex;
80
  align-items: center;
81
  gap: 8px;
82
  font-size: 13px;
83
  color: #cbd5e1;
84
  margin-left: auto;
 
 
85
  }
86
- .speed-control input[type="range"] {
87
- width: 100px;
88
- cursor: pointer;
89
  }
90
 
91
  .btn-group {
@@ -131,7 +136,7 @@
131
 
132
  <div class="input-group">
133
  <input type="text" id="youtubeUrl" placeholder="วางลิงก์ YouTube ที่นี่ (เช่น https://www.youtube.com/watch?v=...)">
134
- <select id="langSelect">
135
  <option value="th">ภาษาไทย</option>
136
  <option value="en">English</option>
137
  </select>
@@ -145,10 +150,9 @@
145
  <!-- แถบควบคุม Read Aloud ด้านล่างกล่องข้อความ -->
146
  <div id="audioControls" class="audio-controls">
147
  <button id="btnPlayStop" class="btn-audio" onclick="togglePlayStop()">Play</button>
148
- <div class="speed-control">
149
- <label for="speedRange">ความเร็ว:</label>
150
- <input type="range" id="speedRange" min="0.5" max="2" step="0.1" value="1" oninput="updateSpeedLabel(this.value)">
151
- <span id="speedVal">1.0x</span>
152
  </div>
153
  </div>
154
 
@@ -171,6 +175,45 @@
171
  let textChunks = [];
172
  let currentChunkIndex = 0;
173
  let isPlaying = false;
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
174
 
175
  // ฟังก์ชันดึง Video ID จากลิงก์ YouTube
176
  function extractVideoId(url) {
@@ -294,7 +337,8 @@ ${cleanedText}`;
294
  statusDiv.innerText = '✅ ดึงและเรียบเรียงข้อมูลสำเร็จ! เลือกดาวน์โหลดไฟล์หรือฟังเสียงอ่านได้ด้านล่าง';
295
  statusDiv.style.color = '#10b981';
296
 
297
- // แสดงปุ่มดาวน์โหลดและส่วนควบคุมเสียง
 
298
  dlTxtBtn.style.display = 'block';
299
  dlDocxBtn.style.display = 'block';
300
  audioControls.style.display = 'flex';
@@ -305,10 +349,6 @@ ${cleanedText}`;
305
  }
306
 
307
  // --- ระบบควบคุม Read Aloud (Play / Stop / Replay) ---
308
- function updateSpeedLabel(val) {
309
- document.getElementById('speedVal').innerText = parseFloat(val).toFixed(1) + 'x';
310
- }
311
-
312
  function resetAudioState(btnText = 'Replay') {
313
  if (synth) synth.cancel();
314
  isPlaying = false;
@@ -352,16 +392,17 @@ ${cleanedText}`;
352
 
353
  const selectedLang = document.getElementById('langSelect').value;
354
  const targetLang = selectedLang === 'en' ? 'en-US' : 'th-TH';
355
- const speed = parseFloat(document.getElementById('speedRange').value);
356
 
357
  const utterance = new SpeechSynthesisUtterance(textChunks[currentChunkIndex]);
358
  utterance.lang = targetLang;
359
- utterance.rate = speed;
360
 
361
- // เลือก Voice
362
- const voices = synth.getVoices();
363
- const preferredVoice = voices.find(v => v.lang.startsWith(targetLang.slice(0, 2)));
364
- if (preferredVoice) utterance.voice = preferredVoice;
 
 
365
 
366
  utterance.onend = () => {
367
  if (isPlaying) {
@@ -381,11 +422,6 @@ ${cleanedText}`;
381
  synth.speak(utterance);
382
  }
383
 
384
- // โหลดรายการ Voice ของเบราว์เซอร์เตรียมพร้อมไว้
385
- if (typeof speechSynthesis !== 'undefined' && speechSynthesis.onvoiceschanged !== undefined) {
386
- speechSynthesis.onvoiceschanged = () => synth.getVoices();
387
- }
388
-
389
  // ฟังก์ชันสำหรับดาวน์โหลดไฟล์ .TXT
390
  function downloadTXT() {
391
  if (!currentTranscriptText) return;
 
41
  color: #fff;
42
  font-size: 14px;
43
  cursor: pointer;
44
+ max-width: 200px;
45
  }
46
  button {
47
  padding: 12px 20px;
 
65
  padding: 10px 16px;
66
  border-radius: 8px;
67
  border: 1px solid #334155;
68
+ flex-wrap: wrap;
69
  }
70
  .btn-audio {
71
  background: #8b5cf6;
 
77
  font-weight: bold;
78
  }
79
  .btn-audio:hover { background: #7c3aed; }
80
+
81
+ .voice-control {
82
  display: flex;
83
  align-items: center;
84
  gap: 8px;
85
  font-size: 13px;
86
  color: #cbd5e1;
87
  margin-left: auto;
88
+ flex: 1;
89
+ justify-content: flex-end;
90
  }
91
+ .voice-control select {
92
+ max-width: 280px;
93
+ width: 100%;
94
  }
95
 
96
  .btn-group {
 
136
 
137
  <div class="input-group">
138
  <input type="text" id="youtubeUrl" placeholder="วางลิงก์ YouTube ที่นี่ (เช่น https://www.youtube.com/watch?v=...)">
139
+ <select id="langSelect" onchange="populateVoiceList()">
140
  <option value="th">ภาษาไทย</option>
141
  <option value="en">English</option>
142
  </select>
 
150
  <!-- แถบควบคุม Read Aloud ด้านล่างกล่องข้อความ -->
151
  <div id="audioControls" class="audio-controls">
152
  <button id="btnPlayStop" class="btn-audio" onclick="togglePlayStop()">Play</button>
153
+ <div class="voice-control">
154
+ <label for="voiceSelect">เสียง/สำเนียง:</label>
155
+ <select id="voiceSelect"></select>
 
156
  </div>
157
  </div>
158
 
 
175
  let textChunks = [];
176
  let currentChunkIndex = 0;
177
  let isPlaying = false;
178
+ let availableVoices = [];
179
+
180
+ // ดึงรายชื่อเสียงพูดทั้งหมดจากเบราว์เซอร์
181
+ function populateVoiceList() {
182
+ if (!synth) return;
183
+ availableVoices = synth.getVoices();
184
+ const voiceSelect = document.getElementById('voiceSelect');
185
+ const selectedLang = document.getElementById('langSelect').value;
186
+
187
+ voiceSelect.innerHTML = '';
188
+
189
+ // กรองเสียงที่รองรับภาษาไทยหรืออังกฤษตาม Dropdown
190
+ const filteredVoices = availableVoices.filter(v => v.lang.startsWith(selectedLang === 'en' ? 'en' : 'th'));
191
+
192
+ if (filteredVoices.length === 0) {
193
+ // ถ้าไม่พบเสียงที่ตรงภาษา ให้ใช้เสียงทั้งหมดสำรองไว้
194
+ availableVoices.forEach((voice) => {
195
+ const option = document.createElement('option');
196
+ option.textContent = `${voice.name} (${voice.lang})`;
197
+ option.setAttribute('data-name', voice.name);
198
+ voiceSelect.appendChild(option);
199
+ });
200
+ } else {
201
+ filteredVoices.forEach((voice) => {
202
+ const option = document.createElement('option');
203
+ option.textContent = `${voice.name} (${voice.lang})`;
204
+ option.setAttribute('data-name', voice.name);
205
+ voiceSelect.appendChild(option);
206
+ });
207
+ }
208
+ }
209
+
210
+ // โหลด Voice list ล่วงหน้า
211
+ if (typeof speechSynthesis !== 'undefined') {
212
+ populateVoiceList();
213
+ if (speechSynthesis.onvoiceschanged !== undefined) {
214
+ speechSynthesis.onvoiceschanged = populateVoiceList;
215
+ }
216
+ }
217
 
218
  // ฟังก์ชันดึง Video ID จากลิงก์ YouTube
219
  function extractVideoId(url) {
 
337
  statusDiv.innerText = '✅ ดึงและเรียบเรียงข้อมูลสำเร็จ! เลือกดาวน์โหลดไฟล์หรือฟังเสียงอ่านได้ด้านล่าง';
338
  statusDiv.style.color = '#10b981';
339
 
340
+ // อัปเดตรายการเสี���งให้ตรงกับภาษาแล้วแสดงปุ่มดาวน์โหลด/เสียงอ่าน
341
+ populateVoiceList();
342
  dlTxtBtn.style.display = 'block';
343
  dlDocxBtn.style.display = 'block';
344
  audioControls.style.display = 'flex';
 
349
  }
350
 
351
  // --- ระบบควบคุม Read Aloud (Play / Stop / Replay) ---
 
 
 
 
352
  function resetAudioState(btnText = 'Replay') {
353
  if (synth) synth.cancel();
354
  isPlaying = false;
 
392
 
393
  const selectedLang = document.getElementById('langSelect').value;
394
  const targetLang = selectedLang === 'en' ? 'en-US' : 'th-TH';
395
+ const voiceSelect = document.getElementById('voiceSelect');
396
 
397
  const utterance = new SpeechSynthesisUtterance(textChunks[currentChunkIndex]);
398
  utterance.lang = targetLang;
 
399
 
400
+ // เลือกเสียงตามที่ผู้ใช้เลือกใน Dropdown
401
+ const selectedOption = voiceSelect.selectedOptions[0]?.getAttribute('data-name');
402
+ if (selectedOption) {
403
+ const selectedVoice = availableVoices.find(v => v.name === selectedOption);
404
+ if (selectedVoice) utterance.voice = selectedVoice;
405
+ }
406
 
407
  utterance.onend = () => {
408
  if (isPlaying) {
 
422
  synth.speak(utterance);
423
  }
424
 
 
 
 
 
 
425
  // ฟังก์ชันสำหรับดาวน์โหลดไฟล์ .TXT
426
  function downloadTXT() {
427
  if (!currentTranscriptText) return;