From 171764e3e072a161520e2b5f0d4883488966b2d3 Mon Sep 17 00:00:00 2001 From: Damien Elmes Date: Tue, 21 Jan 2020 14:47:03 +1000 Subject: [PATCH] add replay buttons to reviewing screen --- qt/aqt/reviewer.py | 22 +++++++++++++++++++--- qt/aqt/sound.py | 28 ++++++++++++++++++++++++++++ qt/aqt_data/web/imgs/play.png | Bin 0 -> 6190 bytes qt/aqt_data/web/reviewer.css | 3 +++ 4 files changed, 50 insertions(+), 3 deletions(-) create mode 100644 qt/aqt_data/web/imgs/play.png diff --git a/qt/aqt/reviewer.py b/qt/aqt/reviewer.py index 7fb990ab0..5ee5ec3ec 100644 --- a/qt/aqt/reviewer.py +++ b/qt/aqt/reviewer.py @@ -14,10 +14,11 @@ import aqt from anki import hooks from anki.cards import Card from anki.lang import _, ngettext +from anki.sound import AVTag from anki.utils import bodyClass, stripHTML from aqt import AnkiQt, gui_hooks from aqt.qt import * -from aqt.sound import av_player, getAudio +from aqt.sound import av_player, getAudio, process_av_tags from aqt.utils import ( askUserDialog, downArrow, @@ -38,6 +39,7 @@ class Reviewer: self.hadCardQueue = False self._answeredIds: List[int] = [] self._recordedAudio = None + self._current_side_audio: Optional[List[AVTag]] = None self.typeCorrect = None # web init happens before this is set self.state: Optional[str] = None self.bottom = aqt.toolbar.BottomBar(mw, mw.bottomWeb) @@ -122,6 +124,14 @@ class Reviewer: txt += c.a() av_player.play_from_text(self.mw.col, txt) + def on_play_button(self, idx: int): + try: + tag = self._current_side_audio[idx] + except IndexError: + return + + av_player.play_tags([tag]) + # Initializing the webview ########################################################################## @@ -181,8 +191,11 @@ The front of this card is empty. Please run Tools>Empty Cards.""" ) else: q = c.q() + + q, self._current_side_audio = process_av_tags(self.mw.col, q) if self.autoplay(c): - av_player.play_from_text(self.mw.col, q) + av_player.play_tags(self._current_side_audio) + # render & update bottom q = self._mungeQA(q) q = gui_hooks.card_will_show(q, c, "reviewQuestion") @@ -223,8 +236,9 @@ The front of this card is empty. Please run Tools>Empty Cards.""" c = self.card a = c.a() # play audio? + a, self._current_side_audio = process_av_tags(self.mw.col, a) if self.autoplay(c): - av_player.play_from_text(self.mw.col, a) + av_player.play_tags(self._current_side_audio) a = self._mungeQA(a) a = gui_hooks.card_will_show(a, c, "reviewAnswer") # render and update bottom @@ -304,6 +318,8 @@ The front of this card is empty. Please run Tools>Empty Cards.""" self.mw.onEditCurrent() elif url == "more": self.showContextMenu() + elif url.startswith("play:"): + self.on_play_button(int(url.split(":")[1])) else: print("unrecognized anki link:", url) diff --git a/qt/aqt/sound.py b/qt/aqt/sound.py index 2b05c1be9..0f974f06f 100644 --- a/qt/aqt/sound.py +++ b/qt/aqt/sound.py @@ -3,6 +3,7 @@ import atexit import os +import re import subprocess import sys import threading @@ -580,6 +581,33 @@ _exports = [i for i in locals().items() if not i[0].startswith("__")] for (k, v) in _exports: sys.modules["anki.sound"].__dict__[k] = v +# Tag handling +########################################################################## + + +def process_av_tags( + col: anki.storage._Collection, text: str +) -> Tuple[str, List[AVTag]]: + "Return card text with play buttons added, and the extracted AV tags." + return ( + av_flags_to_html(col.backend.flag_av_tags(text)), + col.backend.get_av_tags(text), + ) + + +AV_FLAG_RE = re.compile(r"\[anki:play\](\d+)\[/anki:play]") + + +def av_flags_to_html(text: str) -> str: + def repl(match: re.Match) -> str: + return f""" + + +""" + + return AV_FLAG_RE.sub(repl, text) + + # Init defaults ########################################################################## diff --git a/qt/aqt_data/web/imgs/play.png b/qt/aqt_data/web/imgs/play.png new file mode 100644 index 0000000000000000000000000000000000000000..54070ab450ee4dea27d5fdf9cd05a376a0353400 GIT binary patch literal 6190 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 literal 0 HcmV?d00001 diff --git a/qt/aqt_data/web/reviewer.css b/qt/aqt_data/web/reviewer.css index 704d46851..9bb66b375 100644 --- a/qt/aqt_data/web/reviewer.css +++ b/qt/aqt_data/web/reviewer.css @@ -56,3 +56,6 @@ img { .typeMissed { background: #ccc; } + +.playImage { zoom: 50% } +.soundLink { text-decoration: none; }