# Copyright: Ankitects Pty Ltd and contributors
# License: GNU AGPL, version 3 or later; http://www.gnu.org/licenses/agpl.html

# This file is automatically generated; edit tools/genhooks_gui.py instead.
# Please import from anki.hooks instead of this file.

from __future__ import annotations

from typing import Any, Callable, Sequence, Literal, Type

import anki
import aqt
from anki.cards import Card
from anki.decks import DeckDict, DeckConfigDict
from anki.hooks import runFilter, runHook
from anki.models import NotetypeDict
from anki.collection import OpChangesAfterUndo
from aqt.qt import QDialog, QEvent, QMenu, QModelIndex, QWidget, QMimeData
from aqt.tagedit import TagEdit
from aqt.undo import UndoActionsInfo

class _AddCardsDidAddNoteHook:
    _hooks: list[Callable[["anki.notes.Note"], None]] = []

    
    def append(self, callback: Callable[["anki.notes.Note"], None]) -> None:
        '''(note: anki.notes.Note)'''
        self._hooks.append(callback)

    def remove(self, callback: Callable[["anki.notes.Note"], None]) -> None:
        if callback in self._hooks:
            self._hooks.remove(callback)

    def count(self) -> int:
        return len(self._hooks)

    def __call__(self, note: anki.notes.Note) -> None:
        for hook in self._hooks:
            try:
                hook(note)
            except Exception:
                # if the hook fails, remove it
                self._hooks.remove(hook)
                raise
        # legacy support
        anki.hooks.runHook("AddCards.noteAdded", note)



add_cards_did_add_note = _AddCardsDidAddNoteHook()
class _AddCardsDidChangeDeckHook:
    '''Executed after the user selects a new different deck when
        adding cards.'''
    _hooks: list[Callable[["int"], None]] = []

    
    def append(self, callback: Callable[["int"], None]) -> None:
        '''(new_deck_id: int)'''
        self._hooks.append(callback)

    def remove(self, callback: Callable[["int"], None]) -> None:
        if callback in self._hooks:
            self._hooks.remove(callback)

    def count(self) -> int:
        return len(self._hooks)

    def __call__(self, new_deck_id: int) -> None:
        for hook in self._hooks:
            try:
                hook(new_deck_id)
            except Exception:
                # if the hook fails, remove it
                self._hooks.remove(hook)
                raise



add_cards_did_change_deck = _AddCardsDidChangeDeckHook()
class _AddCardsDidChangeNoteTypeHook:
    '''Deprecated. Use addcards_did_change_note_type instead.
        Executed after the user selects a new note type when adding
        cards.'''
    _hooks: list[Callable[["anki.models.NoteType", "anki.models.NoteType"], None]] = []

    
    def append(self, callback: Callable[["anki.models.NoteType", "anki.models.NoteType"], None]) -> None:
        '''(old: anki.models.NoteType, new: anki.models.NoteType)'''
        self._hooks.append(callback)

    def remove(self, callback: Callable[["anki.models.NoteType", "anki.models.NoteType"], None]) -> None:
        if callback in self._hooks:
            self._hooks.remove(callback)

    def count(self) -> int:
        return len(self._hooks)

    def __call__(self, old: anki.models.NoteType, new: anki.models.NoteType) -> None:
        for hook in self._hooks:
            try:
                hook(old, new)
            except Exception:
                # if the hook fails, remove it
                self._hooks.remove(hook)
                raise



add_cards_did_change_note_type = _AddCardsDidChangeNoteTypeHook()
class _AddCardsDidInitHook:
    _hooks: list[Callable[["aqt.addcards.AddCards"], None]] = []

    
    def append(self, callback: Callable[["aqt.addcards.AddCards"], None]) -> None:
        '''(addcards: aqt.addcards.AddCards)'''
        self._hooks.append(callback)

    def remove(self, callback: Callable[["aqt.addcards.AddCards"], None]) -> None:
        if callback in self._hooks:
            self._hooks.remove(callback)

    def count(self) -> int:
        return len(self._hooks)

    def __call__(self, addcards: aqt.addcards.AddCards) -> None:
        for hook in self._hooks:
            try:
                hook(addcards)
            except Exception:
                # if the hook fails, remove it
                self._hooks.remove(hook)
                raise



add_cards_did_init = _AddCardsDidInitHook()
class _AddCardsMightAddNoteHook:
    '''
            Allows you to provide an optional reason to reject a note. A
            yes / no dialog will open displaying the problem, to which the
            user can decide if they would like to add the note anyway.

            optional_problems is a list containing the optional reasons for which
            you might reject a note. If your add-on wants to add a reason,
            it should append the reason to the list.

            An example add-on that asks the user for confirmation before adding a
            card without tags:

            def might_reject_empty_tag(optional_problems, note):
                if not any(note.tags):
                    optional_problems.append("Add cards without tags?")
        '''
    _hooks: list[Callable[["list[str]", "anki.notes.Note"], None]] = []

    
    def append(self, callback: Callable[["list[str]", "anki.notes.Note"], None]) -> None:
        '''(optional_problems: list[str], note: anki.notes.Note)'''
        self._hooks.append(callback)

    def remove(self, callback: Callable[["list[str]", "anki.notes.Note"], None]) -> None:
        if callback in self._hooks:
            self._hooks.remove(callback)

    def count(self) -> int:
        return len(self._hooks)

    def __call__(self, optional_problems: list[str], note: anki.notes.Note) -> None:
        for hook in self._hooks:
            try:
                hook(optional_problems, note)
            except Exception:
                # if the hook fails, remove it
                self._hooks.remove(hook)
                raise



add_cards_might_add_note = _AddCardsMightAddNoteHook()
class _AddCardsWillAddNoteFilter:
    '''Decides whether the note should be added to the collection or
        not. It is assumed to come from the addCards window.

        reason_to_already_reject is the first reason to reject that
        was found, or None. If your filter wants to reject, it should
        replace return the reason to reject. Otherwise return the
        input.'''
    _hooks: list[Callable[["str | None", "anki.notes.Note"], str | None]] = []

    
    def append(self, callback: Callable[["str | None", "anki.notes.Note"], str | None]) -> None:
        '''(problem: str | None, note: anki.notes.Note)'''
        self._hooks.append(callback)

    def remove(self, callback: Callable[["str | None", "anki.notes.Note"], str | None]) -> None:
        if callback in self._hooks:
            self._hooks.remove(callback)

    def count(self) -> int:
        return len(self._hooks)

    def __call__(self, problem: str | None, note: anki.notes.Note) -> str | None:
        for filter in self._hooks:
            try:
                problem = filter(problem, note)
            except Exception:
                # if the hook fails, remove it
                self._hooks.remove(filter)
                raise
        return problem



add_cards_will_add_note = _AddCardsWillAddNoteFilter()
class _AddCardsWillShowHistoryMenuHook:
    _hooks: list[Callable[["aqt.addcards.AddCards", "QMenu"], None]] = []

    
    def append(self, callback: Callable[["aqt.addcards.AddCards", "QMenu"], None]) -> None:
        '''(addcards: aqt.addcards.AddCards, menu: QMenu)'''
        self._hooks.append(callback)

    def remove(self, callback: Callable[["aqt.addcards.AddCards", "QMenu"], None]) -> None:
        if callback in self._hooks:
            self._hooks.remove(callback)

    def count(self) -> int:
        return len(self._hooks)

    def __call__(self, addcards: aqt.addcards.AddCards, menu: QMenu) -> None:
        for hook in self._hooks:
            try:
                hook(addcards, menu)
            except Exception:
                # if the hook fails, remove it
                self._hooks.remove(hook)
                raise
        # legacy support
        anki.hooks.runHook("AddCards.onHistory", addcards, menu)



add_cards_will_show_history_menu = _AddCardsWillShowHistoryMenuHook()
class _AddcardsDidChangeNoteTypeHook:
    '''Executed after the user selects a new note type when adding
        cards.'''
    _hooks: list[Callable[["aqt.addcards.AddCards", "anki.models.NoteType", "anki.models.NoteType"], None]] = []

    
    def append(self, callback: Callable[["aqt.addcards.AddCards", "anki.models.NoteType", "anki.models.NoteType"], None]) -> None:
        '''(addcards: aqt.addcards.AddCards, old: anki.models.NoteType, new: anki.models.NoteType)'''
        self._hooks.append(callback)

    def remove(self, callback: Callable[["aqt.addcards.AddCards", "anki.models.NoteType", "anki.models.NoteType"], None]) -> None:
        if callback in self._hooks:
            self._hooks.remove(callback)

    def count(self) -> int:
        return len(self._hooks)

    def __call__(self, addcards: aqt.addcards.AddCards, old: anki.models.NoteType, new: anki.models.NoteType) -> None:
        for hook in self._hooks:
            try:
                hook(addcards, old, new)
            except Exception:
                # if the hook fails, remove it
                self._hooks.remove(hook)
                raise
        if add_cards_did_change_note_type.count() > 0:
            print(
                "The hook add_cards_did_change_note_type is deprecated.\n"
                "Use addcards_did_change_note_type instead."
            )
        add_cards_did_change_note_type(old, new)



addcards_did_change_note_type = _AddcardsDidChangeNoteTypeHook()
class _AddcardsWillAddHistoryEntryFilter:
    '''Allows changing the history line in the add-card window.'''
    _hooks: list[Callable[["str", "anki.notes.Note"], str]] = []

    
    def append(self, callback: Callable[["str", "anki.notes.Note"], str]) -> None:
        '''(line: str, note: anki.notes.Note)'''
        self._hooks.append(callback)

    def remove(self, callback: Callable[["str", "anki.notes.Note"], str]) -> None:
        if callback in self._hooks:
            self._hooks.remove(callback)

    def count(self) -> int:
        return len(self._hooks)

    def __call__(self, line: str, note: anki.notes.Note) -> str:
        for filter in self._hooks:
            try:
                line = filter(line, note)
            except Exception:
                # if the hook fails, remove it
                self._hooks.remove(filter)
                raise
        return line



addcards_will_add_history_entry = _AddcardsWillAddHistoryEntryFilter()
class _AddonConfigEditorWillDisplayJsonFilter:
    '''Allows changing the text of the json configuration before actually
        displaying it to the user. For example, you can replace "\\n" by
        some actual new line. Then you can replace the new lines by "\\n"
        while reading the file and let the user uses real new line in
        string instead of its encoding.'''
    _hooks: list[Callable[["str"], str]] = []

    
    def append(self, callback: Callable[["str"], str]) -> None:
        '''(text: str)'''
        self._hooks.append(callback)

    def remove(self, callback: Callable[["str"], str]) -> None:
        if callback in self._hooks:
            self._hooks.remove(callback)

    def count(self) -> int:
        return len(self._hooks)

    def __call__(self, text: str) -> str:
        for filter in self._hooks:
            try:
                text = filter(text)
            except Exception:
                # if the hook fails, remove it
                self._hooks.remove(filter)
                raise
        return text



addon_config_editor_will_display_json = _AddonConfigEditorWillDisplayJsonFilter()
class _AddonConfigEditorWillSaveJsonFilter:
    '''Deprecated. Use addon_config_editor_will_update_json instead.
        Allows changing the text of the json configuration that was
        received from the user before actually reading it. For
        example, you can replace new line in strings by some "\\n".'''
    _hooks: list[Callable[["str"], str]] = []

    
    def append(self, callback: Callable[["str"], str]) -> None:
        '''(text: str)'''
        self._hooks.append(callback)

    def remove(self, callback: Callable[["str"], str]) -> None:
        if callback in self._hooks:
            self._hooks.remove(callback)

    def count(self) -> int:
        return len(self._hooks)

    def __call__(self, text: str) -> str:
        for filter in self._hooks:
            try:
                text = filter(text)
            except Exception:
                # if the hook fails, remove it
                self._hooks.remove(filter)
                raise
        return text



addon_config_editor_will_save_json = _AddonConfigEditorWillSaveJsonFilter()
class _AddonConfigEditorWillUpdateJsonFilter:
    '''Allows changing the text of the json configuration that was
        received from the user before actually reading it. For
        example, you can replace new line in strings by some "\\n".'''
    _hooks: list[Callable[["str", "str"], str]] = []

    
    def append(self, callback: Callable[["str", "str"], str]) -> None:
        '''(text: str, addon: str)'''
        self._hooks.append(callback)

    def remove(self, callback: Callable[["str", "str"], str]) -> None:
        if callback in self._hooks:
            self._hooks.remove(callback)

    def count(self) -> int:
        return len(self._hooks)

    def __call__(self, text: str, addon: str) -> str:
        for filter in self._hooks:
            try:
                text = filter(text, addon)
            except Exception:
                # if the hook fails, remove it
                self._hooks.remove(filter)
                raise
        if addon_config_editor_will_save_json.count() > 0:
            print(
                "The hook addon_config_editor_will_save_json is deprecated.\n"
                "Use addon_config_editor_will_update_json instead."
            )
        text = addon_config_editor_will_save_json(text)
        return text



addon_config_editor_will_update_json = _AddonConfigEditorWillUpdateJsonFilter()
class _AddonManagerDidInstallAddonHook:
    '''Called after installing or updating an addon.

        Can be used to restore DB connections or open files after
        an add-on has been updated.'''
    _hooks: list[Callable[["aqt.addons.AddonManager", "str"], None]] = []

    
    def append(self, callback: Callable[["aqt.addons.AddonManager", "str"], None]) -> None:
        '''(manager: aqt.addons.AddonManager, module: str)'''
        self._hooks.append(callback)

    def remove(self, callback: Callable[["aqt.addons.AddonManager", "str"], None]) -> None:
        if callback in self._hooks:
            self._hooks.remove(callback)

    def count(self) -> int:
        return len(self._hooks)

    def __call__(self, manager: aqt.addons.AddonManager, module: str) -> None:
        for hook in self._hooks:
            try:
                hook(manager, module)
            except Exception:
                # if the hook fails, remove it
                self._hooks.remove(hook)
                raise



addon_manager_did_install_addon = _AddonManagerDidInstallAddonHook()
class _AddonManagerWillInstallAddonHook:
    '''Called before installing or updating an addon.

        Can be used to release DB connections or open files that
        would prevent an update from succeeding.'''
    _hooks: list[Callable[["aqt.addons.AddonManager", "str"], None]] = []

    
    def append(self, callback: Callable[["aqt.addons.AddonManager", "str"], None]) -> None:
        '''(manager: aqt.addons.AddonManager, module: str)'''
        self._hooks.append(callback)

    def remove(self, callback: Callable[["aqt.addons.AddonManager", "str"], None]) -> None:
        if callback in self._hooks:
            self._hooks.remove(callback)

    def count(self) -> int:
        return len(self._hooks)

    def __call__(self, manager: aqt.addons.AddonManager, module: str) -> None:
        for hook in self._hooks:
            try:
                hook(manager, module)
            except Exception:
                # if the hook fails, remove it
                self._hooks.remove(hook)
                raise



addon_manager_will_install_addon = _AddonManagerWillInstallAddonHook()
class _AddonsDialogDidChangeSelectedAddonHook:
    '''Allows doing an action when a single add-on is selected.'''
    _hooks: list[Callable[["aqt.addons.AddonsDialog", "aqt.addons.AddonMeta"], None]] = []

    
    def append(self, callback: Callable[["aqt.addons.AddonsDialog", "aqt.addons.AddonMeta"], None]) -> None:
        '''(dialog: aqt.addons.AddonsDialog, add_on: aqt.addons.AddonMeta)'''
        self._hooks.append(callback)

    def remove(self, callback: Callable[["aqt.addons.AddonsDialog", "aqt.addons.AddonMeta"], None]) -> None:
        if callback in self._hooks:
            self._hooks.remove(callback)

    def count(self) -> int:
        return len(self._hooks)

    def __call__(self, dialog: aqt.addons.AddonsDialog, add_on: aqt.addons.AddonMeta) -> None:
        for hook in self._hooks:
            try:
                hook(dialog, add_on)
            except Exception:
                # if the hook fails, remove it
                self._hooks.remove(hook)
                raise



addons_dialog_did_change_selected_addon = _AddonsDialogDidChangeSelectedAddonHook()
class _AddonsDialogWillDeleteAddonsHook:
    '''Allows doing an action before an add-on is deleted.'''
    _hooks: list[Callable[["aqt.addons.AddonsDialog", "list[str]"], None]] = []

    
    def append(self, callback: Callable[["aqt.addons.AddonsDialog", "list[str]"], None]) -> None:
        '''(dialog: aqt.addons.AddonsDialog, ids: list[str])'''
        self._hooks.append(callback)

    def remove(self, callback: Callable[["aqt.addons.AddonsDialog", "list[str]"], None]) -> None:
        if callback in self._hooks:
            self._hooks.remove(callback)

    def count(self) -> int:
        return len(self._hooks)

    def __call__(self, dialog: aqt.addons.AddonsDialog, ids: list[str]) -> None:
        for hook in self._hooks:
            try:
                hook(dialog, ids)
            except Exception:
                # if the hook fails, remove it
                self._hooks.remove(hook)
                raise



addons_dialog_will_delete_addons = _AddonsDialogWillDeleteAddonsHook()
class _AddonsDialogWillShowHook:
    '''Allows changing the add-on dialog before it is shown. E.g. add
        buttons.'''
    _hooks: list[Callable[["aqt.addons.AddonsDialog"], None]] = []

    
    def append(self, callback: Callable[["aqt.addons.AddonsDialog"], None]) -> None:
        '''(dialog: aqt.addons.AddonsDialog)'''
        self._hooks.append(callback)

    def remove(self, callback: Callable[["aqt.addons.AddonsDialog"], None]) -> None:
        if callback in self._hooks:
            self._hooks.remove(callback)

    def count(self) -> int:
        return len(self._hooks)

    def __call__(self, dialog: aqt.addons.AddonsDialog) -> None:
        for hook in self._hooks:
            try:
                hook(dialog)
            except Exception:
                # if the hook fails, remove it
                self._hooks.remove(hook)
                raise



addons_dialog_will_show = _AddonsDialogWillShowHook()
class _AudioDidPauseOrUnpauseHook:
    '''Called when the audio is paused or unpaused.
        This hook is triggered by the action in Anki's More menu or the related key binding.
        The webview is provided in case you wish to use this hook with web-based audio.'''
    _hooks: list[Callable[["aqt.webview.AnkiWebView"], None]] = []

    
    def append(self, callback: Callable[["aqt.webview.AnkiWebView"], None]) -> None:
        '''(webview: aqt.webview.AnkiWebView)'''
        self._hooks.append(callback)

    def remove(self, callback: Callable[["aqt.webview.AnkiWebView"], None]) -> None:
        if callback in self._hooks:
            self._hooks.remove(callback)

    def count(self) -> int:
        return len(self._hooks)

    def __call__(self, webview: aqt.webview.AnkiWebView) -> None:
        for hook in self._hooks:
            try:
                hook(webview)
            except Exception:
                # if the hook fails, remove it
                self._hooks.remove(hook)
                raise



audio_did_pause_or_unpause = _AudioDidPauseOrUnpauseHook()
class _AudioDidSeekRelativeHook:
    '''Called when the audio is sought forward (positive seek) or backwards (negative seek).
        This hook is triggered by the action in Anki's More menu or the related key binding.
        The webview is provided in case you wish to use this hook with web-based audio.'''
    _hooks: list[Callable[["aqt.webview.AnkiWebView", "int"], None]] = []

    
    def append(self, callback: Callable[["aqt.webview.AnkiWebView", "int"], None]) -> None:
        '''(webview: aqt.webview.AnkiWebView, seek_seconds: int)'''
        self._hooks.append(callback)

    def remove(self, callback: Callable[["aqt.webview.AnkiWebView", "int"], None]) -> None:
        if callback in self._hooks:
            self._hooks.remove(callback)

    def count(self) -> int:
        return len(self._hooks)

    def __call__(self, webview: aqt.webview.AnkiWebView, seek_seconds: int) -> None:
        for hook in self._hooks:
            try:
                hook(webview, seek_seconds)
            except Exception:
                # if the hook fails, remove it
                self._hooks.remove(hook)
                raise



audio_did_seek_relative = _AudioDidSeekRelativeHook()
class _AudioWillReplayHook:
    '''Called when the user uses the 'replay audio' action, but not when they click on a play button.'''
    _hooks: list[Callable[["aqt.webview.AnkiWebView", "Card", "bool"], None]] = []

    
    def append(self, callback: Callable[["aqt.webview.AnkiWebView", "Card", "bool"], None]) -> None:
        '''(webview: aqt.webview.AnkiWebView, card: Card, is_front_side: bool)'''
        self._hooks.append(callback)

    def remove(self, callback: Callable[["aqt.webview.AnkiWebView", "Card", "bool"], None]) -> None:
        if callback in self._hooks:
            self._hooks.remove(callback)

    def count(self) -> int:
        return len(self._hooks)

    def __call__(self, webview: aqt.webview.AnkiWebView, card: Card, is_front_side: bool) -> None:
        for hook in self._hooks:
            try:
                hook(webview, card, is_front_side)
            except Exception:
                # if the hook fails, remove it
                self._hooks.remove(hook)
                raise



audio_will_replay = _AudioWillReplayHook()
class _AvPlayerDidBeginPlayingHook:
    _hooks: list[Callable[["aqt.sound.Player", "anki.sound.AVTag"], None]] = []

    
    def append(self, callback: Callable[["aqt.sound.Player", "anki.sound.AVTag"], None]) -> None:
        '''(player: aqt.sound.Player, tag: anki.sound.AVTag)'''
        self._hooks.append(callback)

    def remove(self, callback: Callable[["aqt.sound.Player", "anki.sound.AVTag"], None]) -> None:
        if callback in self._hooks:
            self._hooks.remove(callback)

    def count(self) -> int:
        return len(self._hooks)

    def __call__(self, player: aqt.sound.Player, tag: anki.sound.AVTag) -> None:
        for hook in self._hooks:
            try:
                hook(player, tag)
            except Exception:
                # if the hook fails, remove it
                self._hooks.remove(hook)
                raise



av_player_did_begin_playing = _AvPlayerDidBeginPlayingHook()
class _AvPlayerDidEndPlayingHook:
    _hooks: list[Callable[["aqt.sound.Player"], None]] = []

    
    def append(self, callback: Callable[["aqt.sound.Player"], None]) -> None:
        '''(player: aqt.sound.Player)'''
        self._hooks.append(callback)

    def remove(self, callback: Callable[["aqt.sound.Player"], None]) -> None:
        if callback in self._hooks:
            self._hooks.remove(callback)

    def count(self) -> int:
        return len(self._hooks)

    def __call__(self, player: aqt.sound.Player) -> None:
        for hook in self._hooks:
            try:
                hook(player)
            except Exception:
                # if the hook fails, remove it
                self._hooks.remove(hook)
                raise



av_player_did_end_playing = _AvPlayerDidEndPlayingHook()
class _AvPlayerWillPlayHook:
    _hooks: list[Callable[["anki.sound.AVTag"], None]] = []

    
    def append(self, callback: Callable[["anki.sound.AVTag"], None]) -> None:
        '''(tag: anki.sound.AVTag)'''
        self._hooks.append(callback)

    def remove(self, callback: Callable[["anki.sound.AVTag"], None]) -> None:
        if callback in self._hooks:
            self._hooks.remove(callback)

    def count(self) -> int:
        return len(self._hooks)

    def __call__(self, tag: anki.sound.AVTag) -> None:
        for hook in self._hooks:
            try:
                hook(tag)
            except Exception:
                # if the hook fails, remove it
                self._hooks.remove(hook)
                raise



av_player_will_play = _AvPlayerWillPlayHook()
class _AvPlayerWillPlayTagsHook:
    '''Called before playing a card side's sounds.

        `tags` can be used to inspect and manipulate the sounds
        that will be played (if any).

        `side` can either be "question" or "answer".

        `context` is the screen where the sounds will be played (e.g., Reviewer, Previewer, and CardLayout).

        This won't be called when the user manually plays sounds
        using `Replay Audio`.

        Note that this hook is called even when the `Automatically play audio`
        option is unchecked; This is so as to allow playing custom
        sounds regardless of that option.'''
    _hooks: list[Callable[["list[anki.sound.AVTag]", "str", "Any"], None]] = []

    
    def append(self, callback: Callable[["list[anki.sound.AVTag]", "str", "Any"], None]) -> None:
        '''(tags: list[anki.sound.AVTag], side: str, context: Any)'''
        self._hooks.append(callback)

    def remove(self, callback: Callable[["list[anki.sound.AVTag]", "str", "Any"], None]) -> None:
        if callback in self._hooks:
            self._hooks.remove(callback)

    def count(self) -> int:
        return len(self._hooks)

    def __call__(self, tags: list[anki.sound.AVTag], side: str, context: Any) -> None:
        for hook in self._hooks:
            try:
                hook(tags, side, context)
            except Exception:
                # if the hook fails, remove it
                self._hooks.remove(hook)
                raise



av_player_will_play_tags = _AvPlayerWillPlayTagsHook()
class _BackendDidBlockHook:
    '''Called after one or more DB tasks finish running in the background.
        Called regardless of the success of individual operations, and only called when
        there are no outstanding ops.
        '''
    _hooks: list[Callable[[], None]] = []

    
    def append(self, callback: Callable[[], None]) -> None:
        '''()'''
        self._hooks.append(callback)

    def remove(self, callback: Callable[[], None]) -> None:
        if callback in self._hooks:
            self._hooks.remove(callback)

    def count(self) -> int:
        return len(self._hooks)

    def __call__(self) -> None:
        for hook in self._hooks:
            try:
                hook()
            except Exception:
                # if the hook fails, remove it
                self._hooks.remove(hook)
                raise



backend_did_block = _BackendDidBlockHook()
class _BackendWillBlockHook:
    '''Called before one or more DB tasks are run in the background.

        Subscribers can use this to set a flag to avoid DB queries until the operation
        completes, as doing so will freeze the UI until the long-running operation
        completes.
        '''
    _hooks: list[Callable[[], None]] = []

    
    def append(self, callback: Callable[[], None]) -> None:
        '''()'''
        self._hooks.append(callback)

    def remove(self, callback: Callable[[], None]) -> None:
        if callback in self._hooks:
            self._hooks.remove(callback)

    def count(self) -> int:
        return len(self._hooks)

    def __call__(self) -> None:
        for hook in self._hooks:
            try:
                hook()
            except Exception:
                # if the hook fails, remove it
                self._hooks.remove(hook)
                raise



backend_will_block = _BackendWillBlockHook()
class _BackupDidCompleteHook:
    _hooks: list[Callable[[], None]] = []

    
    def append(self, callback: Callable[[], None]) -> None:
        '''()'''
        self._hooks.append(callback)

    def remove(self, callback: Callable[[], None]) -> None:
        if callback in self._hooks:
            self._hooks.remove(callback)

    def count(self) -> int:
        return len(self._hooks)

    def __call__(self) -> None:
        for hook in self._hooks:
            try:
                hook()
            except Exception:
                # if the hook fails, remove it
                self._hooks.remove(hook)
                raise



backup_did_complete = _BackupDidCompleteHook()
class _BodyClassesNeedUpdateHook:
    '''Called when a setting involving a webview body class is toggled.'''
    _hooks: list[Callable[[], None]] = []

    
    def append(self, callback: Callable[[], None]) -> None:
        '''()'''
        self._hooks.append(callback)

    def remove(self, callback: Callable[[], None]) -> None:
        if callback in self._hooks:
            self._hooks.remove(callback)

    def count(self) -> int:
        return len(self._hooks)

    def __call__(self) -> None:
        for hook in self._hooks:
            try:
                hook()
            except Exception:
                # if the hook fails, remove it
                self._hooks.remove(hook)
                raise



body_classes_need_update = _BodyClassesNeedUpdateHook()
class _BrowserDidChangeRowHook:
    _hooks: list[Callable[["aqt.browser.Browser"], None]] = []

    
    def append(self, callback: Callable[["aqt.browser.Browser"], None]) -> None:
        '''(browser: aqt.browser.Browser)'''
        self._hooks.append(callback)

    def remove(self, callback: Callable[["aqt.browser.Browser"], None]) -> None:
        if callback in self._hooks:
            self._hooks.remove(callback)

    def count(self) -> int:
        return len(self._hooks)

    def __call__(self, browser: aqt.browser.Browser) -> None:
        for hook in self._hooks:
            try:
                hook(browser)
            except Exception:
                # if the hook fails, remove it
                self._hooks.remove(hook)
                raise
        # legacy support
        anki.hooks.runHook("browser.rowChanged", browser)



browser_did_change_row = _BrowserDidChangeRowHook()
class _BrowserDidFetchColumnsHook:
    '''Allows you to add custom columns to the browser.

        columns is a dictionary of data objects. You can add an entry with a custom
        column to describe how it should be displayed in the browser or modify
        existing entries.

        Every column in the dictionary will be toggleable by the user.
        '''
    _hooks: list[Callable[["dict[str, aqt.browser.Column]"], None]] = []

    
    def append(self, callback: Callable[["dict[str, aqt.browser.Column]"], None]) -> None:
        '''(columns: dict[str, aqt.browser.Column])'''
        self._hooks.append(callback)

    def remove(self, callback: Callable[["dict[str, aqt.browser.Column]"], None]) -> None:
        if callback in self._hooks:
            self._hooks.remove(callback)

    def count(self) -> int:
        return len(self._hooks)

    def __call__(self, columns: dict[str, aqt.browser.Column]) -> None:
        for hook in self._hooks:
            try:
                hook(columns)
            except Exception:
                # if the hook fails, remove it
                self._hooks.remove(hook)
                raise



browser_did_fetch_columns = _BrowserDidFetchColumnsHook()
class _BrowserDidFetchRowHook:
    '''Allows you to add or modify content to a row in the browser.

        You can mutate the row object to change what is displayed. Any columns the
        backend did not recognize will be returned as an empty string, and can be
        replaced with custom content.

        You can retrieve metadata passed from browser_will_search with
        context.addon_metadata (for example to trigger post-processing filtering).

        Columns is a list of string values identifying what each column in the row
        represents.
        '''
    _hooks: list[Callable[["aqt.browser.ItemId", "bool", "aqt.browser.CellRow", "Sequence[str]"], None]] = []

    
    def append(self, callback: Callable[["aqt.browser.ItemId", "bool", "aqt.browser.CellRow", "Sequence[str]"], None]) -> None:
        '''(card_or_note_id: aqt.browser.ItemId, is_note: bool, row: aqt.browser.CellRow, columns: Sequence[str])'''
        self._hooks.append(callback)

    def remove(self, callback: Callable[["aqt.browser.ItemId", "bool", "aqt.browser.CellRow", "Sequence[str]"], None]) -> None:
        if callback in self._hooks:
            self._hooks.remove(callback)

    def count(self) -> int:
        return len(self._hooks)

    def __call__(self, card_or_note_id: aqt.browser.ItemId, is_note: bool, row: aqt.browser.CellRow, columns: Sequence[str]) -> None:
        for hook in self._hooks:
            try:
                hook(card_or_note_id, is_note, row, columns)
            except Exception:
                # if the hook fails, remove it
                self._hooks.remove(hook)
                raise



browser_did_fetch_row = _BrowserDidFetchRowHook()
class _BrowserDidSearchHook:
    '''Allows you to modify the list of returned card ids from a search.'''
    _hooks: list[Callable[["aqt.browser.SearchContext"], None]] = []

    
    def append(self, callback: Callable[["aqt.browser.SearchContext"], None]) -> None:
        '''(context: aqt.browser.SearchContext)'''
        self._hooks.append(callback)

    def remove(self, callback: Callable[["aqt.browser.SearchContext"], None]) -> None:
        if callback in self._hooks:
            self._hooks.remove(callback)

    def count(self) -> int:
        return len(self._hooks)

    def __call__(self, context: aqt.browser.SearchContext) -> None:
        for hook in self._hooks:
            try:
                hook(context)
            except Exception:
                # if the hook fails, remove it
                self._hooks.remove(hook)
                raise



browser_did_search = _BrowserDidSearchHook()
class _BrowserHeaderWillShowContextMenuHook:
    _hooks: list[Callable[["aqt.browser.Browser", "QMenu"], None]] = []

    
    def append(self, callback: Callable[["aqt.browser.Browser", "QMenu"], None]) -> None:
        '''(browser: aqt.browser.Browser, menu: QMenu)'''
        self._hooks.append(callback)

    def remove(self, callback: Callable[["aqt.browser.Browser", "QMenu"], None]) -> None:
        if callback in self._hooks:
            self._hooks.remove(callback)

    def count(self) -> int:
        return len(self._hooks)

    def __call__(self, browser: aqt.browser.Browser, menu: QMenu) -> None:
        for hook in self._hooks:
            try:
                hook(browser, menu)
            except Exception:
                # if the hook fails, remove it
                self._hooks.remove(hook)
                raise



browser_header_will_show_context_menu = _BrowserHeaderWillShowContextMenuHook()
class _BrowserMenusDidInitHook:
    _hooks: list[Callable[["aqt.browser.Browser"], None]] = []

    
    def append(self, callback: Callable[["aqt.browser.Browser"], None]) -> None:
        '''(browser: aqt.browser.Browser)'''
        self._hooks.append(callback)

    def remove(self, callback: Callable[["aqt.browser.Browser"], None]) -> None:
        if callback in self._hooks:
            self._hooks.remove(callback)

    def count(self) -> int:
        return len(self._hooks)

    def __call__(self, browser: aqt.browser.Browser) -> None:
        for hook in self._hooks:
            try:
                hook(browser)
            except Exception:
                # if the hook fails, remove it
                self._hooks.remove(hook)
                raise
        # legacy support
        anki.hooks.runHook("browser.setupMenus", browser)



browser_menus_did_init = _BrowserMenusDidInitHook()
class _BrowserSidebarWillShowContextMenuHook:
    _hooks: list[Callable[["aqt.browser.SidebarTreeView", "QMenu", "aqt.browser.SidebarItem", "QModelIndex"], None]] = []

    
    def append(self, callback: Callable[["aqt.browser.SidebarTreeView", "QMenu", "aqt.browser.SidebarItem", "QModelIndex"], None]) -> None:
        '''(sidebar: aqt.browser.SidebarTreeView, menu: QMenu, item: aqt.browser.SidebarItem, index: QModelIndex)'''
        self._hooks.append(callback)

    def remove(self, callback: Callable[["aqt.browser.SidebarTreeView", "QMenu", "aqt.browser.SidebarItem", "QModelIndex"], None]) -> None:
        if callback in self._hooks:
            self._hooks.remove(callback)

    def count(self) -> int:
        return len(self._hooks)

    def __call__(self, sidebar: aqt.browser.SidebarTreeView, menu: QMenu, item: aqt.browser.SidebarItem, index: QModelIndex) -> None:
        for hook in self._hooks:
            try:
                hook(sidebar, menu, item, index)
            except Exception:
                # if the hook fails, remove it
                self._hooks.remove(hook)
                raise



browser_sidebar_will_show_context_menu = _BrowserSidebarWillShowContextMenuHook()
class _BrowserWillBuildTreeFilter:
    '''Used to add or replace items in the browser sidebar tree

        'tree' is the root SidebarItem that all other items are added to.

        'stage' is an enum describing the different construction stages of
        the sidebar tree at which you can interject your changes.
        The different values can be inspected by looking at
        aqt.browser.SidebarStage.

        If you want Anki to proceed with the construction of the tree stage
        in question after your have performed your changes or additions,
        return the 'handled' boolean unchanged.

        On the other hand, if you want to prevent Anki from adding its own
        items at a particular construction stage (e.g. in case your add-on
        implements its own version of that particular stage), return 'True'.

        If you return 'True' at SidebarStage.ROOT, the sidebar will not be
        populated by any of the other construction stages. For any other stage
        the tree construction will just continue as usual.

        For example, if your code wishes to replace the tag tree, you could do:

            def on_browser_will_build_tree(handled, root, stage, browser):
                if stage != SidebarStage.TAGS:
                    # not at tag tree building stage, pass on
                    return handled

                # your tag tree construction code
                # root.addChild(...)

                # your code handled tag tree construction, no need for Anki
                # or other add-ons to build the tag tree
                return True
        '''
    _hooks: list[Callable[["bool", "aqt.browser.SidebarItem", "aqt.browser.SidebarStage", "aqt.browser.Browser"], bool]] = []

    
    def append(self, callback: Callable[["bool", "aqt.browser.SidebarItem", "aqt.browser.SidebarStage", "aqt.browser.Browser"], bool]) -> None:
        '''(handled: bool, tree: aqt.browser.SidebarItem, stage: aqt.browser.SidebarStage, browser: aqt.browser.Browser)'''
        self._hooks.append(callback)

    def remove(self, callback: Callable[["bool", "aqt.browser.SidebarItem", "aqt.browser.SidebarStage", "aqt.browser.Browser"], bool]) -> None:
        if callback in self._hooks:
            self._hooks.remove(callback)

    def count(self) -> int:
        return len(self._hooks)

    def __call__(self, handled: bool, tree: aqt.browser.SidebarItem, stage: aqt.browser.SidebarStage, browser: aqt.browser.Browser) -> bool:
        for filter in self._hooks:
            try:
                handled = filter(handled, tree, stage, browser)
            except Exception:
                # if the hook fails, remove it
                self._hooks.remove(filter)
                raise
        return handled



browser_will_build_tree = _BrowserWillBuildTreeFilter()
class _BrowserWillSearchHook:
    '''Allows you to modify the search text, or perform your own search.

         You can modify context.search to change the text that is sent to the
         searching backend.

         If you need to pass metadata to the browser_did_search hook, you can
         do it with context.addon_metadata. For example, to trigger filtering
         based on a new custom filter.

         If you set context.ids to a list of ids, the regular search will
         not be performed, and the provided ids will be used instead.

         Your add-on should check if context.ids is not None, and return
         without making changes if it has been set.

         In versions of Anki lower than 2.1.45 the field to check is
         context.card_ids rather than context.ids
         '''
    _hooks: list[Callable[["aqt.browser.SearchContext"], None]] = []

    
    def append(self, callback: Callable[["aqt.browser.SearchContext"], None]) -> None:
        '''(context: aqt.browser.SearchContext)'''
        self._hooks.append(callback)

    def remove(self, callback: Callable[["aqt.browser.SearchContext"], None]) -> None:
        if callback in self._hooks:
            self._hooks.remove(callback)

    def count(self) -> int:
        return len(self._hooks)

    def __call__(self, context: aqt.browser.SearchContext) -> None:
        for hook in self._hooks:
            try:
                hook(context)
            except Exception:
                # if the hook fails, remove it
                self._hooks.remove(hook)
                raise



browser_will_search = _BrowserWillSearchHook()
class _BrowserWillShowHook:
    _hooks: list[Callable[["aqt.browser.Browser"], None]] = []

    
    def append(self, callback: Callable[["aqt.browser.Browser"], None]) -> None:
        '''(browser: aqt.browser.Browser)'''
        self._hooks.append(callback)

    def remove(self, callback: Callable[["aqt.browser.Browser"], None]) -> None:
        if callback in self._hooks:
            self._hooks.remove(callback)

    def count(self) -> int:
        return len(self._hooks)

    def __call__(self, browser: aqt.browser.Browser) -> None:
        for hook in self._hooks:
            try:
                hook(browser)
            except Exception:
                # if the hook fails, remove it
                self._hooks.remove(hook)
                raise



browser_will_show = _BrowserWillShowHook()
class _BrowserWillShowContextMenuHook:
    _hooks: list[Callable[["aqt.browser.Browser", "QMenu"], None]] = []

    
    def append(self, callback: Callable[["aqt.browser.Browser", "QMenu"], None]) -> None:
        '''(browser: aqt.browser.Browser, menu: QMenu)'''
        self._hooks.append(callback)

    def remove(self, callback: Callable[["aqt.browser.Browser", "QMenu"], None]) -> None:
        if callback in self._hooks:
            self._hooks.remove(callback)

    def count(self) -> int:
        return len(self._hooks)

    def __call__(self, browser: aqt.browser.Browser, menu: QMenu) -> None:
        for hook in self._hooks:
            try:
                hook(browser, menu)
            except Exception:
                # if the hook fails, remove it
                self._hooks.remove(hook)
                raise
        # legacy support
        anki.hooks.runHook("browser.onContextMenu", browser, menu)



browser_will_show_context_menu = _BrowserWillShowContextMenuHook()
class _CardLayoutWillShowHook:
    '''Allow to change the display of the card layout. After most values are
         set and before the window is actually shown.'''
    _hooks: list[Callable[["aqt.clayout.CardLayout"], None]] = []

    
    def append(self, callback: Callable[["aqt.clayout.CardLayout"], None]) -> None:
        '''(clayout: aqt.clayout.CardLayout)'''
        self._hooks.append(callback)

    def remove(self, callback: Callable[["aqt.clayout.CardLayout"], None]) -> None:
        if callback in self._hooks:
            self._hooks.remove(callback)

    def count(self) -> int:
        return len(self._hooks)

    def __call__(self, clayout: aqt.clayout.CardLayout) -> None:
        for hook in self._hooks:
            try:
                hook(clayout)
            except Exception:
                # if the hook fails, remove it
                self._hooks.remove(hook)
                raise



card_layout_will_show = _CardLayoutWillShowHook()
class _CardReviewWebviewDidInitHook:
    '''Called when initializing the webview for the review screen, the card layout screen, and the preview screen.'''
    _hooks: list[Callable[["aqt.webview.AnkiWebView", "aqt.webview.AnkiWebViewKind"], None]] = []

    
    def append(self, callback: Callable[["aqt.webview.AnkiWebView", "aqt.webview.AnkiWebViewKind"], None]) -> None:
        '''(webview: aqt.webview.AnkiWebView, kind: aqt.webview.AnkiWebViewKind)'''
        self._hooks.append(callback)

    def remove(self, callback: Callable[["aqt.webview.AnkiWebView", "aqt.webview.AnkiWebViewKind"], None]) -> None:
        if callback in self._hooks:
            self._hooks.remove(callback)

    def count(self) -> int:
        return len(self._hooks)

    def __call__(self, webview: aqt.webview.AnkiWebView, kind: aqt.webview.AnkiWebViewKind) -> None:
        for hook in self._hooks:
            try:
                hook(webview, kind)
            except Exception:
                # if the hook fails, remove it
                self._hooks.remove(hook)
                raise



card_review_webview_did_init = _CardReviewWebviewDidInitHook()
class _CardWillShowFilter:
    '''Can modify card text before review/preview.'''
    _hooks: list[Callable[["str", "Card", "str"], str]] = []

    
    def append(self, callback: Callable[["str", "Card", "str"], str]) -> None:
        '''(text: str, card: Card, kind: str)'''
        self._hooks.append(callback)

    def remove(self, callback: Callable[["str", "Card", "str"], str]) -> None:
        if callback in self._hooks:
            self._hooks.remove(callback)

    def count(self) -> int:
        return len(self._hooks)

    def __call__(self, text: str, card: Card, kind: str) -> str:
        for filter in self._hooks:
            try:
                text = filter(text, card, kind)
            except Exception:
                # if the hook fails, remove it
                self._hooks.remove(filter)
                raise
        # legacy support
        text = anki.hooks.runFilter("prepareQA", text, card, kind)
        return text



card_will_show = _CardWillShowFilter()
class _CollectionDidLoadHook:
    _hooks: list[Callable[["anki.collection.Collection"], None]] = []

    
    def append(self, callback: Callable[["anki.collection.Collection"], None]) -> None:
        '''(col: anki.collection.Collection)'''
        self._hooks.append(callback)

    def remove(self, callback: Callable[["anki.collection.Collection"], None]) -> None:
        if callback in self._hooks:
            self._hooks.remove(callback)

    def count(self) -> int:
        return len(self._hooks)

    def __call__(self, col: anki.collection.Collection) -> None:
        for hook in self._hooks:
            try:
                hook(col)
            except Exception:
                # if the hook fails, remove it
                self._hooks.remove(hook)
                raise
        # legacy support
        anki.hooks.runHook("colLoading", col)



collection_did_load = _CollectionDidLoadHook()
class _CollectionDidTemporarilyCloseHook:
    '''Called after one-way syncs and colpkg imports/exports.'''
    _hooks: list[Callable[["anki.collection.Collection"], None]] = []

    
    def append(self, callback: Callable[["anki.collection.Collection"], None]) -> None:
        '''(col: anki.collection.Collection)'''
        self._hooks.append(callback)

    def remove(self, callback: Callable[["anki.collection.Collection"], None]) -> None:
        if callback in self._hooks:
            self._hooks.remove(callback)

    def count(self) -> int:
        return len(self._hooks)

    def __call__(self, col: anki.collection.Collection) -> None:
        for hook in self._hooks:
            try:
                hook(col)
            except Exception:
                # if the hook fails, remove it
                self._hooks.remove(hook)
                raise



collection_did_temporarily_close = _CollectionDidTemporarilyCloseHook()
class _CollectionWillTemporarilyCloseHook:
    '''Called before one-way syncs and colpkg imports/exports.'''
    _hooks: list[Callable[["anki.collection.Collection"], None]] = []

    
    def append(self, callback: Callable[["anki.collection.Collection"], None]) -> None:
        '''(col: anki.collection.Collection)'''
        self._hooks.append(callback)

    def remove(self, callback: Callable[["anki.collection.Collection"], None]) -> None:
        if callback in self._hooks:
            self._hooks.remove(callback)

    def count(self) -> int:
        return len(self._hooks)

    def __call__(self, col: anki.collection.Collection) -> None:
        for hook in self._hooks:
            try:
                hook(col)
            except Exception:
                # if the hook fails, remove it
                self._hooks.remove(hook)
                raise



collection_will_temporarily_close = _CollectionWillTemporarilyCloseHook()
class _CurrentNoteTypeDidChangeHook:
    _hooks: list[Callable[["NotetypeDict"], None]] = []

    
    def append(self, callback: Callable[["NotetypeDict"], None]) -> None:
        '''(notetype: NotetypeDict)'''
        self._hooks.append(callback)

    def remove(self, callback: Callable[["NotetypeDict"], None]) -> None:
        if callback in self._hooks:
            self._hooks.remove(callback)

    def count(self) -> int:
        return len(self._hooks)

    def __call__(self, notetype: NotetypeDict) -> None:
        for hook in self._hooks:
            try:
                hook(notetype)
            except Exception:
                # if the hook fails, remove it
                self._hooks.remove(hook)
                raise
        # legacy support
        anki.hooks.runHook("currentModelChanged")



current_note_type_did_change = _CurrentNoteTypeDidChangeHook()
class _DayDidChangeHook:
    '''Called when Anki moves to the next day.'''
    _hooks: list[Callable[[], None]] = []

    
    def append(self, callback: Callable[[], None]) -> None:
        '''()'''
        self._hooks.append(callback)

    def remove(self, callback: Callable[[], None]) -> None:
        if callback in self._hooks:
            self._hooks.remove(callback)

    def count(self) -> int:
        return len(self._hooks)

    def __call__(self) -> None:
        for hook in self._hooks:
            try:
                hook()
            except Exception:
                # if the hook fails, remove it
                self._hooks.remove(hook)
                raise



day_did_change = _DayDidChangeHook()
class _DebugConsoleDidEvaluatePythonFilter:
    '''Allows processing the debug result. E.g. logging queries and
        result, saving last query to display it later...'''
    _hooks: list[Callable[["str", "str", "aqt.forms.debug.Ui_Dialog"], str]] = []

    
    def append(self, callback: Callable[["str", "str", "aqt.forms.debug.Ui_Dialog"], str]) -> None:
        '''(output: str, query: str, debug_window: aqt.forms.debug.Ui_Dialog)'''
        self._hooks.append(callback)

    def remove(self, callback: Callable[["str", "str", "aqt.forms.debug.Ui_Dialog"], str]) -> None:
        if callback in self._hooks:
            self._hooks.remove(callback)

    def count(self) -> int:
        return len(self._hooks)

    def __call__(self, output: str, query: str, debug_window: aqt.forms.debug.Ui_Dialog) -> str:
        for filter in self._hooks:
            try:
                output = filter(output, query, debug_window)
            except Exception:
                # if the hook fails, remove it
                self._hooks.remove(filter)
                raise
        return output



debug_console_did_evaluate_python = _DebugConsoleDidEvaluatePythonFilter()
class _DebugConsoleWillShowHook:
    '''Allows editing the debug window. E.g. setting a default code, or
        previous code.'''
    _hooks: list[Callable[["QDialog"], None]] = []

    
    def append(self, callback: Callable[["QDialog"], None]) -> None:
        '''(debug_window: QDialog)'''
        self._hooks.append(callback)

    def remove(self, callback: Callable[["QDialog"], None]) -> None:
        if callback in self._hooks:
            self._hooks.remove(callback)

    def count(self) -> int:
        return len(self._hooks)

    def __call__(self, debug_window: QDialog) -> None:
        for hook in self._hooks:
            try:
                hook(debug_window)
            except Exception:
                # if the hook fails, remove it
                self._hooks.remove(hook)
                raise



debug_console_will_show = _DebugConsoleWillShowHook()
class _DeckBrowserDidRenderHook:
    '''Allow to update the deck browser window. E.g. change its title.'''
    _hooks: list[Callable[["aqt.deckbrowser.DeckBrowser"], None]] = []

    
    def append(self, callback: Callable[["aqt.deckbrowser.DeckBrowser"], None]) -> None:
        '''(deck_browser: aqt.deckbrowser.DeckBrowser)'''
        self._hooks.append(callback)

    def remove(self, callback: Callable[["aqt.deckbrowser.DeckBrowser"], None]) -> None:
        if callback in self._hooks:
            self._hooks.remove(callback)

    def count(self) -> int:
        return len(self._hooks)

    def __call__(self, deck_browser: aqt.deckbrowser.DeckBrowser) -> None:
        for hook in self._hooks:
            try:
                hook(deck_browser)
            except Exception:
                # if the hook fails, remove it
                self._hooks.remove(hook)
                raise



deck_browser_did_render = _DeckBrowserDidRenderHook()
class _DeckBrowserWillRenderContentHook:
    '''Used to modify HTML content sections in the deck browser body

        'content' contains the sections of HTML content the deck browser body
        will be updated with.

        When modifying the content of a particular section, please make sure your
        changes only perform the minimum required edits to make your add-on work.
        You should avoid overwriting or interfering with existing data as much
        as possible, instead opting to append your own changes, e.g.:

            def on_deck_browser_will_render_content(deck_browser, content):
                content.stats += "\n<div>my html</div>"
        '''
    _hooks: list[Callable[["aqt.deckbrowser.DeckBrowser", "aqt.deckbrowser.DeckBrowserContent"], None]] = []

    
    def append(self, callback: Callable[["aqt.deckbrowser.DeckBrowser", "aqt.deckbrowser.DeckBrowserContent"], None]) -> None:
        '''(deck_browser: aqt.deckbrowser.DeckBrowser, content: aqt.deckbrowser.DeckBrowserContent)'''
        self._hooks.append(callback)

    def remove(self, callback: Callable[["aqt.deckbrowser.DeckBrowser", "aqt.deckbrowser.DeckBrowserContent"], None]) -> None:
        if callback in self._hooks:
            self._hooks.remove(callback)

    def count(self) -> int:
        return len(self._hooks)

    def __call__(self, deck_browser: aqt.deckbrowser.DeckBrowser, content: aqt.deckbrowser.DeckBrowserContent) -> None:
        for hook in self._hooks:
            try:
                hook(deck_browser, content)
            except Exception:
                # if the hook fails, remove it
                self._hooks.remove(hook)
                raise



deck_browser_will_render_content = _DeckBrowserWillRenderContentHook()
class _DeckBrowserWillShowOptionsMenuHook:
    _hooks: list[Callable[["QMenu", "int"], None]] = []

    
    def append(self, callback: Callable[["QMenu", "int"], None]) -> None:
        '''(menu: QMenu, deck_id: int)'''
        self._hooks.append(callback)

    def remove(self, callback: Callable[["QMenu", "int"], None]) -> None:
        if callback in self._hooks:
            self._hooks.remove(callback)

    def count(self) -> int:
        return len(self._hooks)

    def __call__(self, menu: QMenu, deck_id: int) -> None:
        for hook in self._hooks:
            try:
                hook(menu, deck_id)
            except Exception:
                # if the hook fails, remove it
                self._hooks.remove(hook)
                raise
        # legacy support
        anki.hooks.runHook("showDeckOptions", menu, deck_id)



deck_browser_will_show_options_menu = _DeckBrowserWillShowOptionsMenuHook()
class _DeckConfDidAddConfigHook:
    '''Allows modification of a newly created config group

        This hook is called after the config group was created, but
        before initializing the widget state.

        `deck_conf` will point to the old config group, `new_conf_id` will
        point to the newly created config group.

        Config groups are created as clones of the current one.
        '''
    _hooks: list[Callable[["aqt.deckconf.DeckConf", "DeckDict", "DeckConfigDict", "str", "int"], None]] = []

    
    def append(self, callback: Callable[["aqt.deckconf.DeckConf", "DeckDict", "DeckConfigDict", "str", "int"], None]) -> None:
        '''(deck_conf: aqt.deckconf.DeckConf, deck: DeckDict, config: DeckConfigDict, new_name: str, new_conf_id: int)'''
        self._hooks.append(callback)

    def remove(self, callback: Callable[["aqt.deckconf.DeckConf", "DeckDict", "DeckConfigDict", "str", "int"], None]) -> None:
        if callback in self._hooks:
            self._hooks.remove(callback)

    def count(self) -> int:
        return len(self._hooks)

    def __call__(self, deck_conf: aqt.deckconf.DeckConf, deck: DeckDict, config: DeckConfigDict, new_name: str, new_conf_id: int) -> None:
        for hook in self._hooks:
            try:
                hook(deck_conf, deck, config, new_name, new_conf_id)
            except Exception:
                # if the hook fails, remove it
                self._hooks.remove(hook)
                raise



deck_conf_did_add_config = _DeckConfDidAddConfigHook()
class _DeckConfDidLoadConfigHook:
    '''Called once widget state has been set from deck config'''
    _hooks: list[Callable[["aqt.deckconf.DeckConf", "DeckDict", "DeckConfigDict"], None]] = []

    
    def append(self, callback: Callable[["aqt.deckconf.DeckConf", "DeckDict", "DeckConfigDict"], None]) -> None:
        '''(deck_conf: aqt.deckconf.DeckConf, deck: DeckDict, config: DeckConfigDict)'''
        self._hooks.append(callback)

    def remove(self, callback: Callable[["aqt.deckconf.DeckConf", "DeckDict", "DeckConfigDict"], None]) -> None:
        if callback in self._hooks:
            self._hooks.remove(callback)

    def count(self) -> int:
        return len(self._hooks)

    def __call__(self, deck_conf: aqt.deckconf.DeckConf, deck: DeckDict, config: DeckConfigDict) -> None:
        for hook in self._hooks:
            try:
                hook(deck_conf, deck, config)
            except Exception:
                # if the hook fails, remove it
                self._hooks.remove(hook)
                raise



deck_conf_did_load_config = _DeckConfDidLoadConfigHook()
class _DeckConfDidSetupUiFormHook:
    '''Allows modifying or adding widgets in the deck options UI form'''
    _hooks: list[Callable[["aqt.deckconf.DeckConf"], None]] = []

    
    def append(self, callback: Callable[["aqt.deckconf.DeckConf"], None]) -> None:
        '''(deck_conf: aqt.deckconf.DeckConf)'''
        self._hooks.append(callback)

    def remove(self, callback: Callable[["aqt.deckconf.DeckConf"], None]) -> None:
        if callback in self._hooks:
            self._hooks.remove(callback)

    def count(self) -> int:
        return len(self._hooks)

    def __call__(self, deck_conf: aqt.deckconf.DeckConf) -> None:
        for hook in self._hooks:
            try:
                hook(deck_conf)
            except Exception:
                # if the hook fails, remove it
                self._hooks.remove(hook)
                raise



deck_conf_did_setup_ui_form = _DeckConfDidSetupUiFormHook()
class _DeckConfWillRemoveConfigHook:
    '''Called before current config group is removed'''
    _hooks: list[Callable[["aqt.deckconf.DeckConf", "DeckDict", "DeckConfigDict"], None]] = []

    
    def append(self, callback: Callable[["aqt.deckconf.DeckConf", "DeckDict", "DeckConfigDict"], None]) -> None:
        '''(deck_conf: aqt.deckconf.DeckConf, deck: DeckDict, config: DeckConfigDict)'''
        self._hooks.append(callback)

    def remove(self, callback: Callable[["aqt.deckconf.DeckConf", "DeckDict", "DeckConfigDict"], None]) -> None:
        if callback in self._hooks:
            self._hooks.remove(callback)

    def count(self) -> int:
        return len(self._hooks)

    def __call__(self, deck_conf: aqt.deckconf.DeckConf, deck: DeckDict, config: DeckConfigDict) -> None:
        for hook in self._hooks:
            try:
                hook(deck_conf, deck, config)
            except Exception:
                # if the hook fails, remove it
                self._hooks.remove(hook)
                raise



deck_conf_will_remove_config = _DeckConfWillRemoveConfigHook()
class _DeckConfWillRenameConfigHook:
    '''Called before config group is renamed'''
    _hooks: list[Callable[["aqt.deckconf.DeckConf", "DeckDict", "DeckConfigDict", "str"], None]] = []

    
    def append(self, callback: Callable[["aqt.deckconf.DeckConf", "DeckDict", "DeckConfigDict", "str"], None]) -> None:
        '''(deck_conf: aqt.deckconf.DeckConf, deck: DeckDict, config: DeckConfigDict, new_name: str)'''
        self._hooks.append(callback)

    def remove(self, callback: Callable[["aqt.deckconf.DeckConf", "DeckDict", "DeckConfigDict", "str"], None]) -> None:
        if callback in self._hooks:
            self._hooks.remove(callback)

    def count(self) -> int:
        return len(self._hooks)

    def __call__(self, deck_conf: aqt.deckconf.DeckConf, deck: DeckDict, config: DeckConfigDict, new_name: str) -> None:
        for hook in self._hooks:
            try:
                hook(deck_conf, deck, config, new_name)
            except Exception:
                # if the hook fails, remove it
                self._hooks.remove(hook)
                raise



deck_conf_will_rename_config = _DeckConfWillRenameConfigHook()
class _DeckConfWillSaveConfigHook:
    '''Called before widget state is saved to config'''
    _hooks: list[Callable[["aqt.deckconf.DeckConf", "DeckDict", "DeckConfigDict"], None]] = []

    
    def append(self, callback: Callable[["aqt.deckconf.DeckConf", "DeckDict", "DeckConfigDict"], None]) -> None:
        '''(deck_conf: aqt.deckconf.DeckConf, deck: DeckDict, config: DeckConfigDict)'''
        self._hooks.append(callback)

    def remove(self, callback: Callable[["aqt.deckconf.DeckConf", "DeckDict", "DeckConfigDict"], None]) -> None:
        if callback in self._hooks:
            self._hooks.remove(callback)

    def count(self) -> int:
        return len(self._hooks)

    def __call__(self, deck_conf: aqt.deckconf.DeckConf, deck: DeckDict, config: DeckConfigDict) -> None:
        for hook in self._hooks:
            try:
                hook(deck_conf, deck, config)
            except Exception:
                # if the hook fails, remove it
                self._hooks.remove(hook)
                raise



deck_conf_will_save_config = _DeckConfWillSaveConfigHook()
class _DeckConfWillShowHook:
    '''Allows modifying the deck options dialog before it is shown'''
    _hooks: list[Callable[["aqt.deckconf.DeckConf"], None]] = []

    
    def append(self, callback: Callable[["aqt.deckconf.DeckConf"], None]) -> None:
        '''(deck_conf: aqt.deckconf.DeckConf)'''
        self._hooks.append(callback)

    def remove(self, callback: Callable[["aqt.deckconf.DeckConf"], None]) -> None:
        if callback in self._hooks:
            self._hooks.remove(callback)

    def count(self) -> int:
        return len(self._hooks)

    def __call__(self, deck_conf: aqt.deckconf.DeckConf) -> None:
        for hook in self._hooks:
            try:
                hook(deck_conf)
            except Exception:
                # if the hook fails, remove it
                self._hooks.remove(hook)
                raise



deck_conf_will_show = _DeckConfWillShowHook()
class _DeckOptionsDidLoadHook:
    '''Can be used to inject extra options into the config screen.

        See the example add-ons at:
        https://github.com/ankitects/anki-addons/tree/main/demos/deckoptions_svelte
        https://github.com/ankitects/anki-addons/tree/main/demos/deckoptions_raw_html
        '''
    _hooks: list[Callable[["aqt.deckoptions.DeckOptionsDialog"], None]] = []

    
    def append(self, callback: Callable[["aqt.deckoptions.DeckOptionsDialog"], None]) -> None:
        '''(deck_options: aqt.deckoptions.DeckOptionsDialog)'''
        self._hooks.append(callback)

    def remove(self, callback: Callable[["aqt.deckoptions.DeckOptionsDialog"], None]) -> None:
        if callback in self._hooks:
            self._hooks.remove(callback)

    def count(self) -> int:
        return len(self._hooks)

    def __call__(self, deck_options: aqt.deckoptions.DeckOptionsDialog) -> None:
        for hook in self._hooks:
            try:
                hook(deck_options)
            except Exception:
                # if the hook fails, remove it
                self._hooks.remove(hook)
                raise



deck_options_did_load = _DeckOptionsDidLoadHook()
class _DefaultSearchFilter:
    '''Change the default search when the card browser is opened with card `c`.'''
    _hooks: list[Callable[["str", "Card"], str]] = []

    
    def append(self, callback: Callable[["str", "Card"], str]) -> None:
        '''(current_search: str, c: Card)'''
        self._hooks.append(callback)

    def remove(self, callback: Callable[["str", "Card"], str]) -> None:
        if callback in self._hooks:
            self._hooks.remove(callback)

    def count(self) -> int:
        return len(self._hooks)

    def __call__(self, current_search: str, c: Card) -> str:
        for filter in self._hooks:
            try:
                current_search = filter(current_search, c)
            except Exception:
                # if the hook fails, remove it
                self._hooks.remove(filter)
                raise
        return current_search



default_search = _DefaultSearchFilter()
class _DialogManagerDidOpenDialogHook:
    '''Executed after aqt.dialogs creates a dialog window'''
    _hooks: list[Callable[["aqt.DialogManager", "str", "QWidget"], None]] = []

    
    def append(self, callback: Callable[["aqt.DialogManager", "str", "QWidget"], None]) -> None:
        '''(dialog_manager: aqt.DialogManager, dialog_name: str, dialog_instance: QWidget)'''
        self._hooks.append(callback)

    def remove(self, callback: Callable[["aqt.DialogManager", "str", "QWidget"], None]) -> None:
        if callback in self._hooks:
            self._hooks.remove(callback)

    def count(self) -> int:
        return len(self._hooks)

    def __call__(self, dialog_manager: aqt.DialogManager, dialog_name: str, dialog_instance: QWidget) -> None:
        for hook in self._hooks:
            try:
                hook(dialog_manager, dialog_name, dialog_instance)
            except Exception:
                # if the hook fails, remove it
                self._hooks.remove(hook)
                raise



dialog_manager_did_open_dialog = _DialogManagerDidOpenDialogHook()
class _EditorDidFireTypingTimerHook:
    _hooks: list[Callable[["anki.notes.Note"], None]] = []

    
    def append(self, callback: Callable[["anki.notes.Note"], None]) -> None:
        '''(note: anki.notes.Note)'''
        self._hooks.append(callback)

    def remove(self, callback: Callable[["anki.notes.Note"], None]) -> None:
        if callback in self._hooks:
            self._hooks.remove(callback)

    def count(self) -> int:
        return len(self._hooks)

    def __call__(self, note: anki.notes.Note) -> None:
        for hook in self._hooks:
            try:
                hook(note)
            except Exception:
                # if the hook fails, remove it
                self._hooks.remove(hook)
                raise
        # legacy support
        anki.hooks.runHook("editTimer", note)



editor_did_fire_typing_timer = _EditorDidFireTypingTimerHook()
class _EditorDidFocusFieldHook:
    _hooks: list[Callable[["anki.notes.Note", "int"], None]] = []

    
    def append(self, callback: Callable[["anki.notes.Note", "int"], None]) -> None:
        '''(note: anki.notes.Note, current_field_idx: int)'''
        self._hooks.append(callback)

    def remove(self, callback: Callable[["anki.notes.Note", "int"], None]) -> None:
        if callback in self._hooks:
            self._hooks.remove(callback)

    def count(self) -> int:
        return len(self._hooks)

    def __call__(self, note: anki.notes.Note, current_field_idx: int) -> None:
        for hook in self._hooks:
            try:
                hook(note, current_field_idx)
            except Exception:
                # if the hook fails, remove it
                self._hooks.remove(hook)
                raise
        # legacy support
        anki.hooks.runHook("editFocusGained", note, current_field_idx)



editor_did_focus_field = _EditorDidFocusFieldHook()
class _EditorDidInitHook:
    _hooks: list[Callable[["aqt.editor.Editor"], None]] = []

    
    def append(self, callback: Callable[["aqt.editor.Editor"], None]) -> None:
        '''(editor: aqt.editor.Editor)'''
        self._hooks.append(callback)

    def remove(self, callback: Callable[["aqt.editor.Editor"], None]) -> None:
        if callback in self._hooks:
            self._hooks.remove(callback)

    def count(self) -> int:
        return len(self._hooks)

    def __call__(self, editor: aqt.editor.Editor) -> None:
        for hook in self._hooks:
            try:
                hook(editor)
            except Exception:
                # if the hook fails, remove it
                self._hooks.remove(hook)
                raise



editor_did_init = _EditorDidInitHook()
class _EditorDidInitButtonsHook:
    _hooks: list[Callable[["list[str]", "aqt.editor.Editor"], None]] = []

    
    def append(self, callback: Callable[["list[str]", "aqt.editor.Editor"], None]) -> None:
        '''(buttons: list[str], editor: aqt.editor.Editor)'''
        self._hooks.append(callback)

    def remove(self, callback: Callable[["list[str]", "aqt.editor.Editor"], None]) -> None:
        if callback in self._hooks:
            self._hooks.remove(callback)

    def count(self) -> int:
        return len(self._hooks)

    def __call__(self, buttons: list[str], editor: aqt.editor.Editor) -> None:
        for hook in self._hooks:
            try:
                hook(buttons, editor)
            except Exception:
                # if the hook fails, remove it
                self._hooks.remove(hook)
                raise



editor_did_init_buttons = _EditorDidInitButtonsHook()
class _EditorDidInitLeftButtonsHook:
    _hooks: list[Callable[["list[str]", "aqt.editor.Editor"], None]] = []

    
    def append(self, callback: Callable[["list[str]", "aqt.editor.Editor"], None]) -> None:
        '''(buttons: list[str], editor: aqt.editor.Editor)'''
        self._hooks.append(callback)

    def remove(self, callback: Callable[["list[str]", "aqt.editor.Editor"], None]) -> None:
        if callback in self._hooks:
            self._hooks.remove(callback)

    def count(self) -> int:
        return len(self._hooks)

    def __call__(self, buttons: list[str], editor: aqt.editor.Editor) -> None:
        for hook in self._hooks:
            try:
                hook(buttons, editor)
            except Exception:
                # if the hook fails, remove it
                self._hooks.remove(hook)
                raise



editor_did_init_left_buttons = _EditorDidInitLeftButtonsHook()
class _EditorDidInitShortcutsHook:
    _hooks: list[Callable[["list[tuple]", "aqt.editor.Editor"], None]] = []

    
    def append(self, callback: Callable[["list[tuple]", "aqt.editor.Editor"], None]) -> None:
        '''(shortcuts: list[tuple], editor: aqt.editor.Editor)'''
        self._hooks.append(callback)

    def remove(self, callback: Callable[["list[tuple]", "aqt.editor.Editor"], None]) -> None:
        if callback in self._hooks:
            self._hooks.remove(callback)

    def count(self) -> int:
        return len(self._hooks)

    def __call__(self, shortcuts: list[tuple], editor: aqt.editor.Editor) -> None:
        for hook in self._hooks:
            try:
                hook(shortcuts, editor)
            except Exception:
                # if the hook fails, remove it
                self._hooks.remove(hook)
                raise
        # legacy support
        anki.hooks.runHook("setupEditorShortcuts", shortcuts, editor)



editor_did_init_shortcuts = _EditorDidInitShortcutsHook()
class _EditorDidLoadNoteHook:
    _hooks: list[Callable[["aqt.editor.Editor"], None]] = []

    
    def append(self, callback: Callable[["aqt.editor.Editor"], None]) -> None:
        '''(editor: aqt.editor.Editor)'''
        self._hooks.append(callback)

    def remove(self, callback: Callable[["aqt.editor.Editor"], None]) -> None:
        if callback in self._hooks:
            self._hooks.remove(callback)

    def count(self) -> int:
        return len(self._hooks)

    def __call__(self, editor: aqt.editor.Editor) -> None:
        for hook in self._hooks:
            try:
                hook(editor)
            except Exception:
                # if the hook fails, remove it
                self._hooks.remove(hook)
                raise
        # legacy support
        anki.hooks.runHook("loadNote", editor)



editor_did_load_note = _EditorDidLoadNoteHook()
class _EditorDidPasteHook:
    '''Called after some data is pasted by python into an editor field.'''
    _hooks: list[Callable[["aqt.editor.Editor", "str", "bool", "bool"], None]] = []

    
    def append(self, callback: Callable[["aqt.editor.Editor", "str", "bool", "bool"], None]) -> None:
        '''(editor: aqt.editor.Editor, html: str, internal: bool, extended: bool)'''
        self._hooks.append(callback)

    def remove(self, callback: Callable[["aqt.editor.Editor", "str", "bool", "bool"], None]) -> None:
        if callback in self._hooks:
            self._hooks.remove(callback)

    def count(self) -> int:
        return len(self._hooks)

    def __call__(self, editor: aqt.editor.Editor, html: str, internal: bool, extended: bool) -> None:
        for hook in self._hooks:
            try:
                hook(editor, html, internal, extended)
            except Exception:
                # if the hook fails, remove it
                self._hooks.remove(hook)
                raise



editor_did_paste = _EditorDidPasteHook()
class _EditorDidUnfocusFieldFilter:
    _hooks: list[Callable[["bool", "anki.notes.Note", "int"], bool]] = []

    
    def append(self, callback: Callable[["bool", "anki.notes.Note", "int"], bool]) -> None:
        '''(changed: bool, note: anki.notes.Note, current_field_idx: int)'''
        self._hooks.append(callback)

    def remove(self, callback: Callable[["bool", "anki.notes.Note", "int"], bool]) -> None:
        if callback in self._hooks:
            self._hooks.remove(callback)

    def count(self) -> int:
        return len(self._hooks)

    def __call__(self, changed: bool, note: anki.notes.Note, current_field_idx: int) -> bool:
        for filter in self._hooks:
            try:
                changed = filter(changed, note, current_field_idx)
            except Exception:
                # if the hook fails, remove it
                self._hooks.remove(filter)
                raise
        # legacy support
        changed = anki.hooks.runFilter("editFocusLost", changed, note, current_field_idx)
        return changed



editor_did_unfocus_field = _EditorDidUnfocusFieldFilter()
class _EditorDidUpdateTagsHook:
    _hooks: list[Callable[["anki.notes.Note"], None]] = []

    
    def append(self, callback: Callable[["anki.notes.Note"], None]) -> None:
        '''(note: anki.notes.Note)'''
        self._hooks.append(callback)

    def remove(self, callback: Callable[["anki.notes.Note"], None]) -> None:
        if callback in self._hooks:
            self._hooks.remove(callback)

    def count(self) -> int:
        return len(self._hooks)

    def __call__(self, note: anki.notes.Note) -> None:
        for hook in self._hooks:
            try:
                hook(note)
            except Exception:
                # if the hook fails, remove it
                self._hooks.remove(hook)
                raise
        # legacy support
        anki.hooks.runHook("tagsUpdated", note)



editor_did_update_tags = _EditorDidUpdateTagsHook()
class _EditorMaskEditorDidLoadImageHook:
    '''Called when the image occlusion mask editor has completed
        loading an image.

        When adding new notes `path_or_nid` will be the path to the image file.
        When editing existing notes `path_or_nid` will be the note id.'''
    _hooks: list[Callable[["aqt.editor.Editor", "str | anki.notes.NoteId"], None]] = []

    
    def append(self, callback: Callable[["aqt.editor.Editor", "str | anki.notes.NoteId"], None]) -> None:
        '''(editor: aqt.editor.Editor, path_or_nid: str | anki.notes.NoteId)'''
        self._hooks.append(callback)

    def remove(self, callback: Callable[["aqt.editor.Editor", "str | anki.notes.NoteId"], None]) -> None:
        if callback in self._hooks:
            self._hooks.remove(callback)

    def count(self) -> int:
        return len(self._hooks)

    def __call__(self, editor: aqt.editor.Editor, path_or_nid: str | anki.notes.NoteId) -> None:
        for hook in self._hooks:
            try:
                hook(editor, path_or_nid)
            except Exception:
                # if the hook fails, remove it
                self._hooks.remove(hook)
                raise



editor_mask_editor_did_load_image = _EditorMaskEditorDidLoadImageHook()
class _EditorStateDidChangeHook:
    '''Called when the input state of the editor changes, e.g. when
        switching to an image occlusion note type.'''
    _hooks: list[Callable[["aqt.editor.Editor", "aqt.editor.EditorState", "aqt.editor.EditorState"], None]] = []

    
    def append(self, callback: Callable[["aqt.editor.Editor", "aqt.editor.EditorState", "aqt.editor.EditorState"], None]) -> None:
        '''(editor: aqt.editor.Editor, new_state: aqt.editor.EditorState, old_state: aqt.editor.EditorState)'''
        self._hooks.append(callback)

    def remove(self, callback: Callable[["aqt.editor.Editor", "aqt.editor.EditorState", "aqt.editor.EditorState"], None]) -> None:
        if callback in self._hooks:
            self._hooks.remove(callback)

    def count(self) -> int:
        return len(self._hooks)

    def __call__(self, editor: aqt.editor.Editor, new_state: aqt.editor.EditorState, old_state: aqt.editor.EditorState) -> None:
        for hook in self._hooks:
            try:
                hook(editor, new_state, old_state)
            except Exception:
                # if the hook fails, remove it
                self._hooks.remove(hook)
                raise



editor_state_did_change = _EditorStateDidChangeHook()
class _EditorWebViewDidInitHook:
    _hooks: list[Callable[["aqt.editor.EditorWebView"], None]] = []

    
    def append(self, callback: Callable[["aqt.editor.EditorWebView"], None]) -> None:
        '''(editor_web_view: aqt.editor.EditorWebView)'''
        self._hooks.append(callback)

    def remove(self, callback: Callable[["aqt.editor.EditorWebView"], None]) -> None:
        if callback in self._hooks:
            self._hooks.remove(callback)

    def count(self) -> int:
        return len(self._hooks)

    def __call__(self, editor_web_view: aqt.editor.EditorWebView) -> None:
        for hook in self._hooks:
            try:
                hook(editor_web_view)
            except Exception:
                # if the hook fails, remove it
                self._hooks.remove(hook)
                raise



editor_web_view_did_init = _EditorWebViewDidInitHook()
class _EditorWillLoadNoteFilter:
    '''Allows changing the javascript commands to load note before
        executing it and do change in the QT editor.'''
    _hooks: list[Callable[["str", "anki.notes.Note", "aqt.editor.Editor"], str]] = []

    
    def append(self, callback: Callable[["str", "anki.notes.Note", "aqt.editor.Editor"], str]) -> None:
        '''(js: str, note: anki.notes.Note, editor: aqt.editor.Editor)'''
        self._hooks.append(callback)

    def remove(self, callback: Callable[["str", "anki.notes.Note", "aqt.editor.Editor"], str]) -> None:
        if callback in self._hooks:
            self._hooks.remove(callback)

    def count(self) -> int:
        return len(self._hooks)

    def __call__(self, js: str, note: anki.notes.Note, editor: aqt.editor.Editor) -> str:
        for filter in self._hooks:
            try:
                js = filter(js, note, editor)
            except Exception:
                # if the hook fails, remove it
                self._hooks.remove(filter)
                raise
        return js



editor_will_load_note = _EditorWillLoadNoteFilter()
class _EditorWillMungeHtmlFilter:
    '''Allows manipulating the text that will be saved by the editor'''
    _hooks: list[Callable[["str", "aqt.editor.Editor"], str]] = []

    
    def append(self, callback: Callable[["str", "aqt.editor.Editor"], str]) -> None:
        '''(txt: str, editor: aqt.editor.Editor)'''
        self._hooks.append(callback)

    def remove(self, callback: Callable[["str", "aqt.editor.Editor"], str]) -> None:
        if callback in self._hooks:
            self._hooks.remove(callback)

    def count(self) -> int:
        return len(self._hooks)

    def __call__(self, txt: str, editor: aqt.editor.Editor) -> str:
        for filter in self._hooks:
            try:
                txt = filter(txt, editor)
            except Exception:
                # if the hook fails, remove it
                self._hooks.remove(filter)
                raise
        return txt



editor_will_munge_html = _EditorWillMungeHtmlFilter()
class _EditorWillProcessMimeFilter:
    '''
        Used to modify MIME data stored in the clipboard after a drop or a paste.
        Called after the user pastes or drag-and-drops something to Anki
        before Anki processes the data.

        The function should return a new or existing QMimeData object.

        "mime" contains the corresponding QMimeData object.
        "internal" indicates whether the drop or paste is performed between Anki fields.
        Most likely you want to skip processing if "internal" was set to True.
        "extended" indicates whether the user requested an extended paste.
        "drop_event" indicates whether the event was triggered by a drag-and-drop
        or by a right-click paste.
        '''
    _hooks: list[Callable[["QMimeData", "aqt.editor.EditorWebView", "bool", "bool", "bool"], QMimeData]] = []

    
    def append(self, callback: Callable[["QMimeData", "aqt.editor.EditorWebView", "bool", "bool", "bool"], QMimeData]) -> None:
        '''(mime: QMimeData, editor_web_view: aqt.editor.EditorWebView, internal: bool, extended: bool, drop_event: bool)'''
        self._hooks.append(callback)

    def remove(self, callback: Callable[["QMimeData", "aqt.editor.EditorWebView", "bool", "bool", "bool"], QMimeData]) -> None:
        if callback in self._hooks:
            self._hooks.remove(callback)

    def count(self) -> int:
        return len(self._hooks)

    def __call__(self, mime: QMimeData, editor_web_view: aqt.editor.EditorWebView, internal: bool, extended: bool, drop_event: bool) -> QMimeData:
        for filter in self._hooks:
            try:
                mime = filter(mime, editor_web_view, internal, extended, drop_event)
            except Exception:
                # if the hook fails, remove it
                self._hooks.remove(filter)
                raise
        return mime



editor_will_process_mime = _EditorWillProcessMimeFilter()
class _EditorWillShowContextMenuHook:
    _hooks: list[Callable[["aqt.editor.EditorWebView", "QMenu"], None]] = []

    
    def append(self, callback: Callable[["aqt.editor.EditorWebView", "QMenu"], None]) -> None:
        '''(editor_webview: aqt.editor.EditorWebView, menu: QMenu)'''
        self._hooks.append(callback)

    def remove(self, callback: Callable[["aqt.editor.EditorWebView", "QMenu"], None]) -> None:
        if callback in self._hooks:
            self._hooks.remove(callback)

    def count(self) -> int:
        return len(self._hooks)

    def __call__(self, editor_webview: aqt.editor.EditorWebView, menu: QMenu) -> None:
        for hook in self._hooks:
            try:
                hook(editor_webview, menu)
            except Exception:
                # if the hook fails, remove it
                self._hooks.remove(hook)
                raise
        # legacy support
        anki.hooks.runHook("EditorWebView.contextMenuEvent", editor_webview, menu)



editor_will_show_context_menu = _EditorWillShowContextMenuHook()
class _EditorWillUseFontForFieldFilter:
    _hooks: list[Callable[["str"], str]] = []

    
    def append(self, callback: Callable[["str"], str]) -> None:
        '''(font: str)'''
        self._hooks.append(callback)

    def remove(self, callback: Callable[["str"], str]) -> None:
        if callback in self._hooks:
            self._hooks.remove(callback)

    def count(self) -> int:
        return len(self._hooks)

    def __call__(self, font: str) -> str:
        for filter in self._hooks:
            try:
                font = filter(font)
            except Exception:
                # if the hook fails, remove it
                self._hooks.remove(filter)
                raise
        # legacy support
        font = anki.hooks.runFilter("mungeEditingFontName", font)
        return font



editor_will_use_font_for_field = _EditorWillUseFontForFieldFilter()
class _EmptyCardsWillShowHook:
    '''Allows changing the list of cards to delete.'''
    _hooks: list[Callable[["aqt.emptycards.EmptyCardsDialog"], None]] = []

    
    def append(self, callback: Callable[["aqt.emptycards.EmptyCardsDialog"], None]) -> None:
        '''(diag: aqt.emptycards.EmptyCardsDialog)'''
        self._hooks.append(callback)

    def remove(self, callback: Callable[["aqt.emptycards.EmptyCardsDialog"], None]) -> None:
        if callback in self._hooks:
            self._hooks.remove(callback)

    def count(self) -> int:
        return len(self._hooks)

    def __call__(self, diag: aqt.emptycards.EmptyCardsDialog) -> None:
        for hook in self._hooks:
            try:
                hook(diag)
            except Exception:
                # if the hook fails, remove it
                self._hooks.remove(hook)
                raise



empty_cards_will_show = _EmptyCardsWillShowHook()
class _ExporterDidExportHook:
    '''Called after collection and deck exports.'''
    _hooks: list[Callable[["aqt.import_export.exporting.ExportOptions", "aqt.import_export.exporting.Exporter"], None]] = []

    
    def append(self, callback: Callable[["aqt.import_export.exporting.ExportOptions", "aqt.import_export.exporting.Exporter"], None]) -> None:
        '''(export_options: aqt.import_export.exporting.ExportOptions, exporter: aqt.import_export.exporting.Exporter)'''
        self._hooks.append(callback)

    def remove(self, callback: Callable[["aqt.import_export.exporting.ExportOptions", "aqt.import_export.exporting.Exporter"], None]) -> None:
        if callback in self._hooks:
            self._hooks.remove(callback)

    def count(self) -> int:
        return len(self._hooks)

    def __call__(self, export_options: aqt.import_export.exporting.ExportOptions, exporter: aqt.import_export.exporting.Exporter) -> None:
        for hook in self._hooks:
            try:
                hook(export_options, exporter)
            except Exception:
                # if the hook fails, remove it
                self._hooks.remove(hook)
                raise



exporter_did_export = _ExporterDidExportHook()
class _ExporterWillExportFilter:
    '''Called before collection and deck exports.

        Allows add-ons to be notified of impending deck exports and potentially
        modify the export options. To perform the export unaltered, please return
        `export_options` as is, e.g.:

            def on_exporter_will_export(export_options: ExportOptions, exporter: Exporter):
                if not isinstance(exporter, ApkgExporter):
                    return export_options
                export_options.limit = ...
                return export_options
        '''
    _hooks: list[Callable[["aqt.import_export.exporting.ExportOptions", "aqt.import_export.exporting.Exporter"], aqt.import_export.exporting.ExportOptions]] = []

    
    def append(self, callback: Callable[["aqt.import_export.exporting.ExportOptions", "aqt.import_export.exporting.Exporter"], aqt.import_export.exporting.ExportOptions]) -> None:
        '''(export_options: aqt.import_export.exporting.ExportOptions, exporter: aqt.import_export.exporting.Exporter)'''
        self._hooks.append(callback)

    def remove(self, callback: Callable[["aqt.import_export.exporting.ExportOptions", "aqt.import_export.exporting.Exporter"], aqt.import_export.exporting.ExportOptions]) -> None:
        if callback in self._hooks:
            self._hooks.remove(callback)

    def count(self) -> int:
        return len(self._hooks)

    def __call__(self, export_options: aqt.import_export.exporting.ExportOptions, exporter: aqt.import_export.exporting.Exporter) -> aqt.import_export.exporting.ExportOptions:
        for filter in self._hooks:
            try:
                export_options = filter(export_options, exporter)
            except Exception:
                # if the hook fails, remove it
                self._hooks.remove(filter)
                raise
        return export_options



exporter_will_export = _ExporterWillExportFilter()
class _ExportersListDidInitializeHook:
    '''Called after the list of exporter classes is created.

        Allows you to register custom exporters and/or replace existing ones by
        modifying the exporter list.
        '''
    _hooks: list[Callable[["list[Type[aqt.import_export.exporting.Exporter]]"], None]] = []

    
    def append(self, callback: Callable[["list[Type[aqt.import_export.exporting.Exporter]]"], None]) -> None:
        '''(exporters: list[Type[aqt.import_export.exporting.Exporter]])'''
        self._hooks.append(callback)

    def remove(self, callback: Callable[["list[Type[aqt.import_export.exporting.Exporter]]"], None]) -> None:
        if callback in self._hooks:
            self._hooks.remove(callback)

    def count(self) -> int:
        return len(self._hooks)

    def __call__(self, exporters: list[Type[aqt.import_export.exporting.Exporter]]) -> None:
        for hook in self._hooks:
            try:
                hook(exporters)
            except Exception:
                # if the hook fails, remove it
                self._hooks.remove(hook)
                raise



exporters_list_did_initialize = _ExportersListDidInitializeHook()
class _FieldsDidAddFieldHook:
    _hooks: list[Callable[["aqt.fields.FieldDialog", "anki.models.FieldDict"], None]] = []

    
    def append(self, callback: Callable[["aqt.fields.FieldDialog", "anki.models.FieldDict"], None]) -> None:
        '''(dialog: aqt.fields.FieldDialog, field: anki.models.FieldDict)'''
        self._hooks.append(callback)

    def remove(self, callback: Callable[["aqt.fields.FieldDialog", "anki.models.FieldDict"], None]) -> None:
        if callback in self._hooks:
            self._hooks.remove(callback)

    def count(self) -> int:
        return len(self._hooks)

    def __call__(self, dialog: aqt.fields.FieldDialog, field: anki.models.FieldDict) -> None:
        for hook in self._hooks:
            try:
                hook(dialog, field)
            except Exception:
                # if the hook fails, remove it
                self._hooks.remove(hook)
                raise



fields_did_add_field = _FieldsDidAddFieldHook()
class _FieldsDidDeleteFieldHook:
    _hooks: list[Callable[["aqt.fields.FieldDialog", "anki.models.FieldDict"], None]] = []

    
    def append(self, callback: Callable[["aqt.fields.FieldDialog", "anki.models.FieldDict"], None]) -> None:
        '''(dialog: aqt.fields.FieldDialog, field: anki.models.FieldDict)'''
        self._hooks.append(callback)

    def remove(self, callback: Callable[["aqt.fields.FieldDialog", "anki.models.FieldDict"], None]) -> None:
        if callback in self._hooks:
            self._hooks.remove(callback)

    def count(self) -> int:
        return len(self._hooks)

    def __call__(self, dialog: aqt.fields.FieldDialog, field: anki.models.FieldDict) -> None:
        for hook in self._hooks:
            try:
                hook(dialog, field)
            except Exception:
                # if the hook fails, remove it
                self._hooks.remove(hook)
                raise



fields_did_delete_field = _FieldsDidDeleteFieldHook()
class _FieldsDidRenameFieldHook:
    _hooks: list[Callable[["aqt.fields.FieldDialog", "anki.models.FieldDict", "str"], None]] = []

    
    def append(self, callback: Callable[["aqt.fields.FieldDialog", "anki.models.FieldDict", "str"], None]) -> None:
        '''(dialog: aqt.fields.FieldDialog, field: anki.models.FieldDict, old_name: str)'''
        self._hooks.append(callback)

    def remove(self, callback: Callable[["aqt.fields.FieldDialog", "anki.models.FieldDict", "str"], None]) -> None:
        if callback in self._hooks:
            self._hooks.remove(callback)

    def count(self) -> int:
        return len(self._hooks)

    def __call__(self, dialog: aqt.fields.FieldDialog, field: anki.models.FieldDict, old_name: str) -> None:
        for hook in self._hooks:
            try:
                hook(dialog, field, old_name)
            except Exception:
                # if the hook fails, remove it
                self._hooks.remove(hook)
                raise



fields_did_rename_field = _FieldsDidRenameFieldHook()
class _FilteredDeckDialogDidAddOrUpdateDeckHook:
    '''Allows performing changes after a filtered deck has been added or updated'''
    _hooks: list[Callable[["aqt.filtered_deck.FilteredDeckConfigDialog", "anki.scheduler.FilteredDeckForUpdate", "int"], None]] = []

    
    def append(self, callback: Callable[["aqt.filtered_deck.FilteredDeckConfigDialog", "anki.scheduler.FilteredDeckForUpdate", "int"], None]) -> None:
        '''(filtered_deck_dialog: aqt.filtered_deck.FilteredDeckConfigDialog, filtered_deck: anki.scheduler.FilteredDeckForUpdate, deck_id: int)'''
        self._hooks.append(callback)

    def remove(self, callback: Callable[["aqt.filtered_deck.FilteredDeckConfigDialog", "anki.scheduler.FilteredDeckForUpdate", "int"], None]) -> None:
        if callback in self._hooks:
            self._hooks.remove(callback)

    def count(self) -> int:
        return len(self._hooks)

    def __call__(self, filtered_deck_dialog: aqt.filtered_deck.FilteredDeckConfigDialog, filtered_deck: anki.scheduler.FilteredDeckForUpdate, deck_id: int) -> None:
        for hook in self._hooks:
            try:
                hook(filtered_deck_dialog, filtered_deck, deck_id)
            except Exception:
                # if the hook fails, remove it
                self._hooks.remove(hook)
                raise



filtered_deck_dialog_did_add_or_update_deck = _FilteredDeckDialogDidAddOrUpdateDeckHook()
class _FilteredDeckDialogDidLoadDeckHook:
    '''Allows updating widget state once the filtered deck config is loaded'''
    _hooks: list[Callable[["aqt.filtered_deck.FilteredDeckConfigDialog", "anki.scheduler.FilteredDeckForUpdate"], None]] = []

    
    def append(self, callback: Callable[["aqt.filtered_deck.FilteredDeckConfigDialog", "anki.scheduler.FilteredDeckForUpdate"], None]) -> None:
        '''(filtered_deck_dialog: aqt.filtered_deck.FilteredDeckConfigDialog, filtered_deck: anki.scheduler.FilteredDeckForUpdate)'''
        self._hooks.append(callback)

    def remove(self, callback: Callable[["aqt.filtered_deck.FilteredDeckConfigDialog", "anki.scheduler.FilteredDeckForUpdate"], None]) -> None:
        if callback in self._hooks:
            self._hooks.remove(callback)

    def count(self) -> int:
        return len(self._hooks)

    def __call__(self, filtered_deck_dialog: aqt.filtered_deck.FilteredDeckConfigDialog, filtered_deck: anki.scheduler.FilteredDeckForUpdate) -> None:
        for hook in self._hooks:
            try:
                hook(filtered_deck_dialog, filtered_deck)
            except Exception:
                # if the hook fails, remove it
                self._hooks.remove(hook)
                raise



filtered_deck_dialog_did_load_deck = _FilteredDeckDialogDidLoadDeckHook()
class _FilteredDeckDialogWillAddOrUpdateDeckHook:
    '''Allows modifying the filtered deck config object before it is written'''
    _hooks: list[Callable[["aqt.filtered_deck.FilteredDeckConfigDialog", "anki.scheduler.FilteredDeckForUpdate"], None]] = []

    
    def append(self, callback: Callable[["aqt.filtered_deck.FilteredDeckConfigDialog", "anki.scheduler.FilteredDeckForUpdate"], None]) -> None:
        '''(filtered_deck_dialog: aqt.filtered_deck.FilteredDeckConfigDialog, filtered_deck: anki.scheduler.FilteredDeckForUpdate)'''
        self._hooks.append(callback)

    def remove(self, callback: Callable[["aqt.filtered_deck.FilteredDeckConfigDialog", "anki.scheduler.FilteredDeckForUpdate"], None]) -> None:
        if callback in self._hooks:
            self._hooks.remove(callback)

    def count(self) -> int:
        return len(self._hooks)

    def __call__(self, filtered_deck_dialog: aqt.filtered_deck.FilteredDeckConfigDialog, filtered_deck: anki.scheduler.FilteredDeckForUpdate) -> None:
        for hook in self._hooks:
            try:
                hook(filtered_deck_dialog, filtered_deck)
            except Exception:
                # if the hook fails, remove it
                self._hooks.remove(hook)
                raise



filtered_deck_dialog_will_add_or_update_deck = _FilteredDeckDialogWillAddOrUpdateDeckHook()
class _FlagLabelDidChangeHook:
    '''Used to update the GUI when a new flag label is assigned.'''
    _hooks: list[Callable[[], None]] = []

    
    def append(self, callback: Callable[[], None]) -> None:
        '''()'''
        self._hooks.append(callback)

    def remove(self, callback: Callable[[], None]) -> None:
        if callback in self._hooks:
            self._hooks.remove(callback)

    def count(self) -> int:
        return len(self._hooks)

    def __call__(self) -> None:
        for hook in self._hooks:
            try:
                hook()
            except Exception:
                # if the hook fails, remove it
                self._hooks.remove(hook)
                raise



flag_label_did_change = _FlagLabelDidChangeHook()
class _FocusDidChangeHook:
    '''Called each time the focus changes. Can be used to defer updates from
        `operation_did_execute` until a window is brought to the front.'''
    _hooks: list[Callable[["QWidget | None", "QWidget | None"], None]] = []

    
    def append(self, callback: Callable[["QWidget | None", "QWidget | None"], None]) -> None:
        '''(new: QWidget | None, old: QWidget | None)'''
        self._hooks.append(callback)

    def remove(self, callback: Callable[["QWidget | None", "QWidget | None"], None]) -> None:
        if callback in self._hooks:
            self._hooks.remove(callback)

    def count(self) -> int:
        return len(self._hooks)

    def __call__(self, new: QWidget | None, old: QWidget | None) -> None:
        for hook in self._hooks:
            try:
                hook(new, old)
            except Exception:
                # if the hook fails, remove it
                self._hooks.remove(hook)
                raise



focus_did_change = _FocusDidChangeHook()
class _LegacyExporterDidExportHook:
    '''Called after collection and deck exports performed by legacy exporters.'''
    _hooks: list[Callable[["anki.exporting.Exporter"], None]] = []

    
    def append(self, callback: Callable[["anki.exporting.Exporter"], None]) -> None:
        '''(legacy_exporter: anki.exporting.Exporter)'''
        self._hooks.append(callback)

    def remove(self, callback: Callable[["anki.exporting.Exporter"], None]) -> None:
        if callback in self._hooks:
            self._hooks.remove(callback)

    def count(self) -> int:
        return len(self._hooks)

    def __call__(self, legacy_exporter: anki.exporting.Exporter) -> None:
        for hook in self._hooks:
            try:
                hook(legacy_exporter)
            except Exception:
                # if the hook fails, remove it
                self._hooks.remove(hook)
                raise



legacy_exporter_did_export = _LegacyExporterDidExportHook()
class _LegacyExporterWillExportHook:
    '''Called before collection and deck exports performed by legacy exporters.'''
    _hooks: list[Callable[["anki.exporting.Exporter"], None]] = []

    
    def append(self, callback: Callable[["anki.exporting.Exporter"], None]) -> None:
        '''(legacy_exporter: anki.exporting.Exporter)'''
        self._hooks.append(callback)

    def remove(self, callback: Callable[["anki.exporting.Exporter"], None]) -> None:
        if callback in self._hooks:
            self._hooks.remove(callback)

    def count(self) -> int:
        return len(self._hooks)

    def __call__(self, legacy_exporter: anki.exporting.Exporter) -> None:
        for hook in self._hooks:
            try:
                hook(legacy_exporter)
            except Exception:
                # if the hook fails, remove it
                self._hooks.remove(hook)
                raise



legacy_exporter_will_export = _LegacyExporterWillExportHook()
class _MainWindowDidInitHook:
    '''Executed after the main window is fully initialized

        A sample use case for this hook would be to delay actions until Anki objects
        like the profile or collection are fully initialized. In contrast to
        `profile_did_open`, this hook will only fire once per Anki session and
        is thus suitable for single-shot subscribers.
        '''
    _hooks: list[Callable[[], None]] = []

    
    def append(self, callback: Callable[[], None]) -> None:
        '''()'''
        self._hooks.append(callback)

    def remove(self, callback: Callable[[], None]) -> None:
        if callback in self._hooks:
            self._hooks.remove(callback)

    def count(self) -> int:
        return len(self._hooks)

    def __call__(self) -> None:
        for hook in self._hooks:
            try:
                hook()
            except Exception:
                # if the hook fails, remove it
                self._hooks.remove(hook)
                raise



main_window_did_init = _MainWindowDidInitHook()
class _MainWindowShouldRequireResetFilter:
    '''Executed before the main window will require a reset

        This hook can be used to change the behavior of the main window,
        when other dialogs, like the AddCards or Browser, require a reset
        from the main window.
        If you decide to use this hook, make you sure you check the reason for the reset.
        Some reasons require more attention than others, and skipping important ones might
        put the main window into an invalid state (e.g. display a deleted note).
        '''
    _hooks: list[Callable[["bool", "aqt.main.ResetReason | str", "object | None"], bool]] = []

    
    def append(self, callback: Callable[["bool", "aqt.main.ResetReason | str", "object | None"], bool]) -> None:
        '''(will_reset: bool, reason: aqt.main.ResetReason | str, context: object | None)'''
        self._hooks.append(callback)

    def remove(self, callback: Callable[["bool", "aqt.main.ResetReason | str", "object | None"], bool]) -> None:
        if callback in self._hooks:
            self._hooks.remove(callback)

    def count(self) -> int:
        return len(self._hooks)

    def __call__(self, will_reset: bool, reason: aqt.main.ResetReason | str, context: object | None) -> bool:
        for filter in self._hooks:
            try:
                will_reset = filter(will_reset, reason, context)
            except Exception:
                # if the hook fails, remove it
                self._hooks.remove(filter)
                raise
        return will_reset



main_window_should_require_reset = _MainWindowShouldRequireResetFilter()
class _MediaCheckDidFinishHook:
    '''Called after Media Check finishes.

        `output` provides access to the unused/missing file lists and the text output that will be shown in the Check Media screen.'''
    _hooks: list[Callable[["anki.media.CheckMediaResponse"], None]] = []

    
    def append(self, callback: Callable[["anki.media.CheckMediaResponse"], None]) -> None:
        '''(output: anki.media.CheckMediaResponse)'''
        self._hooks.append(callback)

    def remove(self, callback: Callable[["anki.media.CheckMediaResponse"], None]) -> None:
        if callback in self._hooks:
            self._hooks.remove(callback)

    def count(self) -> int:
        return len(self._hooks)

    def __call__(self, output: anki.media.CheckMediaResponse) -> None:
        for hook in self._hooks:
            try:
                hook(output)
            except Exception:
                # if the hook fails, remove it
                self._hooks.remove(hook)
                raise



media_check_did_finish = _MediaCheckDidFinishHook()
class _MediaCheckWillStartHook:
    _hooks: list[Callable[[], None]] = []

    
    def append(self, callback: Callable[[], None]) -> None:
        '''()'''
        self._hooks.append(callback)

    def remove(self, callback: Callable[[], None]) -> None:
        if callback in self._hooks:
            self._hooks.remove(callback)

    def count(self) -> int:
        return len(self._hooks)

    def __call__(self) -> None:
        for hook in self._hooks:
            try:
                hook()
            except Exception:
                # if the hook fails, remove it
                self._hooks.remove(hook)
                raise



media_check_will_start = _MediaCheckWillStartHook()
class _MediaSyncDidProgressHook:
    _hooks: list[Callable[["str"], None]] = []

    
    def append(self, callback: Callable[["str"], None]) -> None:
        '''(entry: str)'''
        self._hooks.append(callback)

    def remove(self, callback: Callable[["str"], None]) -> None:
        if callback in self._hooks:
            self._hooks.remove(callback)

    def count(self) -> int:
        return len(self._hooks)

    def __call__(self, entry: str) -> None:
        for hook in self._hooks:
            try:
                hook(entry)
            except Exception:
                # if the hook fails, remove it
                self._hooks.remove(hook)
                raise



media_sync_did_progress = _MediaSyncDidProgressHook()
class _MediaSyncDidStartOrStopHook:
    _hooks: list[Callable[["bool"], None]] = []

    
    def append(self, callback: Callable[["bool"], None]) -> None:
        '''(running: bool)'''
        self._hooks.append(callback)

    def remove(self, callback: Callable[["bool"], None]) -> None:
        if callback in self._hooks:
            self._hooks.remove(callback)

    def count(self) -> int:
        return len(self._hooks)

    def __call__(self, running: bool) -> None:
        for hook in self._hooks:
            try:
                hook(running)
            except Exception:
                # if the hook fails, remove it
                self._hooks.remove(hook)
                raise



media_sync_did_start_or_stop = _MediaSyncDidStartOrStopHook()
class _ModelsAdvancedWillShowHook:
    _hooks: list[Callable[["QDialog"], None]] = []

    
    def append(self, callback: Callable[["QDialog"], None]) -> None:
        '''(advanced: QDialog)'''
        self._hooks.append(callback)

    def remove(self, callback: Callable[["QDialog"], None]) -> None:
        if callback in self._hooks:
            self._hooks.remove(callback)

    def count(self) -> int:
        return len(self._hooks)

    def __call__(self, advanced: QDialog) -> None:
        for hook in self._hooks:
            try:
                hook(advanced)
            except Exception:
                # if the hook fails, remove it
                self._hooks.remove(hook)
                raise



models_advanced_will_show = _ModelsAdvancedWillShowHook()
class _ModelsDidInitButtonsFilter:
    '''Allows adding buttons to the Model dialog'''
    _hooks: list[Callable[["list[tuple[str, Callable[[], None]]]", "aqt.models.Models"], list[tuple[str, Callable[[], None]]]]] = []

    
    def append(self, callback: Callable[["list[tuple[str, Callable[[], None]]]", "aqt.models.Models"], list[tuple[str, Callable[[], None]]]]) -> None:
        '''(buttons: list[tuple[str, Callable[[], None]]], models: aqt.models.Models)'''
        self._hooks.append(callback)

    def remove(self, callback: Callable[["list[tuple[str, Callable[[], None]]]", "aqt.models.Models"], list[tuple[str, Callable[[], None]]]]) -> None:
        if callback in self._hooks:
            self._hooks.remove(callback)

    def count(self) -> int:
        return len(self._hooks)

    def __call__(self, buttons: list[tuple[str, Callable[[], None]]], models: aqt.models.Models) -> list[tuple[str, Callable[[], None]]]:
        for filter in self._hooks:
            try:
                buttons = filter(buttons, models)
            except Exception:
                # if the hook fails, remove it
                self._hooks.remove(filter)
                raise
        return buttons



models_did_init_buttons = _ModelsDidInitButtonsFilter()
class _OperationDidExecuteHook:
    '''Called after an operation completes.
        Changes can be inspected to determine whether the UI needs updating.

        This will also be called when the legacy mw.reset() is used.
        '''
    _hooks: list[Callable[["anki.collection.OpChanges", "object | None"], None]] = []

    
    def append(self, callback: Callable[["anki.collection.OpChanges", "object | None"], None]) -> None:
        '''(changes: anki.collection.OpChanges, handler: object | None)'''
        self._hooks.append(callback)

    def remove(self, callback: Callable[["anki.collection.OpChanges", "object | None"], None]) -> None:
        if callback in self._hooks:
            self._hooks.remove(callback)

    def count(self) -> int:
        return len(self._hooks)

    def __call__(self, changes: anki.collection.OpChanges, handler: object | None) -> None:
        for hook in self._hooks:
            try:
                hook(changes, handler)
            except Exception:
                # if the hook fails, remove it
                self._hooks.remove(hook)
                raise



operation_did_execute = _OperationDidExecuteHook()
class _OverviewDidRefreshHook:
    '''Allow to update the overview window. E.g. add the deck name in the
        title.'''
    _hooks: list[Callable[["aqt.overview.Overview"], None]] = []

    
    def append(self, callback: Callable[["aqt.overview.Overview"], None]) -> None:
        '''(overview: aqt.overview.Overview)'''
        self._hooks.append(callback)

    def remove(self, callback: Callable[["aqt.overview.Overview"], None]) -> None:
        if callback in self._hooks:
            self._hooks.remove(callback)

    def count(self) -> int:
        return len(self._hooks)

    def __call__(self, overview: aqt.overview.Overview) -> None:
        for hook in self._hooks:
            try:
                hook(overview)
            except Exception:
                # if the hook fails, remove it
                self._hooks.remove(hook)
                raise



overview_did_refresh = _OverviewDidRefreshHook()
class _OverviewWillRenderBottomFilter:
    '''Allows adding buttons to the Overview bottom bar.

        Append a list of strings to 'links' argument to add new buttons.
        - The first value is the shortcut to appear in the tooltip.
        - The second value is the url to be triggered.
        - The third value is the text of the new button.

        Extend the callable 'link_handler' to handle new urls. This callable
        accepts one argument: the triggered url.
        Make a check of the triggered url, call any functions related to
        that trigger, and return the new link_handler.

        Example:
        links.append(['H', 'hello', 'Click me!'])
        def custom_link_handler(url):
            if url == 'hello':
                print('Hello World!')
            return link_handler(url=url)
        return custom_link_handler
        '''
    _hooks: list[Callable[["Callable[[str], bool]", "list[list[str]]"], Callable[[str], bool]]] = []

    
    def append(self, callback: Callable[["Callable[[str], bool]", "list[list[str]]"], Callable[[str], bool]]) -> None:
        '''(link_handler: Callable[[str], bool], links: list[list[str]])'''
        self._hooks.append(callback)

    def remove(self, callback: Callable[["Callable[[str], bool]", "list[list[str]]"], Callable[[str], bool]]) -> None:
        if callback in self._hooks:
            self._hooks.remove(callback)

    def count(self) -> int:
        return len(self._hooks)

    def __call__(self, link_handler: Callable[[str], bool], links: list[list[str]]) -> Callable[[str], bool]:
        for filter in self._hooks:
            try:
                link_handler = filter(link_handler, links)
            except Exception:
                # if the hook fails, remove it
                self._hooks.remove(filter)
                raise
        return link_handler



overview_will_render_bottom = _OverviewWillRenderBottomFilter()
class _OverviewWillRenderContentHook:
    '''Used to modify HTML content sections in the overview body

        'content' contains the sections of HTML content the overview body
        will be updated with.

        When modifying the content of a particular section, please make sure your
        changes only perform the minimum required edits to make your add-on work.
        You should avoid overwriting or interfering with existing data as much
        as possible, instead opting to append your own changes, e.g.:

            def on_overview_will_render_content(overview, content):
                content.table += "
<div>my html</div>"
        '''
    _hooks: list[Callable[["aqt.overview.Overview", "aqt.overview.OverviewContent"], None]] = []

    
    def append(self, callback: Callable[["aqt.overview.Overview", "aqt.overview.OverviewContent"], None]) -> None:
        '''(overview: aqt.overview.Overview, content: aqt.overview.OverviewContent)'''
        self._hooks.append(callback)

    def remove(self, callback: Callable[["aqt.overview.Overview", "aqt.overview.OverviewContent"], None]) -> None:
        if callback in self._hooks:
            self._hooks.remove(callback)

    def count(self) -> int:
        return len(self._hooks)

    def __call__(self, overview: aqt.overview.Overview, content: aqt.overview.OverviewContent) -> None:
        for hook in self._hooks:
            try:
                hook(overview, content)
            except Exception:
                # if the hook fails, remove it
                self._hooks.remove(hook)
                raise



overview_will_render_content = _OverviewWillRenderContentHook()
class _PreviewerDidInitHook:
    '''Called after the previewer is initialized.'''
    _hooks: list[Callable[["aqt.browser.previewer.Previewer"], None]] = []

    
    def append(self, callback: Callable[["aqt.browser.previewer.Previewer"], None]) -> None:
        '''(previewer: aqt.browser.previewer.Previewer)'''
        self._hooks.append(callback)

    def remove(self, callback: Callable[["aqt.browser.previewer.Previewer"], None]) -> None:
        if callback in self._hooks:
            self._hooks.remove(callback)

    def count(self) -> int:
        return len(self._hooks)

    def __call__(self, previewer: aqt.browser.previewer.Previewer) -> None:
        for hook in self._hooks:
            try:
                hook(previewer)
            except Exception:
                # if the hook fails, remove it
                self._hooks.remove(hook)
                raise



previewer_did_init = _PreviewerDidInitHook()
class _PreviewerWillRedrawAfterShowBothSidesToggledHook:
    '''Called when the checkbox <show both sides> is toggled by the user.'''
    _hooks: list[Callable[["aqt.webview.AnkiWebView", "Card", "bool", "bool"], None]] = []

    
    def append(self, callback: Callable[["aqt.webview.AnkiWebView", "Card", "bool", "bool"], None]) -> None:
        '''(webview: aqt.webview.AnkiWebView, card: Card, is_front_side: bool, show_both_sides: bool)'''
        self._hooks.append(callback)

    def remove(self, callback: Callable[["aqt.webview.AnkiWebView", "Card", "bool", "bool"], None]) -> None:
        if callback in self._hooks:
            self._hooks.remove(callback)

    def count(self) -> int:
        return len(self._hooks)

    def __call__(self, webview: aqt.webview.AnkiWebView, card: Card, is_front_side: bool, show_both_sides: bool) -> None:
        for hook in self._hooks:
            try:
                hook(webview, card, is_front_side, show_both_sides)
            except Exception:
                # if the hook fails, remove it
                self._hooks.remove(hook)
                raise



previewer_will_redraw_after_show_both_sides_toggled = _PreviewerWillRedrawAfterShowBothSidesToggledHook()
class _ProfileDidOpenHook:
    '''Executed whenever a user profile has been opened

        Please note that this hook will also be called on profile switches, so if you
        are looking to simply delay an add-on action in a single-shot manner,
        `main_window_did_init` is likely the more suitable choice.
        '''
    _hooks: list[Callable[[], None]] = []

    
    def append(self, callback: Callable[[], None]) -> None:
        '''()'''
        self._hooks.append(callback)

    def remove(self, callback: Callable[[], None]) -> None:
        if callback in self._hooks:
            self._hooks.remove(callback)

    def count(self) -> int:
        return len(self._hooks)

    def __call__(self) -> None:
        for hook in self._hooks:
            try:
                hook()
            except Exception:
                # if the hook fails, remove it
                self._hooks.remove(hook)
                raise
        # legacy support
        anki.hooks.runHook("profileLoaded")



profile_did_open = _ProfileDidOpenHook()
class _ProfileWillCloseHook:
    _hooks: list[Callable[[], None]] = []

    
    def append(self, callback: Callable[[], None]) -> None:
        '''()'''
        self._hooks.append(callback)

    def remove(self, callback: Callable[[], None]) -> None:
        if callback in self._hooks:
            self._hooks.remove(callback)

    def count(self) -> int:
        return len(self._hooks)

    def __call__(self) -> None:
        for hook in self._hooks:
            try:
                hook()
            except Exception:
                # if the hook fails, remove it
                self._hooks.remove(hook)
                raise
        # legacy support
        anki.hooks.runHook("unloadProfile")



profile_will_close = _ProfileWillCloseHook()
class _ReviewerDidAnswerCardHook:
    _hooks: list[Callable[["aqt.reviewer.Reviewer", "Card", "Literal[1, 2, 3, 4]"], None]] = []

    
    def append(self, callback: Callable[["aqt.reviewer.Reviewer", "Card", "Literal[1, 2, 3, 4]"], None]) -> None:
        '''(reviewer: aqt.reviewer.Reviewer, card: Card, ease: Literal[1, 2, 3, 4])'''
        self._hooks.append(callback)

    def remove(self, callback: Callable[["aqt.reviewer.Reviewer", "Card", "Literal[1, 2, 3, 4]"], None]) -> None:
        if callback in self._hooks:
            self._hooks.remove(callback)

    def count(self) -> int:
        return len(self._hooks)

    def __call__(self, reviewer: aqt.reviewer.Reviewer, card: Card, ease: Literal[1, 2, 3, 4]) -> None:
        for hook in self._hooks:
            try:
                hook(reviewer, card, ease)
            except Exception:
                # if the hook fails, remove it
                self._hooks.remove(hook)
                raise



reviewer_did_answer_card = _ReviewerDidAnswerCardHook()
class _ReviewerDidInitHook:
    '''Called after the reviewer is initialized.'''
    _hooks: list[Callable[["aqt.reviewer.Reviewer"], None]] = []

    
    def append(self, callback: Callable[["aqt.reviewer.Reviewer"], None]) -> None:
        '''(reviewer: aqt.reviewer.Reviewer)'''
        self._hooks.append(callback)

    def remove(self, callback: Callable[["aqt.reviewer.Reviewer"], None]) -> None:
        if callback in self._hooks:
            self._hooks.remove(callback)

    def count(self) -> int:
        return len(self._hooks)

    def __call__(self, reviewer: aqt.reviewer.Reviewer) -> None:
        for hook in self._hooks:
            try:
                hook(reviewer)
            except Exception:
                # if the hook fails, remove it
                self._hooks.remove(hook)
                raise



reviewer_did_init = _ReviewerDidInitHook()
class _ReviewerDidShowAnswerHook:
    _hooks: list[Callable[["Card"], None]] = []

    
    def append(self, callback: Callable[["Card"], None]) -> None:
        '''(card: Card)'''
        self._hooks.append(callback)

    def remove(self, callback: Callable[["Card"], None]) -> None:
        if callback in self._hooks:
            self._hooks.remove(callback)

    def count(self) -> int:
        return len(self._hooks)

    def __call__(self, card: Card) -> None:
        for hook in self._hooks:
            try:
                hook(card)
            except Exception:
                # if the hook fails, remove it
                self._hooks.remove(hook)
                raise
        # legacy support
        anki.hooks.runHook("showAnswer")



reviewer_did_show_answer = _ReviewerDidShowAnswerHook()
class _ReviewerDidShowQuestionHook:
    _hooks: list[Callable[["Card"], None]] = []

    
    def append(self, callback: Callable[["Card"], None]) -> None:
        '''(card: Card)'''
        self._hooks.append(callback)

    def remove(self, callback: Callable[["Card"], None]) -> None:
        if callback in self._hooks:
            self._hooks.remove(callback)

    def count(self) -> int:
        return len(self._hooks)

    def __call__(self, card: Card) -> None:
        for hook in self._hooks:
            try:
                hook(card)
            except Exception:
                # if the hook fails, remove it
                self._hooks.remove(hook)
                raise
        # legacy support
        anki.hooks.runHook("showQuestion")



reviewer_did_show_question = _ReviewerDidShowQuestionHook()
class _ReviewerWillAnswerCardFilter:
    '''Used to modify the ease at which a card is rated or to bypass
        rating the card completely.

        ease_tuple is a tuple consisting of a boolean expressing whether the reviewer
        should continue with rating the card, and an integer expressing the ease at
        which the card should be rated.

        If your code just needs to be notified of the card rating event, you should use
        the reviewer_did_answer_card hook instead.'''
    _hooks: list[Callable[["tuple[bool, Literal[1, 2, 3, 4]]", "aqt.reviewer.Reviewer", "Card"], tuple[bool, Literal[1, 2, 3, 4]]]] = []

    
    def append(self, callback: Callable[["tuple[bool, Literal[1, 2, 3, 4]]", "aqt.reviewer.Reviewer", "Card"], tuple[bool, Literal[1, 2, 3, 4]]]) -> None:
        '''(ease_tuple: tuple[bool, Literal[1, 2, 3, 4]], reviewer: aqt.reviewer.Reviewer, card: Card)'''
        self._hooks.append(callback)

    def remove(self, callback: Callable[["tuple[bool, Literal[1, 2, 3, 4]]", "aqt.reviewer.Reviewer", "Card"], tuple[bool, Literal[1, 2, 3, 4]]]) -> None:
        if callback in self._hooks:
            self._hooks.remove(callback)

    def count(self) -> int:
        return len(self._hooks)

    def __call__(self, ease_tuple: tuple[bool, Literal[1, 2, 3, 4]], reviewer: aqt.reviewer.Reviewer, card: Card) -> tuple[bool, Literal[1, 2, 3, 4]]:
        for filter in self._hooks:
            try:
                ease_tuple = filter(ease_tuple, reviewer, card)
            except Exception:
                # if the hook fails, remove it
                self._hooks.remove(filter)
                raise
        return ease_tuple



reviewer_will_answer_card = _ReviewerWillAnswerCardFilter()
class _ReviewerWillBuryCardHook:
    _hooks: list[Callable[["int"], None]] = []

    
    def append(self, callback: Callable[["int"], None]) -> None:
        '''(id: int)'''
        self._hooks.append(callback)

    def remove(self, callback: Callable[["int"], None]) -> None:
        if callback in self._hooks:
            self._hooks.remove(callback)

    def count(self) -> int:
        return len(self._hooks)

    def __call__(self, id: int) -> None:
        for hook in self._hooks:
            try:
                hook(id)
            except Exception:
                # if the hook fails, remove it
                self._hooks.remove(hook)
                raise



reviewer_will_bury_card = _ReviewerWillBuryCardHook()
class _ReviewerWillBuryNoteHook:
    _hooks: list[Callable[["int"], None]] = []

    
    def append(self, callback: Callable[["int"], None]) -> None:
        '''(nid: int)'''
        self._hooks.append(callback)

    def remove(self, callback: Callable[["int"], None]) -> None:
        if callback in self._hooks:
            self._hooks.remove(callback)

    def count(self) -> int:
        return len(self._hooks)

    def __call__(self, nid: int) -> None:
        for hook in self._hooks:
            try:
                hook(nid)
            except Exception:
                # if the hook fails, remove it
                self._hooks.remove(hook)
                raise



reviewer_will_bury_note = _ReviewerWillBuryNoteHook()
class _ReviewerWillCompareAnswerFilter:
    '''Modify expected answer and provided answer before comparing

        expected_provided_tuple is a tuple composed of:
        - expected answer
        - provided answer
        type_pattern is the detail of the type tag on the card

        Return a tuple composed of:
        - modified expected answer
        - modified provided answer
        '''
    _hooks: list[Callable[["tuple[str, str]", "str"], tuple[str, str]]] = []

    
    def append(self, callback: Callable[["tuple[str, str]", "str"], tuple[str, str]]) -> None:
        '''(expected_provided_tuple: tuple[str, str], type_pattern: str)'''
        self._hooks.append(callback)

    def remove(self, callback: Callable[["tuple[str, str]", "str"], tuple[str, str]]) -> None:
        if callback in self._hooks:
            self._hooks.remove(callback)

    def count(self) -> int:
        return len(self._hooks)

    def __call__(self, expected_provided_tuple: tuple[str, str], type_pattern: str) -> tuple[str, str]:
        for filter in self._hooks:
            try:
                expected_provided_tuple = filter(expected_provided_tuple, type_pattern)
            except Exception:
                # if the hook fails, remove it
                self._hooks.remove(filter)
                raise
        return expected_provided_tuple



reviewer_will_compare_answer = _ReviewerWillCompareAnswerFilter()
class _ReviewerWillEndHook:
    '''Called before Anki transitions from the review screen to another screen.'''
    _hooks: list[Callable[[], None]] = []

    
    def append(self, callback: Callable[[], None]) -> None:
        '''()'''
        self._hooks.append(callback)

    def remove(self, callback: Callable[[], None]) -> None:
        if callback in self._hooks:
            self._hooks.remove(callback)

    def count(self) -> int:
        return len(self._hooks)

    def __call__(self) -> None:
        for hook in self._hooks:
            try:
                hook()
            except Exception:
                # if the hook fails, remove it
                self._hooks.remove(hook)
                raise
        # legacy support
        anki.hooks.runHook("reviewCleanup")



reviewer_will_end = _ReviewerWillEndHook()
class _ReviewerWillInitAnswerButtonsFilter:
    '''Used to modify list of answer buttons

        buttons_tuple is a tuple of buttons, with each button represented by a
        tuple containing an int for the button's ease and a string for the
        button's label.

        Return a tuple of the form ((int, str), ...), e.g.:
            ((1, "Label1"), (2, "Label2"), ...)

        Note: import _ from anki.lang to support translation, using, e.g.,
            ((1, _("Label1")), ...)
        '''
    _hooks: list[Callable[["tuple[tuple[int, str], ...]", "aqt.reviewer.Reviewer", "Card"], tuple[tuple[int, str], ...]]] = []

    
    def append(self, callback: Callable[["tuple[tuple[int, str], ...]", "aqt.reviewer.Reviewer", "Card"], tuple[tuple[int, str], ...]]) -> None:
        '''(buttons_tuple: tuple[tuple[int, str], ...], reviewer: aqt.reviewer.Reviewer, card: Card)'''
        self._hooks.append(callback)

    def remove(self, callback: Callable[["tuple[tuple[int, str], ...]", "aqt.reviewer.Reviewer", "Card"], tuple[tuple[int, str], ...]]) -> None:
        if callback in self._hooks:
            self._hooks.remove(callback)

    def count(self) -> int:
        return len(self._hooks)

    def __call__(self, buttons_tuple: tuple[tuple[int, str], ...], reviewer: aqt.reviewer.Reviewer, card: Card) -> tuple[tuple[int, str], ...]:
        for filter in self._hooks:
            try:
                buttons_tuple = filter(buttons_tuple, reviewer, card)
            except Exception:
                # if the hook fails, remove it
                self._hooks.remove(filter)
                raise
        return buttons_tuple



reviewer_will_init_answer_buttons = _ReviewerWillInitAnswerButtonsFilter()
class _ReviewerWillPlayAnswerSoundsHook:
    '''Called before showing the answer/back side.

        `tags` can be used to inspect and manipulate the sounds
        that will be played (if any).

        This won't be called when the user manually plays sounds
        using `Replay Audio`.

        Note that this hook is called even when the `Automatically play audio`
        option is unchecked; This is so as to allow playing custom
        sounds regardless of that option.'''
    _hooks: list[Callable[["Card", "list[anki.sound.AVTag]"], None]] = []

    
    def append(self, callback: Callable[["Card", "list[anki.sound.AVTag]"], None]) -> None:
        '''(card: Card, tags: list[anki.sound.AVTag])'''
        self._hooks.append(callback)

    def remove(self, callback: Callable[["Card", "list[anki.sound.AVTag]"], None]) -> None:
        if callback in self._hooks:
            self._hooks.remove(callback)

    def count(self) -> int:
        return len(self._hooks)

    def __call__(self, card: Card, tags: list[anki.sound.AVTag]) -> None:
        for hook in self._hooks:
            try:
                hook(card, tags)
            except Exception:
                # if the hook fails, remove it
                self._hooks.remove(hook)
                raise



reviewer_will_play_answer_sounds = _ReviewerWillPlayAnswerSoundsHook()
class _ReviewerWillPlayQuestionSoundsHook:
    '''Called before showing the question/front side.

        `tags` can be used to inspect and manipulate the sounds
        that will be played (if any).

        This won't be called when the user manually plays sounds
        using `Replay Audio`.

        Note that this hook is called even when the `Automatically play audio`
        option is unchecked; This is so as to allow playing custom
        sounds regardless of that option.'''
    _hooks: list[Callable[["Card", "list[anki.sound.AVTag]"], None]] = []

    
    def append(self, callback: Callable[["Card", "list[anki.sound.AVTag]"], None]) -> None:
        '''(card: Card, tags: list[anki.sound.AVTag])'''
        self._hooks.append(callback)

    def remove(self, callback: Callable[["Card", "list[anki.sound.AVTag]"], None]) -> None:
        if callback in self._hooks:
            self._hooks.remove(callback)

    def count(self) -> int:
        return len(self._hooks)

    def __call__(self, card: Card, tags: list[anki.sound.AVTag]) -> None:
        for hook in self._hooks:
            try:
                hook(card, tags)
            except Exception:
                # if the hook fails, remove it
                self._hooks.remove(hook)
                raise



reviewer_will_play_question_sounds = _ReviewerWillPlayQuestionSoundsHook()
class _ReviewerWillRenderComparedAnswerFilter:
    '''Modify the output of default compare answer feature

        output is the result of default compare answer function
        initial_expected is the expected answer from the card
        initial_provided is the answer provided during review
        type_pattern is the detail of the type tag on the card

        Return a string comparing expected and provided answers
        '''
    _hooks: list[Callable[["str", "str", "str", "str"], str]] = []

    
    def append(self, callback: Callable[["str", "str", "str", "str"], str]) -> None:
        '''(output: str, initial_expected: str, initial_provided: str, type_pattern: str)'''
        self._hooks.append(callback)

    def remove(self, callback: Callable[["str", "str", "str", "str"], str]) -> None:
        if callback in self._hooks:
            self._hooks.remove(callback)

    def count(self) -> int:
        return len(self._hooks)

    def __call__(self, output: str, initial_expected: str, initial_provided: str, type_pattern: str) -> str:
        for filter in self._hooks:
            try:
                output = filter(output, initial_expected, initial_provided, type_pattern)
            except Exception:
                # if the hook fails, remove it
                self._hooks.remove(filter)
                raise
        return output



reviewer_will_render_compared_answer = _ReviewerWillRenderComparedAnswerFilter()
class _ReviewerWillReplayRecordingFilter:
    '''Used to inspect and modify a recording recorded by "Record Own Voice" before replaying.'''
    _hooks: list[Callable[["str"], str]] = []

    
    def append(self, callback: Callable[["str"], str]) -> None:
        '''(path: str)'''
        self._hooks.append(callback)

    def remove(self, callback: Callable[["str"], str]) -> None:
        if callback in self._hooks:
            self._hooks.remove(callback)

    def count(self) -> int:
        return len(self._hooks)

    def __call__(self, path: str) -> str:
        for filter in self._hooks:
            try:
                path = filter(path)
            except Exception:
                # if the hook fails, remove it
                self._hooks.remove(filter)
                raise
        return path



reviewer_will_replay_recording = _ReviewerWillReplayRecordingFilter()
class _ReviewerWillShowContextMenuHook:
    _hooks: list[Callable[["aqt.reviewer.Reviewer", "QMenu"], None]] = []

    
    def append(self, callback: Callable[["aqt.reviewer.Reviewer", "QMenu"], None]) -> None:
        '''(reviewer: aqt.reviewer.Reviewer, menu: QMenu)'''
        self._hooks.append(callback)

    def remove(self, callback: Callable[["aqt.reviewer.Reviewer", "QMenu"], None]) -> None:
        if callback in self._hooks:
            self._hooks.remove(callback)

    def count(self) -> int:
        return len(self._hooks)

    def __call__(self, reviewer: aqt.reviewer.Reviewer, menu: QMenu) -> None:
        for hook in self._hooks:
            try:
                hook(reviewer, menu)
            except Exception:
                # if the hook fails, remove it
                self._hooks.remove(hook)
                raise
        # legacy support
        anki.hooks.runHook("Reviewer.contextMenuEvent", reviewer, menu)



reviewer_will_show_context_menu = _ReviewerWillShowContextMenuHook()
class _ReviewerWillSuspendCardHook:
    _hooks: list[Callable[["int"], None]] = []

    
    def append(self, callback: Callable[["int"], None]) -> None:
        '''(id: int)'''
        self._hooks.append(callback)

    def remove(self, callback: Callable[["int"], None]) -> None:
        if callback in self._hooks:
            self._hooks.remove(callback)

    def count(self) -> int:
        return len(self._hooks)

    def __call__(self, id: int) -> None:
        for hook in self._hooks:
            try:
                hook(id)
            except Exception:
                # if the hook fails, remove it
                self._hooks.remove(hook)
                raise



reviewer_will_suspend_card = _ReviewerWillSuspendCardHook()
class _ReviewerWillSuspendNoteHook:
    _hooks: list[Callable[["int"], None]] = []

    
    def append(self, callback: Callable[["int"], None]) -> None:
        '''(nid: int)'''
        self._hooks.append(callback)

    def remove(self, callback: Callable[["int"], None]) -> None:
        if callback in self._hooks:
            self._hooks.remove(callback)

    def count(self) -> int:
        return len(self._hooks)

    def __call__(self, nid: int) -> None:
        for hook in self._hooks:
            try:
                hook(nid)
            except Exception:
                # if the hook fails, remove it
                self._hooks.remove(hook)
                raise



reviewer_will_suspend_note = _ReviewerWillSuspendNoteHook()
class _SidebarShouldRefreshDecksHook:
    '''Legacy, do not use.'''
    _hooks: list[Callable[[], None]] = []

    
    def append(self, callback: Callable[[], None]) -> None:
        '''()'''
        self._hooks.append(callback)

    def remove(self, callback: Callable[[], None]) -> None:
        if callback in self._hooks:
            self._hooks.remove(callback)

    def count(self) -> int:
        return len(self._hooks)

    def __call__(self) -> None:
        for hook in self._hooks:
            try:
                hook()
            except Exception:
                # if the hook fails, remove it
                self._hooks.remove(hook)
                raise



sidebar_should_refresh_decks = _SidebarShouldRefreshDecksHook()
class _SidebarShouldRefreshNotetypesHook:
    '''Legacy, do not use.'''
    _hooks: list[Callable[[], None]] = []

    
    def append(self, callback: Callable[[], None]) -> None:
        '''()'''
        self._hooks.append(callback)

    def remove(self, callback: Callable[[], None]) -> None:
        if callback in self._hooks:
            self._hooks.remove(callback)

    def count(self) -> int:
        return len(self._hooks)

    def __call__(self) -> None:
        for hook in self._hooks:
            try:
                hook()
            except Exception:
                # if the hook fails, remove it
                self._hooks.remove(hook)
                raise



sidebar_should_refresh_notetypes = _SidebarShouldRefreshNotetypesHook()
class _StateDidChangeHook:
    _hooks: list[Callable[["aqt.main.MainWindowState", "aqt.main.MainWindowState"], None]] = []

    
    def append(self, callback: Callable[["aqt.main.MainWindowState", "aqt.main.MainWindowState"], None]) -> None:
        '''(new_state: aqt.main.MainWindowState, old_state: aqt.main.MainWindowState)'''
        self._hooks.append(callback)

    def remove(self, callback: Callable[["aqt.main.MainWindowState", "aqt.main.MainWindowState"], None]) -> None:
        if callback in self._hooks:
            self._hooks.remove(callback)

    def count(self) -> int:
        return len(self._hooks)

    def __call__(self, new_state: aqt.main.MainWindowState, old_state: aqt.main.MainWindowState) -> None:
        for hook in self._hooks:
            try:
                hook(new_state, old_state)
            except Exception:
                # if the hook fails, remove it
                self._hooks.remove(hook)
                raise
        # legacy support
        anki.hooks.runHook("afterStateChange", new_state, old_state)



state_did_change = _StateDidChangeHook()
class _StateDidResetHook:
    '''Legacy 'reset' hook. Called by mw.reset() and CollectionOp() to redraw the UI.

        New code should use `operation_did_execute` instead.
        '''
    _hooks: list[Callable[[], None]] = []

    
    def append(self, callback: Callable[[], None]) -> None:
        '''()'''
        self._hooks.append(callback)

    def remove(self, callback: Callable[[], None]) -> None:
        if callback in self._hooks:
            self._hooks.remove(callback)

    def count(self) -> int:
        return len(self._hooks)

    def __call__(self) -> None:
        for hook in self._hooks:
            try:
                hook()
            except Exception:
                # if the hook fails, remove it
                self._hooks.remove(hook)
                raise
        # legacy support
        anki.hooks.runHook("reset")



state_did_reset = _StateDidResetHook()
class _StateDidUndoHook:
    '''Called after backend undoes a change.'''
    _hooks: list[Callable[["OpChangesAfterUndo"], None]] = []

    
    def append(self, callback: Callable[["OpChangesAfterUndo"], None]) -> None:
        '''(changes: OpChangesAfterUndo)'''
        self._hooks.append(callback)

    def remove(self, callback: Callable[["OpChangesAfterUndo"], None]) -> None:
        if callback in self._hooks:
            self._hooks.remove(callback)

    def count(self) -> int:
        return len(self._hooks)

    def __call__(self, changes: OpChangesAfterUndo) -> None:
        for hook in self._hooks:
            try:
                hook(changes)
            except Exception:
                # if the hook fails, remove it
                self._hooks.remove(hook)
                raise



state_did_undo = _StateDidUndoHook()
class _StateShortcutsWillChangeHook:
    _hooks: list[Callable[["aqt.main.MainWindowState", "list[tuple[str, Callable]]"], None]] = []

    
    def append(self, callback: Callable[["aqt.main.MainWindowState", "list[tuple[str, Callable]]"], None]) -> None:
        '''(state: aqt.main.MainWindowState, shortcuts: list[tuple[str, Callable]])'''
        self._hooks.append(callback)

    def remove(self, callback: Callable[["aqt.main.MainWindowState", "list[tuple[str, Callable]]"], None]) -> None:
        if callback in self._hooks:
            self._hooks.remove(callback)

    def count(self) -> int:
        return len(self._hooks)

    def __call__(self, state: aqt.main.MainWindowState, shortcuts: list[tuple[str, Callable]]) -> None:
        for hook in self._hooks:
            try:
                hook(state, shortcuts)
            except Exception:
                # if the hook fails, remove it
                self._hooks.remove(hook)
                raise



state_shortcuts_will_change = _StateShortcutsWillChangeHook()
class _StateWillChangeHook:
    _hooks: list[Callable[["aqt.main.MainWindowState", "aqt.main.MainWindowState"], None]] = []

    
    def append(self, callback: Callable[["aqt.main.MainWindowState", "aqt.main.MainWindowState"], None]) -> None:
        '''(new_state: aqt.main.MainWindowState, old_state: aqt.main.MainWindowState)'''
        self._hooks.append(callback)

    def remove(self, callback: Callable[["aqt.main.MainWindowState", "aqt.main.MainWindowState"], None]) -> None:
        if callback in self._hooks:
            self._hooks.remove(callback)

    def count(self) -> int:
        return len(self._hooks)

    def __call__(self, new_state: aqt.main.MainWindowState, old_state: aqt.main.MainWindowState) -> None:
        for hook in self._hooks:
            try:
                hook(new_state, old_state)
            except Exception:
                # if the hook fails, remove it
                self._hooks.remove(hook)
                raise
        # legacy support
        anki.hooks.runHook("beforeStateChange", new_state, old_state)



state_will_change = _StateWillChangeHook()
class _StatsDialogOldWillShowHook:
    '''Allows changing the old stats dialog before it is shown.'''
    _hooks: list[Callable[["aqt.stats.DeckStats"], None]] = []

    
    def append(self, callback: Callable[["aqt.stats.DeckStats"], None]) -> None:
        '''(dialog: aqt.stats.DeckStats)'''
        self._hooks.append(callback)

    def remove(self, callback: Callable[["aqt.stats.DeckStats"], None]) -> None:
        if callback in self._hooks:
            self._hooks.remove(callback)

    def count(self) -> int:
        return len(self._hooks)

    def __call__(self, dialog: aqt.stats.DeckStats) -> None:
        for hook in self._hooks:
            try:
                hook(dialog)
            except Exception:
                # if the hook fails, remove it
                self._hooks.remove(hook)
                raise



stats_dialog_old_will_show = _StatsDialogOldWillShowHook()
class _StatsDialogWillShowHook:
    '''Allows changing the stats dialog before it is shown.'''
    _hooks: list[Callable[["aqt.stats.NewDeckStats"], None]] = []

    
    def append(self, callback: Callable[["aqt.stats.NewDeckStats"], None]) -> None:
        '''(dialog: aqt.stats.NewDeckStats)'''
        self._hooks.append(callback)

    def remove(self, callback: Callable[["aqt.stats.NewDeckStats"], None]) -> None:
        if callback in self._hooks:
            self._hooks.remove(callback)

    def count(self) -> int:
        return len(self._hooks)

    def __call__(self, dialog: aqt.stats.NewDeckStats) -> None:
        for hook in self._hooks:
            try:
                hook(dialog)
            except Exception:
                # if the hook fails, remove it
                self._hooks.remove(hook)
                raise



stats_dialog_will_show = _StatsDialogWillShowHook()
class _StyleDidInitFilter:
    _hooks: list[Callable[["str"], str]] = []

    
    def append(self, callback: Callable[["str"], str]) -> None:
        '''(style: str)'''
        self._hooks.append(callback)

    def remove(self, callback: Callable[["str"], str]) -> None:
        if callback in self._hooks:
            self._hooks.remove(callback)

    def count(self) -> int:
        return len(self._hooks)

    def __call__(self, style: str) -> str:
        for filter in self._hooks:
            try:
                style = filter(style)
            except Exception:
                # if the hook fails, remove it
                self._hooks.remove(filter)
                raise
        # legacy support
        style = anki.hooks.runFilter("setupStyle", style)
        return style



style_did_init = _StyleDidInitFilter()
class _SyncDidFinishHook:
    '''Executes after the sync of the collection concluded.

        Note that the media sync did not necessarily finish at this point.'''
    _hooks: list[Callable[[], None]] = []

    
    def append(self, callback: Callable[[], None]) -> None:
        '''()'''
        self._hooks.append(callback)

    def remove(self, callback: Callable[[], None]) -> None:
        if callback in self._hooks:
            self._hooks.remove(callback)

    def count(self) -> int:
        return len(self._hooks)

    def __call__(self) -> None:
        for hook in self._hooks:
            try:
                hook()
            except Exception:
                # if the hook fails, remove it
                self._hooks.remove(hook)
                raise



sync_did_finish = _SyncDidFinishHook()
class _SyncWillStartHook:
    _hooks: list[Callable[[], None]] = []

    
    def append(self, callback: Callable[[], None]) -> None:
        '''()'''
        self._hooks.append(callback)

    def remove(self, callback: Callable[[], None]) -> None:
        if callback in self._hooks:
            self._hooks.remove(callback)

    def count(self) -> int:
        return len(self._hooks)

    def __call__(self) -> None:
        for hook in self._hooks:
            try:
                hook()
            except Exception:
                # if the hook fails, remove it
                self._hooks.remove(hook)
                raise



sync_will_start = _SyncWillStartHook()
class _TagEditorDidProcessKeyHook:
    _hooks: list[Callable[["TagEdit", "QEvent"], None]] = []

    
    def append(self, callback: Callable[["TagEdit", "QEvent"], None]) -> None:
        '''(tag_edit: TagEdit, evt: QEvent)'''
        self._hooks.append(callback)

    def remove(self, callback: Callable[["TagEdit", "QEvent"], None]) -> None:
        if callback in self._hooks:
            self._hooks.remove(callback)

    def count(self) -> int:
        return len(self._hooks)

    def __call__(self, tag_edit: TagEdit, evt: QEvent) -> None:
        for hook in self._hooks:
            try:
                hook(tag_edit, evt)
            except Exception:
                # if the hook fails, remove it
                self._hooks.remove(hook)
                raise



tag_editor_did_process_key = _TagEditorDidProcessKeyHook()
class _ThemeDidChangeHook:
    '''Called after night mode is toggled.'''
    _hooks: list[Callable[[], None]] = []

    
    def append(self, callback: Callable[[], None]) -> None:
        '''()'''
        self._hooks.append(callback)

    def remove(self, callback: Callable[[], None]) -> None:
        if callback in self._hooks:
            self._hooks.remove(callback)

    def count(self) -> int:
        return len(self._hooks)

    def __call__(self) -> None:
        for hook in self._hooks:
            try:
                hook()
            except Exception:
                # if the hook fails, remove it
                self._hooks.remove(hook)
                raise



theme_did_change = _ThemeDidChangeHook()
class _TopToolbarDidInitLinksHook:
    '''Used to modify or add links in the top toolbar of Anki's main window

        'links' is a list of HTML link elements. Add-ons can generate their own links
        by using aqt.toolbar.Toolbar.create_link. Links created in that way can then be
        appended to the link list, e.g.:

            def on_top_toolbar_did_init_links(links, toolbar):
                my_link = toolbar.create_link(...)
                links.append(my_link)
        '''
    _hooks: list[Callable[["list[str]", "aqt.toolbar.Toolbar"], None]] = []

    
    def append(self, callback: Callable[["list[str]", "aqt.toolbar.Toolbar"], None]) -> None:
        '''(links: list[str], top_toolbar: aqt.toolbar.Toolbar)'''
        self._hooks.append(callback)

    def remove(self, callback: Callable[["list[str]", "aqt.toolbar.Toolbar"], None]) -> None:
        if callback in self._hooks:
            self._hooks.remove(callback)

    def count(self) -> int:
        return len(self._hooks)

    def __call__(self, links: list[str], top_toolbar: aqt.toolbar.Toolbar) -> None:
        for hook in self._hooks:
            try:
                hook(links, top_toolbar)
            except Exception:
                # if the hook fails, remove it
                self._hooks.remove(hook)
                raise



top_toolbar_did_init_links = _TopToolbarDidInitLinksHook()
class _TopToolbarDidRedrawHook:
    '''Executed when the top toolbar is redrawn'''
    _hooks: list[Callable[["aqt.toolbar.Toolbar"], None]] = []

    
    def append(self, callback: Callable[["aqt.toolbar.Toolbar"], None]) -> None:
        '''(top_toolbar: aqt.toolbar.Toolbar)'''
        self._hooks.append(callback)

    def remove(self, callback: Callable[["aqt.toolbar.Toolbar"], None]) -> None:
        if callback in self._hooks:
            self._hooks.remove(callback)

    def count(self) -> int:
        return len(self._hooks)

    def __call__(self, top_toolbar: aqt.toolbar.Toolbar) -> None:
        for hook in self._hooks:
            try:
                hook(top_toolbar)
            except Exception:
                # if the hook fails, remove it
                self._hooks.remove(hook)
                raise



top_toolbar_did_redraw = _TopToolbarDidRedrawHook()
class _TopToolbarWillSetLeftTrayContentHook:
    '''Used to add custom add-on components to the *left* area of Anki's main
        window toolbar

        'content' is a list of HTML strings added by add-ons which you can append your
        own components or elements to. To equip your components with logic and styling
        please see `webview_will_set_content` and `webview_did_receive_js_message`.

        Please note that Anki's main screen is due to undergo a significant refactor
        in the future and, as a result, add-ons subscribing to this hook will likely
        require changes to continue working.
        '''
    _hooks: list[Callable[["list[str]", "aqt.toolbar.Toolbar"], None]] = []

    
    def append(self, callback: Callable[["list[str]", "aqt.toolbar.Toolbar"], None]) -> None:
        '''(content: list[str], top_toolbar: aqt.toolbar.Toolbar)'''
        self._hooks.append(callback)

    def remove(self, callback: Callable[["list[str]", "aqt.toolbar.Toolbar"], None]) -> None:
        if callback in self._hooks:
            self._hooks.remove(callback)

    def count(self) -> int:
        return len(self._hooks)

    def __call__(self, content: list[str], top_toolbar: aqt.toolbar.Toolbar) -> None:
        for hook in self._hooks:
            try:
                hook(content, top_toolbar)
            except Exception:
                # if the hook fails, remove it
                self._hooks.remove(hook)
                raise



top_toolbar_will_set_left_tray_content = _TopToolbarWillSetLeftTrayContentHook()
class _TopToolbarWillSetRightTrayContentHook:
    '''Used to add custom add-on components to the *right* area of Anki's main
        window toolbar

        'content' is a list of HTML strings added by add-ons which you can append your
        own components or elements to. To equip your components with logic and styling
        please see `webview_will_set_content` and `webview_did_receive_js_message`.

        Please note that Anki's main screen is due to undergo a significant refactor
        in the future and, as a result, add-ons subscribing to this hook will likely
        require changes to continue working.
        '''
    _hooks: list[Callable[["list[str]", "aqt.toolbar.Toolbar"], None]] = []

    
    def append(self, callback: Callable[["list[str]", "aqt.toolbar.Toolbar"], None]) -> None:
        '''(content: list[str], top_toolbar: aqt.toolbar.Toolbar)'''
        self._hooks.append(callback)

    def remove(self, callback: Callable[["list[str]", "aqt.toolbar.Toolbar"], None]) -> None:
        if callback in self._hooks:
            self._hooks.remove(callback)

    def count(self) -> int:
        return len(self._hooks)

    def __call__(self, content: list[str], top_toolbar: aqt.toolbar.Toolbar) -> None:
        for hook in self._hooks:
            try:
                hook(content, top_toolbar)
            except Exception:
                # if the hook fails, remove it
                self._hooks.remove(hook)
                raise



top_toolbar_will_set_right_tray_content = _TopToolbarWillSetRightTrayContentHook()
class _UndoStateDidChangeHook:
    _hooks: list[Callable[["UndoActionsInfo"], None]] = []

    
    def append(self, callback: Callable[["UndoActionsInfo"], None]) -> None:
        '''(info: UndoActionsInfo)'''
        self._hooks.append(callback)

    def remove(self, callback: Callable[["UndoActionsInfo"], None]) -> None:
        if callback in self._hooks:
            self._hooks.remove(callback)

    def count(self) -> int:
        return len(self._hooks)

    def __call__(self, info: UndoActionsInfo) -> None:
        for hook in self._hooks:
            try:
                hook(info)
            except Exception:
                # if the hook fails, remove it
                self._hooks.remove(hook)
                raise



undo_state_did_change = _UndoStateDidChangeHook()
class _WebviewDidInjectStyleIntoPageHook:
    '''Called after standard styling is injected into an external
        html file, such as when loading the new graphs. You can use this hook to
        mutate the DOM before the page is revealed.
        
        For example:
        
        def mytest(webview: AnkiWebView):
            if webview.kind != AnkiWebViewKind.DECK_STATS:
                return
            webview.eval(
                """
                div = document.createElement("div");
                div.innerHTML = 'hello';
                document.body.appendChild(div);
                """
            )
        
        gui_hooks.webview_did_inject_style_into_page.append(mytest)
        '''
    _hooks: list[Callable[["aqt.webview.AnkiWebView"], None]] = []

    
    def append(self, callback: Callable[["aqt.webview.AnkiWebView"], None]) -> None:
        '''(webview: aqt.webview.AnkiWebView)'''
        self._hooks.append(callback)

    def remove(self, callback: Callable[["aqt.webview.AnkiWebView"], None]) -> None:
        if callback in self._hooks:
            self._hooks.remove(callback)

    def count(self) -> int:
        return len(self._hooks)

    def __call__(self, webview: aqt.webview.AnkiWebView) -> None:
        for hook in self._hooks:
            try:
                hook(webview)
            except Exception:
                # if the hook fails, remove it
                self._hooks.remove(hook)
                raise



webview_did_inject_style_into_page = _WebviewDidInjectStyleIntoPageHook()
class _WebviewDidReceiveJsMessageFilter:
    '''Used to handle pycmd() messages sent from Javascript.

        Message is the string passed to pycmd().

        For messages you don't want to handle, return 'handled' unchanged.

        If you handle a message and don't want it passed to the original
        bridge command handler, return (True, None).

        If you want to pass a value to pycmd's result callback, you can
        return it with (True, some_value).

        Context is the instance that was passed to set_bridge_command().
        It can be inspected to check which screen this hook is firing
        in, and to get a reference to the screen. For example, if your
        code wishes to function only in the review screen, you could do:

            if not isinstance(context, aqt.reviewer.Reviewer):
                # not reviewer, pass on message
                return handled

            if message == "my-mark-action":
                # our message, call onMark() on the reviewer instance
                context.onMark()
                # and don't pass message to other handlers
                return (True, None)
            else:
                # some other command, pass it on
                return handled
        '''
    _hooks: list[Callable[["tuple[bool, Any]", "str", "Any"], tuple[bool, Any]]] = []

    
    def append(self, callback: Callable[["tuple[bool, Any]", "str", "Any"], tuple[bool, Any]]) -> None:
        '''(handled: tuple[bool, Any], message: str, context: Any)'''
        self._hooks.append(callback)

    def remove(self, callback: Callable[["tuple[bool, Any]", "str", "Any"], tuple[bool, Any]]) -> None:
        if callback in self._hooks:
            self._hooks.remove(callback)

    def count(self) -> int:
        return len(self._hooks)

    def __call__(self, handled: tuple[bool, Any], message: str, context: Any) -> tuple[bool, Any]:
        for filter in self._hooks:
            try:
                handled = filter(handled, message, context)
            except Exception:
                # if the hook fails, remove it
                self._hooks.remove(filter)
                raise
        return handled



webview_did_receive_js_message = _WebviewDidReceiveJsMessageFilter()
class _WebviewWillSetContentHook:
    '''Used to modify web content before it is rendered.

        Web_content contains the HTML, JS, and CSS the web view will be
        populated with.

        Context is the instance that was passed to stdHtml().
        It can be inspected to check which screen this hook is firing
        in, and to get a reference to the screen. For example, if your
        code wishes to function only in the review screen, you could do:

            def on_webview_will_set_content(web_content: WebContent, context):

                if not isinstance(context, aqt.reviewer.Reviewer):
                    # not reviewer, do not modify content
                    return

                # reviewer, perform changes to content

                context: aqt.reviewer.Reviewer

                addon_package = mw.addonManager.addonFromModule(__name__)

                web_content.css.append(
                    f"/_addons/{addon_package}/web/my-addon.css")
                web_content.js.append(
                    f"/_addons/{addon_package}/web/my-addon.js")

                web_content.head += "<script>console.log('my-addon')</script>"
                web_content.body += "<div id='my-addon'></div>"
        '''
    _hooks: list[Callable[["aqt.webview.WebContent", "object | None"], None]] = []

    
    def append(self, callback: Callable[["aqt.webview.WebContent", "object | None"], None]) -> None:
        '''(web_content: aqt.webview.WebContent, context: object | None)'''
        self._hooks.append(callback)

    def remove(self, callback: Callable[["aqt.webview.WebContent", "object | None"], None]) -> None:
        if callback in self._hooks:
            self._hooks.remove(callback)

    def count(self) -> int:
        return len(self._hooks)

    def __call__(self, web_content: aqt.webview.WebContent, context: object | None) -> None:
        for hook in self._hooks:
            try:
                hook(web_content, context)
            except Exception:
                # if the hook fails, remove it
                self._hooks.remove(hook)
                raise



webview_will_set_content = _WebviewWillSetContentHook()
class _WebviewWillShowContextMenuHook:
    _hooks: list[Callable[["aqt.webview.AnkiWebView", "QMenu"], None]] = []

    
    def append(self, callback: Callable[["aqt.webview.AnkiWebView", "QMenu"], None]) -> None:
        '''(webview: aqt.webview.AnkiWebView, menu: QMenu)'''
        self._hooks.append(callback)

    def remove(self, callback: Callable[["aqt.webview.AnkiWebView", "QMenu"], None]) -> None:
        if callback in self._hooks:
            self._hooks.remove(callback)

    def count(self) -> int:
        return len(self._hooks)

    def __call__(self, webview: aqt.webview.AnkiWebView, menu: QMenu) -> None:
        for hook in self._hooks:
            try:
                hook(webview, menu)
            except Exception:
                # if the hook fails, remove it
                self._hooks.remove(hook)
                raise
        # legacy support
        anki.hooks.runHook("AnkiWebView.contextMenuEvent", webview, menu)



webview_will_show_context_menu = _WebviewWillShowContextMenuHook()

