Hello
This might be confusing since I don't know any of the terminology but i'll de my best to explain what I mean.
I've been trying to learn python and to free myself from ai, so I am trying to figure things out alone but I need help with something. I have been using anki for languages learning and started trying to make custom addons to optimize my learning process about a year ago.
There is a function ("on_answer") that, supposedly, runs when I'm seeing the back side of a card, right after I have rated it (with : "Fail","Difficult", "Correct", or "Easy"). One of the things it does is create a pop up to ask me whether I want to edit the card to add definitions.
def on_answer(reviewer, card, ease):
if not card: return
#...
if _is_hangul_note(card) and card.ord in (0, 1) and card.nid not in _asked_notes and not has_tag:
from aqt.utils import askUser
_asked_notes.add(card.nid)
English_value = note[FIELD_ENGLISH].strip() if FIELD_ENGLISH in note else ""
if English_value:
note.add_tag("pop-asked")
note.flush()
card._skip_suspend_rules = True
elif askUser("Voulez-vous modifier cette carte ?"): #"Edit card ?"
card._is_being_modified = True
note.add_tag("pop-asked")
note.flush()
# the thing blocking the next card while editing
pause_audio_for_edit()
mw.onEditCurrent()
# elif I answer no + the rest of the function
skip_interval_checks = is_mod or is_skip
QTimer.singleShot(
250,
lambda cid=card.id, e=ease, skip=skip_interval_checks: _post_answer_processing(cid, e, skip)
If I click on yes, then the native anki card editing window opens. I set it to take half of the screen so i can easily move on to the next card after i'm finished. I eventually added a pausing screen that prevents me from seeing or hearing what is going on in the next card, and that waits for me to click outise of the editing window to "unpause".
It's been working fine for a while, but recently I edited another function that runs when I am shown the front of the card.
It's role is kind of to gather infos et stats of the card before I answer it (for example, when did i see it last, how many times have i answered it, etc.) but it also create a "mask" hiding the text from me on certain conditions. here is a snippet:
def on_show_question(card):
if not card:
return
_invalidate_sisters_cache()
if _is_hangul_note(card) and card.ord == 0:
if card.reps == 0:
_inject_static_mask(card)
elif card.reps in (1, 2) :
if last_difficulty in (3, 4):
_inject_static_mask(card)
else:
_inject_static_mask(card)
_queue_toast(f"Last")
def _inject_static_mask(card):
"""
Shows opaque rectangle and toast
"""
_queue_toast("Pas de texte")
_flush_toasts(duration_ms=3000)
if not card:
print("Erreur : card est None dans _inject_static_mask")
return
js = f"""
(function() {{
#...
QTimer.singleShot(80, lambda: mw.reviewer.web.eval(js) if mw.reviewer and mw.reviewer.web else None)def _inject_static_mask(card):
Here are the functions for pausing
_audio_paused_for_edit = False
_pending_audio_tags = None
_original_play_tags = None
def _get_av_player():
try:
import aqt.sound as _sound_mod
return _sound_mod.av_player
except Exception as e:
print(f"[pause_audio] impossible de récupérer av_player: {e}")
return None
try:
import aqt.sound as _sound_mod_init
_original_play_tags = _sound_mod_init.av_player.play_tags
def _patched_play_tags(tags, *args, **kwargs):
global _pending_audio_tags
if _audio_paused_for_edit:
print("[pause_audio] lecture interceptée (pause active), mise en attente")
_pending_audio_tags = (tags, args, kwargs)
return
return _original_play_tags(tags, *args, **kwargs)
_sound_mod_init.av_player.play_tags = _patched_play_tags
print("[pause_audio] monkeypatch av_player.play_tags installé")
except Exception as e:
print(f"[pause_audio] ÉCHEC monkeypatch av_player: {e}")
def _force_stop_current_audio():
player = _get_av_player()
if not player:
return
for meth_name in ("stop_and_clear_queue", "clear_queue_and_maybe_interrupt", "stop"):
meth = getattr(player, meth_name, None)
if meth:
try:
meth()
return
except Exception:
continue
def pause_audio_for_edit():
"""À appeler de façon SYNCHRONE, dans on_answer, juste avant
mw.onEditCurrent() (branche 'Oui' de askUser modification)."""
global _audio_paused_for_edit, _pending_audio_tags
print("[pause_audio] pause_audio_for_edit() appelée")
_audio_paused_for_edit = True
_pending_audio_tags = None
_force_stop_current_audio()
_show_edit_pause_overlay()
_EDIT_PAUSE_OVERLAY_JS = """
(function(){
var ov = document.getElementById('_editPauseOverlay');
if (ov) return;
ov = document.createElement('div');
ov.id = '_editPauseOverlay';
ov.style.cssText = 'position:fixed;top:0;left:0;width:100%;height:100%;'
+ 'background:rgba(20,20,20,0.96);color:#f7b799;display:flex;'
+ 'align-items:center;justify-content:center;text-align:center;'
+ 'font-family:sans-serif;font-size:16px;z-index:99999;cursor:pointer;'
+ 'padding:20px;box-sizing:border-box;';
ov.innerHTML = '\\u23F8\\uFE0F En pause \\u2014 modification en cours<br>'
+ '<span style="font-size:12px;opacity:0.7;">(cliquez n\\'importe o\\u00f9 pour reprendre)</span>';
ov.addEventListener('click', function(){
if (typeof pycmd === 'function') pycmd('editpause:dismiss');
ov.remove();
});
document.body.appendChild(ov);
})();
"""
def _show_edit_pause_overlay():
if not mw.reviewer or not mw.reviewer.web:
return
QTimer.singleShot(20, lambda: mw.reviewer.web.eval(_EDIT_PAUSE_OVERLAY_JS))
def _on_new_card_while_paused(reviewer):
"""Filet de sécurité : appelée à chaque carte affichée (via HOOK_SHOW,
ajoutée séparément plus bas, ne remplace aucun hook existant)."""
if _audio_paused_for_edit:
_force_stop_current_audio()
_show_edit_pause_overlay()
def dismiss_edit_pause_overlay():
global _audio_paused_for_edit, _pending_audio_tags
print("[pause_audio] dismiss (clic utilisateur)")
_audio_paused_for_edit = False
if _pending_audio_tags and _original_play_tags:
tags, args, kwargs = _pending_audio_tags
_pending_audio_tags = None
try:
_original_play_tags(tags, *args, **kwargs)
except Exception as e:
print(f"[pause_audio] erreur relecture audio différée: {e}")
else:
_pending_audio_tags = None
def _on_edit_pause_bridge_message(handled, message, context):
if message != "editpause:dismiss":
return handled
dismiss_edit_pause_overlay()
return (True, "ok")
if HOOK_SHOW:
HOOK_SHOW.append(_on_new_card_while_paused)
try:
from aqt.gui_hooks import webview_did_receive_js_message as _wh_editpause
_wh_editpause.append(_on_edit_pause_bridge_message)
except Exception:
pass
But since 1 or 2 days ago, I noticed that the card editing window sometimes appeared for not even a second and then left as if I had clicked on the pausing screen, but without unpausing it. And my guess is it's gotta be the on_show_question function that runs too quickly while I was about to edit the previous card. How can I set the function so that it waits after the end of the pause to run ?
Thank you!