Fix overlapping audio when explaining multi-line PDF selections.
Use exclusive playback sessions so popup and pane do not play simultaneously, and stop standalone audio when the lecture pane is closed. Co-authored-by: Cursor <cursoragent@cursor.com>
This commit is contained in:
@@ -136,6 +136,14 @@ export async function playSelectionExplainStandalone(
|
||||
await playSelectionExplainExclusive(result);
|
||||
}
|
||||
|
||||
export function pauseStandalonePlayback(): void {
|
||||
standaloneAudio?.pause();
|
||||
if (standaloneAudio) {
|
||||
standaloneAudio.onended = null;
|
||||
standaloneAudio.removeAttribute("src");
|
||||
}
|
||||
}
|
||||
|
||||
export function stopSelectionExplainStandalone(): void {
|
||||
stopAllLecturePlayback();
|
||||
}
|
||||
|
||||
@@ -50,9 +50,9 @@ import {
|
||||
import {
|
||||
beginSelectionExplainSession,
|
||||
isSelectionExplainSessionActive,
|
||||
playSelectionExplainAudio,
|
||||
playSelectionExplainExclusive,
|
||||
registerLecturePlaybackHandle,
|
||||
pauseStandalonePlayback,
|
||||
stopAllLecturePlayback,
|
||||
} from "../application/playSelectionExplain";
|
||||
import { getString } from "../../../utils/locale";
|
||||
@@ -264,10 +264,23 @@ export class LecturePaneView {
|
||||
|
||||
this.updateActionButton();
|
||||
this.bindEvents();
|
||||
this.unregisterPlayback = registerLecturePlaybackHandle({
|
||||
pause: () => {
|
||||
this.paragraphPlayer?.pause();
|
||||
this.player?.pause();
|
||||
this.audioEl?.pause();
|
||||
},
|
||||
});
|
||||
await this.refreshFromStore();
|
||||
}
|
||||
|
||||
destroy(): void {
|
||||
this.unregisterPlayback?.();
|
||||
this.unregisterPlayback = undefined;
|
||||
this.paragraphPlayer?.pause();
|
||||
this.player?.pause();
|
||||
this.audioEl?.pause();
|
||||
pauseStandalonePlayback();
|
||||
for (const off of this.unsubscribers) off();
|
||||
this.unsubscribers = [];
|
||||
this.player?.destroy();
|
||||
@@ -313,7 +326,7 @@ export class LecturePaneView {
|
||||
}),
|
||||
lectureEvents.on("lecture:selection_explain", (d) => {
|
||||
if (String(getRegularItem(this.item).id) !== d.itemId) return;
|
||||
void this.applySelectionExplainResult(d.result);
|
||||
void this.applySelectionExplainResult(d.result, { play: false });
|
||||
}),
|
||||
);
|
||||
}
|
||||
@@ -828,6 +841,8 @@ export class LecturePaneView {
|
||||
|
||||
this.explainingSelection = true;
|
||||
this.explainSelectionBtn.disabled = true;
|
||||
this.explainSessionId = beginSelectionExplainSession();
|
||||
const sessionId = this.explainSessionId;
|
||||
this.setStatus("summarizing", getString("lecture-selection-explaining"));
|
||||
|
||||
try {
|
||||
@@ -836,7 +851,9 @@ export class LecturePaneView {
|
||||
selectedText,
|
||||
onProgress: (message) => this.setStatus("summarizing", message),
|
||||
});
|
||||
await this.applySelectionExplainResult(result);
|
||||
if (!isSelectionExplainSessionActive(sessionId)) return;
|
||||
await this.applySelectionExplainResult(result, { play: true });
|
||||
if (!isSelectionExplainSessionActive(sessionId)) return;
|
||||
this.setStatus("ready", getString("lecture-selection-done"));
|
||||
} catch (e) {
|
||||
const msg = e instanceof Error ? e.message : String(e);
|
||||
@@ -849,12 +866,17 @@ export class LecturePaneView {
|
||||
|
||||
private async applySelectionExplainResult(
|
||||
result: SelectionExplainResult,
|
||||
options?: { play?: boolean },
|
||||
): Promise<void> {
|
||||
this.lastSelectionResult = result;
|
||||
this.renderSelectionExplain(result);
|
||||
|
||||
await this.syncPdfHighlight(result.original, result.page);
|
||||
|
||||
if (options?.play === false) return;
|
||||
|
||||
stopAllLecturePlayback();
|
||||
|
||||
if (result.fromPrepared && result.matched) {
|
||||
if (!this.paragraphPlayer) {
|
||||
await this.refreshPlayer();
|
||||
@@ -881,12 +903,10 @@ export class LecturePaneView {
|
||||
}
|
||||
|
||||
if (!this.audioEl) return;
|
||||
this.paragraphPlayer?.pause();
|
||||
this.player?.pause();
|
||||
this.playBtn.hidden = true;
|
||||
this.pauseBtn.hidden = false;
|
||||
try {
|
||||
await playSelectionExplainAudio(this.audioEl, result);
|
||||
await playSelectionExplainExclusive(result, this.audioEl);
|
||||
} catch (e) {
|
||||
ztoolkit.log("[ChatPapers:Lecture] selection audio failed", e);
|
||||
} finally {
|
||||
@@ -938,8 +958,8 @@ export class LecturePaneView {
|
||||
this.doc.createTextNode(getString("lecture-selection-replay")),
|
||||
);
|
||||
replayBtn.addEventListener("click", () => {
|
||||
if (!this.audioEl || !this.lastSelectionResult) return;
|
||||
void playSelectionExplainAudio(this.audioEl, this.lastSelectionResult);
|
||||
if (!this.lastSelectionResult) return;
|
||||
void playSelectionExplainExclusive(this.lastSelectionResult, this.audioEl);
|
||||
});
|
||||
this.selectionExplainEl.append(replayBtn);
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user