diff --git a/proto/anki/scheduler.proto b/proto/anki/scheduler.proto index 69430c070..e865af132 100644 --- a/proto/anki/scheduler.proto +++ b/proto/anki/scheduler.proto @@ -344,6 +344,8 @@ message NextCardDataResponse { } optional NextCardData next_card = 1; + // For media pre-loading. The fields of the note after next_card. + string preload = 2; } message CustomStudyRequest { diff --git a/rslib/src/scheduler/service/mod.rs b/rslib/src/scheduler/service/mod.rs index 07a99cf91..e073236e7 100644 --- a/rslib/src/scheduler/service/mod.rs +++ b/rslib/src/scheduler/service/mod.rs @@ -400,7 +400,7 @@ impl crate::services::SchedulerService for Collection { if let Some(answer) = req.answer { self.answer_card(&mut answer.into())?; } - let mut queue = self.get_queued_cards(1, false)?; + let mut queue = self.get_queued_cards(2, false)?; let next_card = queue.cards.first(); if let Some(next_card) = next_card { let cid = next_card.card.id; @@ -483,6 +483,17 @@ impl crate::services::SchedulerService for Collection { stop_on_answer: deck_config.stop_timer_on_answer, }); + let preload = queue + .cards + .get(1) + .map(|after_card| -> Result> { + let after_note = self.get_note(after_card.card.note_id.into())?; + Ok(after_note.fields) + }) + .transpose()? + .unwrap_or(vec![]) + .join(""); + Ok(NextCardDataResponse { next_card: Some(NextCardData { queue: Some(queue.into()), @@ -515,6 +526,7 @@ impl crate::services::SchedulerService for Collection { question_av_tags: vec![], answer_av_tags: vec![], }), + preload, }) } else { Ok(NextCardDataResponse::default()) diff --git a/ts/routes/reviewer-inner/index.ts b/ts/routes/reviewer-inner/index.ts index 79afff161..5ebc68753 100644 --- a/ts/routes/reviewer-inner/index.ts +++ b/ts/routes/reviewer-inner/index.ts @@ -10,6 +10,7 @@ import "mathjax/es5/tex-chtml-full.js"; import { registerPackage } from "@tslib/runtime-require"; import { _runHook, renderError } from "../../reviewer"; import { addBrowserClasses } from "../../reviewer/browser_selector"; +import { preloadResources } from "../../reviewer/preload"; import { imageOcclusionAPI } from "../image-occlusion/review"; import { enableNightMode } from "../reviewer/reviewer"; import type { ReviewerRequest } from "../reviewer/reviewerRequest"; @@ -100,6 +101,10 @@ addEventListener("message", async (e: MessageEvent) => { } _runHook(onShownHook); + + if (e.data.preload) { + preloadResources(e.data.preload); + } break; } default: { diff --git a/ts/routes/reviewer-inner/innerReviewerRequest.ts b/ts/routes/reviewer-inner/innerReviewerRequest.ts index aa9de1867..d7aab68d4 100644 --- a/ts/routes/reviewer-inner/innerReviewerRequest.ts +++ b/ts/routes/reviewer-inner/innerReviewerRequest.ts @@ -5,6 +5,7 @@ interface HtmlMessage { value: string; css?: string; bodyclass?: string; + preload?: string; } interface StorageUpdateMessage { diff --git a/ts/routes/reviewer/reviewer.ts b/ts/routes/reviewer/reviewer.ts index 2547d3a1a..11224a605 100644 --- a/ts/routes/reviewer/reviewer.ts +++ b/ts/routes/reviewer/reviewer.ts @@ -364,8 +364,8 @@ export class ReviewerState { this.iframe?.contentWindow?.postMessage(message, "*"); } - updateHtml(htmlString: string, css?: string, bodyclass?: string) { - this.sendInnerRequest({ type: "html", value: htmlString, css, bodyclass }); + updateHtml(htmlString: string, css?: string, bodyclass?: string, preload?: string) { + this.sendInnerRequest({ type: "html", value: htmlString, css, bodyclass, preload }); } updateAutoAdvanceQuestion() { @@ -430,7 +430,7 @@ export class ReviewerState { this.answerShown.set(false); const question = resp.nextCard?.front || ""; - this.updateHtml(question, resp?.nextCard?.css, resp?.nextCard?.bodyClass); + this.updateHtml(question, resp?.nextCard?.css, resp?.nextCard?.bodyClass, resp?.preload); this.iframe!.style.visibility = "visible"; this.maybeAutoPlayAudio(this._cardData.questionAvTags); this.beginAnsweringMs = Date.now();