I’m trying to upgrade two similar add-ons, but I couldn’t figure out how hooks work in the newer versions of Anki. The add-ons are the followings:
ABC notation to MP3 (music integration) for Anki 2.1.x (add-on number 203713821)
LilyPond Integration (Sheet Music Typesetter) for Anki 2.1.x (add-on number 123418104)
I have a hook that looks like this (mungeFields is my callback function and “mungeFields” is the hook):
It seems that it is never called. What should I do instead?
For the other portions of code to port, I figured out to replace the depreciated API, but PyCharme - whitch is advised to use - wasn’t so helpful. For instance, the autocompletion proposed “stripHTML” instead of the new “strip_html”… so I’ll prefer to use a simple text editor in the future.
This is apparently a really old hook that is no longer called. You can try replacing it with editor_will_munge_html. Hooks are defined and documented in the following two pages: genhooks_gui.py, genhooks.py.
Did you install the latest versions of the anki/aqt PyPI packages? I usually use VS Code and it suggests strip_html if I have recent packages.
I wasn’t sure about editor_will_munge_html hook, but now I feel confident. I’ll try it asap.
Is it still ok to use addHook()?
I don’t know if I’ve installed the latest versions of anki/aqt PyPI packages, but I followed the instructions on the documentation. No worries, I prefer a simple text editor, even if I wouldn’t complain about autocompletion .
Another question: how to deal with internationalisation gettext_()?
I based my work on an add-on for Anki 2.0 and it contained i18n text like _(‘Edit’) and some longer sentences. I don’t know if Anki translate all that content, but I would like to keep this functionality.
What should I replace _() with?
Does Anki now uses i18n python module and i18n.t() instead of _()?
Thanks again and Happy New Year! Best wishes for 2023!
Hello again @abdo
I’ve tried the code below, but it seems that the hook isn’t called at all when the card is displayed. Any idea?
def mungeFields(fields, model, data, col):
'''Parse lilypond tags before they are displayed.'''
print("******* mungeFields **********")
# Ignore duplicated mungeFields call for the answer side.
if 'FrontSide' in fields:
for fld in model['flds']:
field = fld['name']
# check field name
match = lilypondFieldRegexp.search(field)
if match \
and fields[field] != "(%s)" % (field,) \
and fields[field] != "ankiflag":
fields[field] = _imgLink(col, match.group(2), _lyFromHtml(fields[field]))
# autofill field for web:
imgfield = field.replace("lilypond", "lilypondimg", 1)
if imgfield in fields and fields[field] != fields[imgfield]:
fields[imgfield] = fields[field]
col.findReplace((data,), "^.*$", fields[field], regex=True, field=imgfield)
# check field contents
for match in lilypondRegexp.finditer(fields[field]):
fields[field] = fields[field].replace(
match.group(), _imgLink(col, match.group(2), _lyFromHtml(match.group(3)))
editor hooks are called while the editor is shown. If you’re trying to do something during review, that’s not going to work. Some other hooks are mentioned on Changes in 2.1.20 to 29 - Changes that may or may not work for you.
Thanks for your answer.
It seems that the hook isn’t called even when the editor is shown (I tried to add a new card and to browse cards in the deck). I’ll do a further test today, and I’ll come back to report.
I couldn’t find a hook similar to the old mungeFields in the links you and @abdo provided me, except for editor_will_munge_html.
editor_will_munge_html is not the right hook for your case though, because the add-on needs to change the rendered display when reviewing rather than the the edited field contents in the editor. card_did_render may work.
I’ve made the change you suggested according to the new system of hooks. Unfortunately, it seems that the hook card_did_render doesn’t exist (2.1.54 Qt5).
I installed last version of Anki (2.1.55 Qt6) and I obtained the same error.
I found another hook card_will_show, but then I don’t know how to use it. Because the old fashion hook requires these arguments: fields, model, data, col; but the new one requires only one argument: card. I don’t know if it is the right hook to use. I don’t know how to handle its argument (i.e. card) and recover what I need (i.e. fields, model, data, col). Any idea?
I’m struggling with this port: I’m not a programmer, and I did only adapt an existing no-updated add-on for Anki 2.0. I appreciate all your support and help, it means a lot. Thank you!
card_did_render is defined under anki.hooks rather than aqt.gui_hooks (new hooks are defined in two places). anki.hooks.card_did_render should work.
Probably the add-on’s behavior need to be changed a bit for it to be possible to port it to Anki 2.1, since it apparently needs to modify individual fields, the thing which card_did_render doesn’t provide. I can’t help here, because I’m not familiar with the add-on and don’t have the time to look into it at the moment.
Thank you @abdo !
The hook is found now.
I’ll figure out the arguments needed and change the functionality of the callback function. I guess I have to scale down the add-on’s capabilities, if we can’t change the fields, and if we can only change the card rendering.
LilyPond (sheet music typesetting) integration by Andreas Klauer (add-on 1080109152) do exactly what I want. In fact, it’s his prior code for anki 2.0 that I updated for Anki 2.1 and adapted for ABC notation sound generation as well (for 2.0, then for 2.1).
I’m going to adapt my add-on for LilyPond (because it adds a menu for templates to Andreas’ add-on) and I’ll update the add-on for ABC sound generation with an similar code.