|
|
@@ -1981,11 +1981,11 @@
|
|
|
});
|
|
|
|
|
|
// 停止播放
|
|
|
- function stopCurrentPlayback(showTip = true) {
|
|
|
- if (activePlayController) {
|
|
|
- activePlayController.abort();
|
|
|
- activePlayController = null;
|
|
|
- }
|
|
|
+ function stopCurrentPlayback(showTip = true) {
|
|
|
+ if (activePlayController) {
|
|
|
+ activePlayController.abort();
|
|
|
+ activePlayController = null;
|
|
|
+ }
|
|
|
if (activeStreamReader) {
|
|
|
try {
|
|
|
activeStreamReader.cancel();
|
|
|
@@ -1993,16 +1993,22 @@
|
|
|
console.warn('取消流读取失败:', e);
|
|
|
}
|
|
|
activeStreamReader = null;
|
|
|
- }
|
|
|
- if (currentAudio) {
|
|
|
- currentAudio.pause();
|
|
|
- currentAudio.src = '';
|
|
|
- currentAudio = null;
|
|
|
- }
|
|
|
- isPaused = false;
|
|
|
- pausePlayButton.classList.remove('is-active');
|
|
|
- pausePlayButton.title = '暂停播放';
|
|
|
- pausePlayButton.setAttribute('aria-label', '暂停播放');
|
|
|
+ }
|
|
|
+ if (currentAudio) {
|
|
|
+ currentAudio.onended = null;
|
|
|
+ currentAudio.onerror = null;
|
|
|
+ currentAudio.pause();
|
|
|
+ currentAudio.src = '';
|
|
|
+ currentAudio.load();
|
|
|
+ currentAudio = null;
|
|
|
+ }
|
|
|
+ if (audioContext && audioContext.state === 'running') {
|
|
|
+ audioContext.suspend().catch(() => {});
|
|
|
+ }
|
|
|
+ isPaused = false;
|
|
|
+ pausePlayButton.classList.remove('is-active');
|
|
|
+ pausePlayButton.title = '暂停播放';
|
|
|
+ pausePlayButton.setAttribute('aria-label', '暂停播放');
|
|
|
if (showTip) {
|
|
|
const loadingIndicator = document.getElementById('loading-indicator');
|
|
|
loadingIndicator.textContent = '已停止';
|
|
|
@@ -2093,13 +2099,13 @@
|
|
|
updateReadPageButtonText();
|
|
|
|
|
|
// 播放音频队列(添加句子间停顿以模拟段落停顿)
|
|
|
- async function playAudioSequentially(queue, signal) {
|
|
|
- const audioElements = new Map();
|
|
|
- const loadingIndicator = document.getElementById('loading-indicator');
|
|
|
- const PAUSE_BETWEEN_SENTENCES = 10; // ms 停顿时间,句子间短暂停顿,累积形成段落停顿效果
|
|
|
- try {
|
|
|
- while (true) {
|
|
|
- if (signal.aborted) break;
|
|
|
+ async function playAudioSequentially(queue, signal) {
|
|
|
+ const audioElements = new Map();
|
|
|
+ const loadingIndicator = document.getElementById('loading-indicator');
|
|
|
+ const PAUSE_BETWEEN_SENTENCES = 10; // ms 停顿时间,句子间短暂停顿,累积形成段落停顿效果
|
|
|
+ try {
|
|
|
+ while (true) {
|
|
|
+ if (signal.aborted) break;
|
|
|
|
|
|
const chunk = queue.shift();
|
|
|
if (!chunk) {
|
|
|
@@ -2111,60 +2117,68 @@
|
|
|
if (audioContext && audioContext.state !== 'running') {
|
|
|
await audioContext.resume();
|
|
|
}
|
|
|
-
|
|
|
- const audio = new Audio(chunk.audio);
|
|
|
- audioElements.set(chunk.index, audio);
|
|
|
- currentAudio = audio;
|
|
|
-
|
|
|
- try {
|
|
|
- loadingIndicator.textContent = `正在播放第 ${chunk.index + 1} 句`;
|
|
|
- loadingIndicator.style.display = 'block';
|
|
|
- await playAudio(audio);
|
|
|
- // 添加句子间停顿(非暂停状态下)
|
|
|
- if (!signal.aborted && !isPaused) {
|
|
|
- await new Promise(resolve => setTimeout(resolve, PAUSE_BETWEEN_SENTENCES));
|
|
|
- }
|
|
|
- } catch (e) {
|
|
|
+
|
|
|
+ const audio = new Audio(chunk.audio);
|
|
|
+ audioElements.set(chunk.index, audio);
|
|
|
+ currentAudio = audio;
|
|
|
+
|
|
|
+ try {
|
|
|
+ if (signal.aborted) break;
|
|
|
+ loadingIndicator.textContent = `正在播放第 ${chunk.index + 1} 句`;
|
|
|
+ loadingIndicator.style.display = 'block';
|
|
|
+ await playAudio(audio);
|
|
|
+ if (signal.aborted) break;
|
|
|
+ // 添加句子间停顿(非暂停状态下)
|
|
|
+ if (!signal.aborted && !isPaused) {
|
|
|
+ await new Promise(resolve => setTimeout(resolve, PAUSE_BETWEEN_SENTENCES));
|
|
|
+ }
|
|
|
+ } catch (e) {
|
|
|
console.warn(`播放失败: ${e.message}`);
|
|
|
} finally {
|
|
|
audioElements.delete(chunk.index);
|
|
|
if (audio === currentAudio) currentAudio = null;
|
|
|
}
|
|
|
- }
|
|
|
- loadingIndicator.textContent = '播放完成';
|
|
|
- setTimeout(() => {
|
|
|
- loadingIndicator.style.display = 'none';
|
|
|
- }, 1000);
|
|
|
+ }
|
|
|
+ loadingIndicator.textContent = '播放完成';
|
|
|
+ setTimeout(() => {
|
|
|
+ loadingIndicator.style.display = 'none';
|
|
|
+ }, 1000);
|
|
|
} catch (error) {
|
|
|
console.error(error);
|
|
|
loadingIndicator.textContent = `错误: ${error.message}`;
|
|
|
loadingIndicator.style.display = 'block';
|
|
|
} finally {
|
|
|
- audioElements.forEach(audio => {
|
|
|
- audio.pause();
|
|
|
- audio.src = ''; // 清理
|
|
|
- });
|
|
|
- if (currentAudio) {
|
|
|
- currentAudio.pause();
|
|
|
- currentAudio.src = '';
|
|
|
- currentAudio = null;
|
|
|
- }
|
|
|
- }
|
|
|
- }
|
|
|
+ audioElements.forEach(audio => {
|
|
|
+ audio.onended = null;
|
|
|
+ audio.onerror = null;
|
|
|
+ audio.pause();
|
|
|
+ audio.src = ''; // 清理
|
|
|
+ audio.load();
|
|
|
+ });
|
|
|
+ if (currentAudio) {
|
|
|
+ currentAudio.onended = null;
|
|
|
+ currentAudio.onerror = null;
|
|
|
+ currentAudio.pause();
|
|
|
+ currentAudio.src = '';
|
|
|
+ currentAudio.load();
|
|
|
+ currentAudio = null;
|
|
|
+ }
|
|
|
+ }
|
|
|
+ }
|
|
|
|
|
|
// 播放单个音频
|
|
|
- function playAudio(audio) {
|
|
|
- return new Promise((resolve, reject) => {
|
|
|
- audio.play()
|
|
|
- .then(() => {
|
|
|
- audio.onended = () => {
|
|
|
- if (!isPaused) resolve();
|
|
|
- };
|
|
|
- audio.onerror = reject;
|
|
|
- })
|
|
|
- .catch(reject);
|
|
|
- });
|
|
|
- }
|
|
|
+ function playAudio(audio) {
|
|
|
+ return new Promise((resolve, reject) => {
|
|
|
+ audio.play()
|
|
|
+ .then(() => {
|
|
|
+ audio.onended = () => {
|
|
|
+ if (!isPaused) resolve();
|
|
|
+ };
|
|
|
+ audio.onerror = reject;
|
|
|
+ })
|
|
|
+ .catch(reject);
|
|
|
+ });
|
|
|
+ }
|
|
|
|
|
|
// 解析流数据
|
|
|
function parseStreamData(line) {
|