Hi everyone,
I’m trying to create an add-on (`field_persistence`) to persist field visibility preferences across notes in Anki Desktop during a single session, resetting when Anki closes. The add-on uses `pycmd` to handle `load_prefs` and `save_prefs` commands, storing preferences in a global variable. However, I’m stuck with an "Invalid add-on manifest" error when installing the add-on via zip, and it doesn’t load when placed in the `addons21` folder.
**Details**:
- **Anki Version**: [Version <U+2068>25.07.5 (7172b2d2)<U+2069> Python 3.13.5 Qt 6.9.1 Chromium 122]
- **OS**: [Windows 11]
- **Add-on Goal**: Persist field visibility (e.g., hide/show `English_Translation`) across notes in a custom note type (Notetype 4) during a session, similar to how `localStorage` works in AnkiDroid.
- **Error**: When installing `field_persistence.zip` via `Tools > Add-ons > Install`, I get: "Error installing field_persistence.zip: Invalid add-on manifest." The add-on doesn’t appear in `Tools > Add-ons` or in the debug console (`import addonmanager; print(addonmanager.get_addons())`).
**Add-on Structure**:
<Anki2/addons21>/
└── field_persistence/
├── init.py
└── meta.json
**`_init_.py`**:
```python
import logging
from anki.hooks import addHook
from aqt import gui_hooks
logging.basicConfig(level=logging.DEBUG)
logger = logging.getLogger(_name_)
logger.debug(“Field Persistence Add-on initialized”)
session_prefs = {}
def on_pycmd(cmd, data, callback):
global session_prefs
logger.debug(f"Received pycmd: {cmd}, data: {data}“)
try:
if cmd == “load_prefs”:
callback(str(session_prefs) if session_prefs else “{}”)
elif cmd == “save_prefs”:
session_prefs = eval(data)
logger.debug(f"Saved preferences: {session_prefs}”)
callback(“Preferences saved”)
else:
logger.debug(f"Unknown pycmd: {cmd}“)
callback(“Unknown command”)
except Exception as e:
logger.error(f"Error in pycmd {cmd}: {str(e)}”)
callback(f"Error: {str(e)}")
addHook(“pycmd”, on_pycmd)
def on_profile_closed():
global session_prefs
session_prefs = {}
logger.debug(“Profile closed, preferences cleared”)
gui_hooks.profile_will_close.append(on_profile_closed)
meta.json:
{
“name”: “Field Persistence”,
“mod”: 0,
“id”: “field_persistence”
}
I hope somebody can clarify this.
BTW it would be great if persistant storage would work by default on ankidesktop.
and as long as that is not possible, perhaps a shared add on on ankiweb would be nice.
I am just starting mostly with help of AI.
Questions:
-
Why am I getting the “Invalid add-on manifest” error? Is there an issue with my meta.json or zip structure?
-
How can I debug why the add-on isn’t loading in addons21? Are there specific logs or debug console commands to try?
-
Is there a way to achieve session-only preference persistence in Anki Desktop without an add-on, e.g., using sessionStorage or cookies in QtWebEngine?
-
Could my Anki version be causing issues with add-on loading or storage persistence?
Template Context: My back card template toggles field visibility (e.g., English_Translation) and tries to save preferences using pycmd or sessionStorage. Here’s the relevant JavaScript:
Questions:
-
Why am I getting the “Invalid add-on manifest” error? Is there an issue with my meta.json or zip structure?
-
How can I debug why the add-on isn’t loading in addons21? Are there specific logs or debug console commands to try?
-
Is there a way to achieve session-only preference persistence in Anki Desktop without an add-on, e.g., using sessionStorage or cookies in QtWebEngine?
-
Could my Anki version be causing issues with add-on loading or storage persistence?
Template Context: My back card template toggles field visibility (e.g., English_Translation) and tries to save preferences using pycmd or sessionStorage. Here’s the relevant JavaScript:
const storage = typeof pycmd !== ‘undefined’ ? sessionStorage : localStorage;
function savePreferences(preferences) {
try {
storage.setItem(‘fieldPreferences’, JSON.stringify(preferences));
console.log(`Saved preferences to ${storage === sessionStorage ? ‘sessionStorage’ : ‘localStorage’}:`, preferences);
} catch (e) {
console.error(`Error saving to ${storage === sessionStorage ? ‘sessionStorage’ : ‘localStorage’}:`, e);
}
}
function loadPreferences() {
const stored = storage.getItem(‘fieldPreferences’);
if (stored) {
try {
const preferences = JSON.parse(stored);
console.log(`Loaded preferences from ${storage === sessionStorage ? ‘sessionStorage’ : ‘localStorage’}:`, preferences);
} catch (e) {
console.error(`Error parsing ${storage === sessionStorage ? ‘sessionStorage’ : ‘localStorage’}:`, e);
}
}
}
Thank you