Spaces:
Running
Running
Update index.html
Browse files- 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 |
-
|
|
|
|
| 79 |
display: flex;
|
| 80 |
align-items: center;
|
| 81 |
gap: 8px;
|
| 82 |
font-size: 13px;
|
| 83 |
color: #cbd5e1;
|
| 84 |
margin-left: auto;
|
|
|
|
|
|
|
| 85 |
}
|
| 86 |
-
.
|
| 87 |
-
width:
|
| 88 |
-
|
| 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="
|
| 149 |
-
<label for="
|
| 150 |
-
<
|
| 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
|
| 356 |
|
| 357 |
const utterance = new SpeechSynthesisUtterance(textChunks[currentChunkIndex]);
|
| 358 |
utterance.lang = targetLang;
|
| 359 |
-
utterance.rate = speed;
|
| 360 |
|
| 361 |
-
// เลือก
|
| 362 |
-
const
|
| 363 |
-
|
| 364 |
-
|
|
|
|
|
|
|
| 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;
|