From bf2e7055dbee89f3620ce9d409bab082a80d66fc Mon Sep 17 00:00:00 2001 From: Nitsud Yarg Date: Mon, 22 Jun 2026 20:17:18 -0700 Subject: [PATCH] poc anki status pull --- anki-connect.py | 103 ++++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 103 insertions(+) create mode 100644 anki-connect.py diff --git a/anki-connect.py b/anki-connect.py new file mode 100644 index 0000000..e22ba96 --- /dev/null +++ b/anki-connect.py @@ -0,0 +1,103 @@ +import json +import requests + +ANKI_URL = "http://127.0.0.1:8765" + +def request_anki(action, params=None): + """Sends a payload to AnkiConnect.""" + payload = {"action": action, "version": 6, "params": params or {}} + response = requests.post(ANKI_URL, json=payload) + response.raise_for_status() + return response.json().get("result") + +def get_card_proficiency(query="deck:current"): + """ + Finds cards by query, retrieves scheduling data, + and prints proficiency stats for each card. + """ + card_ids = request_anki("findCards", {"query": query}) + if not card_ids: + print("No cards found.") + return + + card_info = request_anki("cardsInfo", {"cards": card_ids}) + + card_proficiency = {} + + for card in card_info: + card_id = card["cardId"] + # In Anki: 0=new, 1=learning, 2=review, 3=relearning + queue_state = card["queue"] + interval = card["interval"] + reps = card["reps"] + lapses = card["lapses"] + + # Anki queue mappings: + # 0 = New, 1 = Learning, 2 = Review, 3 = Relearning + if queue_state == 0: + status = "New" + color = '' + elif queue_state == 1: + status = "Learning" + color = 'orangered' + elif queue_state == 3: + status = "Relearning" + color = 'yellow' + elif queue_state == 2: + # Review card split by 21-day threshold + if interval >= 21: + status = "Mature" + color = 'cyan' + else: + status = "Young" + color = 'lime' + elif queue_state < 0: + status = "Suspended" + color = '' + else: + status = f"Unknown (Queue {queue})" + color = '' + + word = '' + if (card['fields'].get('Word')): + print(card['fields']['Word']) + word = card['fields']['Word']['value'] + else: + #print(card['fields']) + continue + + if (card_proficiency.get(word)): + print("Multiple matches for word") + else: + card_proficiency[word] = {'Status' : status,'State' : status, 'Color' : color} + + print(f"Card ID {card_id} (State: {queue_state}):") + print(f" Reps: {reps} | Lapses: {lapses} | Interval: {interval} days | Ease: {status} \n") + + return card_proficiency + +# Example usage: Evaluate proficiency for all cards in a specific deck +# get_card_proficiency(query='deck:"Your Deck Name Here"') +proficiency_stats = get_card_proficiency(query='deck:"Japanese Vocab" card:0') +if proficiency_stats.get('休み'): + proficiency_stats['休み']['Status'] + +#Anki determines a card's maturity, learning, or relearning state based on its queue type and interval value. +# Mature: Review card with an interval of 21 days or more. +# Young: Review card with an interval of less than 21 days. +# Relearning: Card currently failing review, placed back into a learning queue. +""" + # Anki queue mappings: + # 0 = New, 1 = Learning, 2 = Review, 3 = Relearning + if queue == 0: + status = "New" + elif queue == 1: + status = "Learning" + elif queue == 3: + status = "Relearning" + elif queue == 2: + # Review card split by 21-day threshold + status = "Mature (Review)" if ivl >= 21 else "Young (Review)" + else: + status = f"Unknown (Queue {queue})" +"""