Refactor PlayAudio

This commit is contained in:
Luc Mcgrady 2025-10-31 08:28:39 +00:00
parent 112f951a13
commit 8da0491ae5
No known key found for this signature in database
GPG key ID: 4F3D7A0B17CC3D9C
5 changed files with 27 additions and 25 deletions

View file

@ -10,6 +10,7 @@ package anki.frontend;
import "anki/scheduler.proto";
import "anki/generic.proto";
import "anki/search.proto";
import "anki/card_rendering.proto";
service FrontendService {
// Returns values from the reviewer
@ -31,8 +32,7 @@ service FrontendService {
// Save colour picker's custom colour palette
rpc SaveCustomColours(generic.Empty) returns (generic.Empty);
// Plays an audio tag at an index in a specific card
// If the index is blank, plays all audio on that side
// Plays the listed audio tags
rpc PlayAudio(PlayAudioRequest) returns (generic.Empty);
}
@ -49,7 +49,5 @@ message SetSchedulingStatesRequest {
}
message PlayAudioRequest {
bool answer_side = 1;
optional uint32 index = 2;
uint64 cid = 3;
repeated card_rendering.AVTag tags = 1;
}

View file

@ -306,13 +306,16 @@ message NextCardDataResponse {
string css = 5;
string body_class = 6;
repeated card_rendering.AVTag question_av_tags = 7;
repeated card_rendering.AVTag answer_av_tags = 8;
// TODO: We can probably make this a little faster by using oneof and
// preventing the partial_front and back being sent to svelte where it isn't
// used. Alternatively we can use a completely different message for both
// Rust -> Python and the Python -> Svelte though this would be more
// complicated to implement.
repeated card_rendering.RenderedTemplateNode partial_front = 7;
repeated card_rendering.RenderedTemplateNode partial_back = 8;
repeated card_rendering.RenderedTemplateNode partial_front = 9;
repeated card_rendering.RenderedTemplateNode partial_back = 10;
}
optional NextCardData next_card = 1;

View file

@ -28,7 +28,7 @@ import aqt
import aqt.main
import aqt.operations
from anki import hooks
from anki.cards import Card, CardId
from anki.cards import Card
from anki.collection import OpChanges, OpChangesOnly, Progress, SearchNode
from anki.decks import UpdateDeckConfigs
from anki.frontend_pb2 import PlayAudioRequest
@ -38,6 +38,7 @@ from anki.template import (
PartiallyRenderedCard,
TemplateRenderContext,
apply_custom_filters,
av_tags_to_native,
)
from anki.utils import dev_mode
from aqt.changenotetype import ChangeNotetypeDialog
@ -670,8 +671,15 @@ def next_card_data() -> bytes:
qside,
)
qside = ctx.col()._backend.extract_av_tags(text=qside, question_side=True).text
aside = ctx.col()._backend.extract_av_tags(text=aside, question_side=False).text
q_avtags = ctx.col()._backend.extract_av_tags(text=qside, question_side=True)
a_avtags = ctx.col()._backend.extract_av_tags(text=aside, question_side=False)
# Assumes the av tags are empty in the original response
data.next_card.question_av_tags.extend(q_avtags.av_tags)
data.next_card.answer_av_tags.extend(a_avtags.av_tags)
qside = q_avtags.text
aside = a_avtags.text
qside = aqt.mw.prepare_card_text_for_display(qside)
aside = aqt.mw.prepare_card_text_for_display(aside)
@ -687,13 +695,7 @@ def next_card_data() -> bytes:
def play_audio():
req = PlayAudioRequest.FromString(request.data)
card = aqt.mw.col.get_card(CardId(req.cid))
# TODO: Pass tags with next_card_data rather than rendering the card here.
tags = card.answer_av_tags() if req.answer_side else card.question_av_tags()
if req.HasField("index"):
play_tags([tags[req.index]])
else:
play_tags(tags)
play_tags(av_tags_to_native(req.tags))
post_handler_list = [

View file

@ -413,11 +413,13 @@ impl crate::services::SchedulerService for Collection {
next_card: Some(NextCardData {
queue: Some(queue.into()),
css: render.css,
css: render.css.clone(),
// Filled by python
front: "".to_string(),
back: "".to_string(),
body_class: "".to_string(),
question_av_tags: vec![],
answer_av_tags: vec![],
partial_front: rendered_nodes_to_proto(render.qnodes),
partial_back: rendered_nodes_to_proto(render.anodes),

View file

@ -42,14 +42,11 @@ export class ReviewerState {
addEventListener("message", this.onMessage.bind(this));
}
playAudio(answerSide: boolean, index?: number) {
playAudio({ answerSide, index, cid: this.currentCard!.card!.id });
}
onMessage(e: MessageEvent<ReviewerRequest>) {
switch (e.data.type) {
case "audio": {
this.playAudio(e.data.answerSide, e.data.index);
const tags = get(this.answerShown) ? this._cardData!.answerAvTags : this._cardData!.questionAvTags;
playAudio({ tags: [tags[e.data.index]] });
break;
}
}
@ -113,7 +110,7 @@ export class ReviewerState {
const question = resp.nextCard?.front || "";
this.updateHtml(question, resp?.nextCard?.css, resp?.nextCard?.bodyClass);
this.playAudio(false)
playAudio({ tags: this._cardData!.questionAvTags });
this.beginAnsweringMs = Date.now();
}
@ -124,7 +121,7 @@ export class ReviewerState {
public showAnswer() {
this.answerShown.set(true);
this.playAudio(true)
playAudio({ tags: this._cardData!.answerAvTags });
this.updateHtml(this._cardData?.back || "");
}