MW integration
This commit is contained in:
144
lib/words.py
Normal file
144
lib/words.py
Normal file
@@ -0,0 +1,144 @@
|
||||
import json
|
||||
import requests
|
||||
|
||||
from PyQt6.QtSql import QSqlQuery
|
||||
from typing import Type, Self, Dict, Any, Optional
|
||||
|
||||
from lib import query_error
|
||||
|
||||
API = "https://api.dictionaryapi.dev/api/v2/entries/en/{word}"
|
||||
MWAPI = "https://www.dictionaryapi.com/api/v3/references/collegiate/json/{word}?key=51d9df34-ee13-489e-8656-478c215e846c"
|
||||
|
||||
class Word:
|
||||
_instance = None
|
||||
_words: Dict[str,str] = {}
|
||||
_current: Optional[Dict[str,Any]] = None
|
||||
|
||||
def __new__(cls: Type[Self], word:str ) -> Self:
|
||||
if cls._instance:
|
||||
return cls._instance
|
||||
cls._instance = super(Word, cls).__new__(cls)
|
||||
return cls._instance
|
||||
|
||||
def __init__(self, word: str) -> None:
|
||||
print(f"Word == {word}")
|
||||
#
|
||||
# Have we already retrieved this word?
|
||||
#
|
||||
try:
|
||||
self._current = json.loads(self._words[word])
|
||||
return
|
||||
except KeyError:
|
||||
pass
|
||||
query = QSqlQuery()
|
||||
query.prepare("SELECT * FROM words "
|
||||
"WHERE word = :word")
|
||||
query.bindValue(":word", word)
|
||||
if not query.exec():
|
||||
query_error(query)
|
||||
if query.next():
|
||||
self._words[word] = query.value("definition")
|
||||
self._current = json.loads(self._words[word])
|
||||
return
|
||||
response = requests.get(MWAPI.format(word=word))
|
||||
if response.status_code != 200:
|
||||
self._current = None
|
||||
return
|
||||
data = json.loads(response.content.decode("utf-8"))
|
||||
#
|
||||
# XXX - The first entry should be the correct entry. There could be more
|
||||
# if there is a "hom" entry, then that will be appended to meta.id
|
||||
# word = "lady", hom=1, meta.id = "lady:1";
|
||||
#
|
||||
print(response.content.decode('utf-8'))
|
||||
self._words[word] = json.dumps(data[0])
|
||||
self._current = data[0]
|
||||
query.prepare("INSERT INTO words "
|
||||
"(word, definition) "
|
||||
"VALUES (:word, :definition)")
|
||||
query.bindValue(":word", word)
|
||||
query.bindValue(":definition", self._words[word])
|
||||
if not query.exec():
|
||||
query_error(query)
|
||||
return
|
||||
def get_html(self) -> str|None:
|
||||
if not self._current:
|
||||
return None
|
||||
if "meta" in self._current.keys():
|
||||
return self.mw_html()
|
||||
else:
|
||||
return self.apidictionary_html()
|
||||
|
||||
def mw_html(self) -> str:
|
||||
|
||||
def sound_url(prs:Dict[str,Any]) -> str|None:
|
||||
base = 'https://media.merriam-webster.com/audio/prons/en/us/ogg'
|
||||
if 'sound' not in prs.keys():
|
||||
return None
|
||||
audio = prs['sound']['audio']
|
||||
if audio.startswith('bix'):
|
||||
url = base + '/bix/'
|
||||
elif audio.startswith('gg'):
|
||||
url = base + '/gg/'
|
||||
elif audio[0] not in "abcdefghijklmnopqrstuvwxyz":
|
||||
url = base + '/number/'
|
||||
else:
|
||||
url = base + '/' + audio[0] + '/'
|
||||
url += audio + '.ogg'
|
||||
return url
|
||||
|
||||
def parse_sn(sn:str, old:str) -> str:
|
||||
return sn
|
||||
|
||||
assert self._current is not None
|
||||
word = self._current['hwi']['hw']
|
||||
label = self._current['fl']
|
||||
html = f"<h1 class=\"def-word\">{word} <span class=\"def-label\">{label}</span></h1>\n"
|
||||
if "vrs" in self._current.keys():
|
||||
html += "<ol class=\"def-vars\'>\n"
|
||||
html += "<li>"
|
||||
html += "</li>\n<li>".join([vrs['va'] for vrs in self._current['vrs']])
|
||||
html += "</li>\n</ol>\n"
|
||||
if 'prs' in self._current['hwi'].keys():
|
||||
tmp = []
|
||||
for prs in self._current['hwi']['prs']:
|
||||
url = sound_url(prs)
|
||||
how = prs['mw']
|
||||
if url:
|
||||
tmp.append(f'<a href="{url}">\\{how}\\</a>')
|
||||
else:
|
||||
tmp.append(f'\\{how}\\')
|
||||
html += '<span class="def-phonetic">'
|
||||
html += '</span><span="def-phonetic">'.join(tmp)
|
||||
html += "</span>\n"
|
||||
if 'ins' in self._current.keys():
|
||||
html += "<h2 class=\"def-word\">"
|
||||
html += ', '.join([ins['if'] for ins in self._current['ins']])
|
||||
html += "</h2>\n"
|
||||
html += "<ul class='def-outer'>\n"
|
||||
for meaning in self._current['def']:
|
||||
html += f"<li>{meaning['vd']}\n"
|
||||
html += "<ul class=\"def-inner\">\n"
|
||||
label = ''
|
||||
for sseq in meaning['sseq']:
|
||||
for sense in sseq:
|
||||
label = parse_sn(sense[1]['sn'], label)
|
||||
sls = ''
|
||||
if 'sls' in sense[1].keys():
|
||||
sls = ', '.join(sense[1]['sls'])
|
||||
sls = f"<span class=\"def-sls\">{sls}</span> "
|
||||
for dt in sense[1]['dt']:
|
||||
if dt[0] == 'text':
|
||||
html += f"<li class=\"def-text\"><span class=\"def-sn\">{label}</span>{sls}{dt[1]}</li>\n"
|
||||
elif dt[0] == 'vis':
|
||||
for vis in dt[1]:
|
||||
html += f"<li class=\"def-vis\">{vis['t']}</li>\n"
|
||||
else:
|
||||
print(f"Do something with {dt[0]}")
|
||||
html += "</ul>\n"
|
||||
html += "</ul>\n"
|
||||
return html
|
||||
|
||||
def apidictionary_html(self) ->str:
|
||||
html = ""
|
||||
return html
|
||||
Reference in New Issue
Block a user