145 lines
5.3 KiB
Python
145 lines
5.3 KiB
Python
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
|