A => .flake8 +6 -0
@@ 1,6 @@
+# They dropped support for XDG config files in 2021, so this file has to be symlinked to
+# project/.flake8 https://github.com/pycqa/flake8/pull/1404
+
+[flake8]
+max-line-length = 88
+extend-ignore = E203
A => .gitignore +3 -0
@@ 1,3 @@
+__pycache__/
+meta.json
+.mypy_cache/
A => LICENSE +24 -0
@@ 1,24 @@
+This is free and unencumbered software released into the public domain.
+
+Anyone is free to copy, modify, publish, use, compile, sell, or
+distribute this software, either in source code form or as a compiled
+binary, for any purpose, commercial or non-commercial, and by any
+means.
+
+In jurisdictions that recognize copyright laws, the author or authors
+of this software dedicate any and all copyright interest in the
+software to the public domain. We make this dedication for the benefit
+of the public at large and to the detriment of our heirs and
+successors. We intend this dedication to be an overt act of
+relinquishment in perpetuity of all present and future rights to this
+software under copyright law.
+
+THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
+MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
+IN NO EVENT SHALL THE AUTHORS BE LIABLE FOR ANY CLAIM, DAMAGES OR
+OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE,
+ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
+OTHER DEALINGS IN THE SOFTWARE.
+
+For more information, please refer to <https://unlicense.org>
A => README.md +18 -0
@@ 1,18 @@
+# Anki add note id
+
+Simple plugin to add note id(s) to a chosen field on all selected cards.
+
+For some reason all variants of this plugin that I have found online try to have some
+clever logic that automatically fills in the note id for an appropriately named field
+upon creation or modification, or some such behaviour. This plugin is really simple and
+literally just puts the value from the database into the field you choose on the card
+when you click the button, and does nothing else.
+
+
+
+
+
+
+
+
+
A => __init__.py +92 -0
@@ 1,92 @@
+from typing import Sequence
+
+from anki.notes import NoteId, NotetypeDict
+from aqt import Collection, gui_hooks
+from aqt.browser import Browser
+from aqt.operations import CollectionOp, OpChanges
+from aqt.qt import QDialog # type: ignore
+from aqt.qt import QPushButton # type: ignore
+from aqt.qt import QButtonGroup, QLabel, QRadioButton, QVBoxLayout, QWidget
+from aqt.utils import showWarning, tooltip
+
+
+# Mostly copied from here:
+# https://github.com/realmayus/anki_forvo_dl/blob/main/src/FieldSelector.py
+class FieldSelector(QDialog):
+ def __init__(self, parent: QWidget, note_type: NotetypeDict, prompt: str) -> None:
+ super().__init__(parent)
+
+ self.layout = QVBoxLayout()
+ self.setLayout(self.layout)
+
+ self.setWindowTitle(prompt)
+ self.layout.addWidget(QLabel(f"<h1>{prompt}</h1>"))
+
+ self.button_group = QButtonGroup()
+
+ for idx, field in enumerate(note_type["flds"]):
+ radio = QRadioButton(field["name"])
+ radio.field = field["name"]
+ self.button_group.addButton(radio)
+ self.layout.addWidget(radio)
+
+ self.button_group.buttonClicked.connect(self.handle_selection_change)
+ self.sel_fld = "" # Default value used if user kills dialog without selection
+
+ self.next_btn = QPushButton("Continue")
+ self.next_btn.clicked.connect(self.close)
+ self.next_btn.setEnabled(False)
+
+ self.layout.addWidget(self.next_btn)
+
+ def handle_selection_change(self) -> None:
+ sel = self.button_group.checkedButton()
+ self.sel_fld = sel.field if sel is not None else ""
+ self.next_btn.setEnabled(sel is not None)
+
+
+def add_nids(browser: Browser) -> None:
+ nids: Sequence[NoteId] = browser.selected_notes()
+ notes = [browser.mw.col.get_note(nid) for nid in nids]
+
+ if len(notes) == 0:
+ showWarning("No notes selected.", parent=browser)
+ return
+
+ note_type = notes[0].note_type()
+ assert note_type # Make mypy shut up
+
+ field_selector = FieldSelector(browser, note_type, "Select nid field")
+ field_selector.exec()
+ nid_field = field_selector.sel_fld
+
+ if nid_field == "":
+ tooltip("No field selected, cannot add nid(s)", parent=browser)
+ return
+
+ for note in notes:
+ if nid_field not in note.keys():
+ showWarning(
+ "Note %d is missing field %s, cannot add nids" % (note.id, nid_field),
+ parent=browser,
+ )
+ return
+
+ def execute(col: Collection) -> OpChanges:
+ undo_entry = col.add_custom_undo_entry("Add nid(s)")
+ for note in notes:
+ note[nid_field] = str(note.id)
+ col.update_notes(notes)
+ return col.merge_undo_entries(undo_entry)
+
+ CollectionOp(browser, lambda col: execute(col)).success(
+ lambda _: tooltip("Added nids to %s card(s)" % len(nids))
+ ).run_in_background()
+
+
+def add_menu_opt(browser: Browser) -> None:
+ action = browser.form.menu_Notes.addAction("Add note id(s)")
+ action.triggered.connect(lambda: add_nids(browser))
+
+
+gui_hooks.browser_menus_did_init.append(add_menu_opt)
A => img/dialog.png +0 -0
A => +0 -0
A => img/result.png +0 -0