Closed pierreg14 closed 1 year ago
A friend who knows py told me that my python doesn't support "list" or something like that. I fixed my issue with this! Hope it will help
LingqApi.py
from typing import List
import requests
from .Models.Lingq import Lingq
class LingqApi:
def __init__(self, apiKey, languageCode):
self.apiKey = apiKey
self.languageCode = languageCode
self._baseUrl = f"https://www.lingq.com/api/v2/{languageCode}/cards"
self.unformatedLingqs = []
self.lingqs = []
def GetAllLingqs(self) -> List[Lingq]:
nextUrl = self._baseUrl
while (nextUrl != None):
words_response = self._GetSinglePage(nextUrl)
words = words_response.json()['results']
self.unformatedLingqs.extend(words)
nextUrl = words_response.json()['next']
self._ConvertApiToLingqs()
return self.lingqs
def _GetSinglePage(self, url):
headers = {'Authorization': f'Token {self.apiKey}'}
words_response = requests.get(url, headers=headers)
words_response.raise_for_status()
return words_response
def _ConvertApiToLingqs(self) -> List[Lingq]:
for lingq in self.unformatedLingqs:
self.lingqs.append(
Lingq(
lingq['pk'],
lingq['term'],
lingq['hints'][0]['text']
if (len(lingq['hints']) > 0)
else " ",
lingq['status'],
lingq['extended_status']
))
def SyncStatusesToLingq(self, lingqs: List[Lingq]) -> int:
lingqsUpdated = 0
for lingq in lingqs:
lingq = self._GetLingqStatusReadyForSync(lingq)
if (self._ShouldUpdateStatus(lingq.primaryKey, lingq.status) == False): continue
headers = {"Authorization": f"Token {self.apiKey}"}
url = f"{self._baseUrl}/{lingq.primaryKey}/"
response = requests.patch(url, headers=headers, data={
"status": lingq.status, "extended_status": lingq.extended_status})
response.raise_for_status()
lingqsUpdated += 1
return lingqsUpdated
def _GetLingqStatus(self, lingqPrimaryKey):
url = f"{self._baseUrl}/{lingqPrimaryKey}/"
response = self._GetSinglePage(url)
status = response.json()['status']
extendedStatus = response.json()['extended_status']
if (extendedStatus == 3 and status == 3):
status = 4
return status
def _GetLingqStatusReadyForSync(self, lingq: Lingq):
if (lingq.status == 4):
lingq.extended_status = 3
lingq.status = 3
else:
lingq.extended_status = 0
return lingq
def _ShouldUpdateStatus(self, lingqPrimaryKey, newStatus) -> bool:
lingqCurrentStatus = self._GetLingqStatus(lingqPrimaryKey)
return int(lingqCurrentStatus) < int(newStatus)
AnkiHandler.py
from typing import List
from aqt import mw
from anki.notes import Note
from anki.cards import Card
from .Models.AnkiCard import AnkiCard
def CreateNotesFromCards(cards: List[AnkiCard], deckName: str) -> int:
return sum(CreateNote(card, deckName) == True for card in cards)
def CreateNote(card: AnkiCard, deckName: str) -> bool:
if (DoesDuplicateCardExistInDeck(card.primaryKey , deckName)):
return False
modelName = "LingqAnkiSync"
noteFields = ["Front", "Back", "LingqPK"]
CreateNoteTypeIfNotExist(modelName, noteFields, deckName)
model = mw.col.models.byName(modelName)
note = Note(mw.col, model)
note["Front"] = card.word
note["Back"] = card.translation
note["LingqPK"] = str(card.primaryKey)
deck_id = mw.col.decks.id(deckName)
note.model()['did'] = deck_id
mw.col.addNote(note)
mw.col.sched.set_due_date([note.id], str(card.interval))
return True
def DoesDuplicateCardExistInDeck(LingqPK, deckName):
return len(mw.col.find_cards(f'deck:"{deckName}" LingqPK:"{LingqPK}"')) > 0
def CreateNoteType(name: str, fields: List):
model = mw.col.models.new(name)
for field in fields:
mw.col.models.addField(model, mw.col.models.newField(field))
template = mw.col.models.newTemplate("lingqAnkiSyncTemplate")
template['qfmt'] = "{{Front}}"
template['afmt'] = "{{FrontSide}}<hr id=answer>{{Back}}"
mw.col.models.addTemplate(model, template)
mw.col.models.add(model)
mw.col.models.setCurrent(model)
mw.col.models.save(model)
return model
def CreateNoteTypeIfNotExist(noteTypeName: str, noteFields: List, deckName: str):
if not mw.col.models.byName(noteTypeName):
CreateNoteType(noteTypeName, noteFields)
def GetAllCardsInDeck(deckName: str) -> List[AnkiCard]:
cards = []
cardIds = mw.col.find_cards(f'deck:"{deckName}"')
for cardId in cardIds:
card = mw.col.get_card(cardId)
card = _CreateAnkiCardObject(card, cardId)
cards.append(card)
return cards
def GetAllDeckNames() -> List[str]:
return mw.col.decks.all_names()
def GetIntervalFromCard(cardId) -> int:
interval = mw.col.db.scalar("select ivl from cards where id = ?", cardId)
return 0 if interval is None else interval
def _CreateAnkiCardObject(card, cardId) -> AnkiCard:
return AnkiCard(
card.note()["LingqPK"],
card.note()["Front"],
card.note()["Back"],
GetIntervalFromCard(cardId)
)
Converter.py
import sys, os
sys.path.append(os.path.realpath(f"./{os.path.dirname(__file__)}"))
from typing import List, Dict
from Models.Lingq import Lingq
from Models.AnkiCard import AnkiCard
def ConvertAnkiCardsToLingqs(ankiCards: List[AnkiCard], statusToInterval: Dict[int,int]) -> List[Lingq]:
lingqs = []
for card in ankiCards:
lingqs.append(
Lingq(
card.primaryKey,
card.word,
card.translation,
_ConvertAnkiIntervalToLingqStatus(card.interval, statusToInterval),
None
))
return lingqs
def ConvertLingqsToAnkiCards(lingqs: List[Lingq], statusToInterval: Dict[int,int]) -> List[AnkiCard]:
ankiCards = []
for lingq in lingqs:
ankiCards.append(
AnkiCard(
lingq.primaryKey,
lingq.word,
lingq.translation,
_ConvertLingqStatusToAnkiInterval(lingq.status, statusToInterval)
))
return ankiCards
def _ConvertLingqStatusToAnkiInterval(status: int, statusToInterval: Dict[int,int]) -> str:
for lingqStatus, ankiInterval in statusToInterval.items():
if status <= lingqStatus:
return ankiInterval
return max(statusToInterval.values())
def _ConvertAnkiIntervalToLingqStatus(interval: int, statusToInterval: Dict[int,int]) -> int:
for lingqStatus, ankiInterval in statusToInterval.items():
if interval <= ankiInterval:
return lingqStatus
return max(statusToInterval.keys())
Thanks for sending this in. I'll add this in to the code as long as it doesn't cause any issues on the windows side. I don't have a mac to test with.
Hi, when I try to install the addon and I restart it, it shows me this message :
"Traceback (most recent call last): File "aqt/addons.py", line 230, in loadAddons File "/Users/pierreg/Library/Application Support/Anki2/addons21/594879777/init.py", line 1, in
from .popUpWindow import UI
File "/Users/pierreg/Library/Application Support/Anki2/addons21/594879777/popUpWindow.py", line 6, in
from .UIActionHandler import ActionHandler
File "/Users/pierreg/Library/Application Support/Anki2/addons21/594879777/UIActionHandler.py", line 1, in
from .Converter import ConvertAnkiCardsToLingqs, ConvertLingqsToAnkiCards
File "/Users/pierreg/Library/Application Support/Anki2/addons21/594879777/Converter.py", line 7, in
def ConvertAnkiCardsToLingqs(ankiCards: list[AnkiCard], statusToInterval: dict[int:int]) -> list[Lingq]:
TypeError: 'type' object is not subscriptable"
mac OS Big sur 11.7.4 Anki version : 2.1.49 Python 3.8.6 Qt 5.14.2 PyQt 5.14.2
On the anki addon link --> Supported Anki versions: 2.1.6-2.1.16+ (Updated 2023-03-20)
Thanks.