Checkpoint. Not working
This commit is contained in:
@@ -4,4 +4,5 @@ from .books import Book
|
||||
from .person import PersonDialog
|
||||
from .read import ReadDialog
|
||||
from .session import SessionDialog
|
||||
from .words import Definition, DefinitionArea, Word
|
||||
from .words import DefinitionArea, Word
|
||||
from .definition import Fragment, Line, Definition
|
||||
|
||||
886
lib/words.py
886
lib/words.py
File diff suppressed because it is too large
Load Diff
0
plugins/__init__.py
Normal file
0
plugins/__init__.py
Normal file
253
plugins/merriam-webster.py
Normal file
253
plugins/merriam-webster.py
Normal file
@@ -0,0 +1,253 @@
|
||||
from trycast import trycast
|
||||
import json
|
||||
import re
|
||||
from typing import Any, NamedTuple, TypedDict, cast
|
||||
|
||||
from PyQt6.QtCore import QEventLoop, QUrl, Qt
|
||||
from PyQt6.QtGui import QColor, QFont
|
||||
from PyQt6.QtNetwork import QNetworkRequest
|
||||
from lib.words import Word
|
||||
from lib.definition import Line, Fragment
|
||||
|
||||
registration = {
|
||||
'source': 'mw',
|
||||
'name': 'Merriam-Webster',
|
||||
}
|
||||
|
||||
API = "https://www.dictionaryapi.com/api/v3/references/collegiate/json/{word}?key={key}"
|
||||
key = "51d9df34-ee13-489e-8656-478c215e846c"
|
||||
|
||||
class TextTuple(NamedTuple):
|
||||
type_: str # 'text'
|
||||
text: str
|
||||
class TTuple(NamedTuple):
|
||||
type_: str # 't'
|
||||
text: str
|
||||
class VerbalIllustration(TypedDict):
|
||||
t: str
|
||||
aq: str
|
||||
|
||||
class VerbalIllustrationTuple(NamedTuple):
|
||||
type_: str # 'vis'
|
||||
data: list[VerbalIllustration]
|
||||
|
||||
class Sound(TypedDict):
|
||||
audio: str
|
||||
ref: str
|
||||
stat: str
|
||||
|
||||
class Pronunciation(TypedDict):
|
||||
mw: str
|
||||
l: str
|
||||
l2: str
|
||||
pun: str
|
||||
sound: Sound
|
||||
|
||||
|
||||
|
||||
class Meta(TypedDict):
|
||||
id: str
|
||||
uuid: str
|
||||
sort: str
|
||||
src: str
|
||||
section: str
|
||||
stems: list[str]
|
||||
offensive: bool
|
||||
|
||||
class HeadWordInfo(TypedDict):
|
||||
hw: str
|
||||
prs: list[Pronunciation]
|
||||
|
||||
class HeadWord(TypedDict):
|
||||
hw: str
|
||||
prs: list[Pronunciation]
|
||||
psl: str
|
||||
|
||||
class Variant(TypedDict):
|
||||
va: str
|
||||
vl: str
|
||||
prs: list[Pronunciation]
|
||||
spl: str
|
||||
|
||||
class Inflection(TypedDict):
|
||||
if_: str
|
||||
ifc: str
|
||||
il: str
|
||||
prs: list[Pronunciation]
|
||||
spl: str
|
||||
|
||||
class DividedSense(TypedDict):
|
||||
sd: str
|
||||
et: list[str] # Not full
|
||||
ins: list[Inflection]
|
||||
lbs: list[str]
|
||||
prs: list[Pronunciation]
|
||||
sgram: str
|
||||
sls: list[str]
|
||||
vrs: list[Variant]
|
||||
|
||||
class BioGraphicalNameWrap(TypedDict):
|
||||
pname: str
|
||||
sname: str
|
||||
altname: str
|
||||
prs: list[Pronunciation]
|
||||
|
||||
class CalledAlsoTarget(TypedDict):
|
||||
cat: str
|
||||
catref: str
|
||||
pn: str
|
||||
prs: list[Pronunciation]
|
||||
psl: str
|
||||
|
||||
class CalledAlso(TypedDict):
|
||||
intro: str
|
||||
cats: list[CalledAlsoTarget]
|
||||
|
||||
class RunInWrap(TypedDict):
|
||||
rie: str
|
||||
prs: list[Pronunciation]
|
||||
text: str
|
||||
vrs: list[Variant]
|
||||
|
||||
class Sense:
|
||||
dt: list[str] # not full
|
||||
et: list[str] # not full
|
||||
ins: list[Inflection]
|
||||
lbs: list[str]
|
||||
prs: list[Pronunciation]
|
||||
sdsense: DividedSense
|
||||
sgram: str
|
||||
sls: list[str]
|
||||
sn: str
|
||||
vrs: list[Variant]
|
||||
|
||||
class SenseSequence(TypedDict):
|
||||
sense: Sense
|
||||
sen: Sense
|
||||
|
||||
class Definition(TypedDict):
|
||||
sseq: list[SenseSequence]
|
||||
vd: str
|
||||
|
||||
class Entry(TypedDict):
|
||||
meta: Meta
|
||||
hom: str
|
||||
hwi: HeadWordInfo
|
||||
ahws: list[HeadWord]
|
||||
vrs: list[Variant]
|
||||
fl: str
|
||||
def_: list[Definition]
|
||||
|
||||
def fetch(word:str) -> dict[str, Any]:
|
||||
request = QNetworkRequest()
|
||||
url = QUrl(API.format(word=word, key=key))
|
||||
request.setUrl(url)
|
||||
request.setTransferTimeout(3000)
|
||||
reply = Word._nam.get(request)
|
||||
assert reply is not None
|
||||
loop = QEventLoop()
|
||||
reply.finished.connect(loop.quit)
|
||||
loop.exec()
|
||||
content = reply.readAll()
|
||||
data = json.loads(content.data().decode('utf-8'))
|
||||
return {
|
||||
'word': word,
|
||||
'source': 'mw',
|
||||
'definition': data,
|
||||
}
|
||||
|
||||
def soundUrl(sound:Sound, fmt='ogg') -> QUrl:
|
||||
"""Create a URL from a PRS structure."""
|
||||
base = f"https://media.merriam-webster.com/audio/prons/en/us/{fmt}"
|
||||
audio = sound['audio']
|
||||
m = re.match(r"(bix|gg|[a-zA-Z])", audio)
|
||||
if m:
|
||||
url = base + f"/{m.group(1)}/"
|
||||
else:
|
||||
url = base + "/number/"
|
||||
url += audio + f".{fmt}"
|
||||
return QUrl(url)
|
||||
|
||||
def getFirstSound(definition: list[Entry]) -> QUrl:
|
||||
# ahws, cats, dros, hwi, ins, ri, sdsense, sen, sense, uros, vrs
|
||||
for entry in definition:
|
||||
for v in entry.values():
|
||||
hwi = trycast(HeadWordInfo, v)
|
||||
if hwi is None:
|
||||
continue
|
||||
if 'prs' in hwi:
|
||||
for pr in hwi['prs']:
|
||||
if 'sound' in pr:
|
||||
url = soundUrl(pr['sound'])
|
||||
if url.isValid():
|
||||
return url
|
||||
return QUrl()
|
||||
|
||||
def do_prs(prs: list[Pronunciation]) -> list[Fragment]:
|
||||
frags: list[Fragment] = []
|
||||
font = trycast(QFont, Word._resources['fonts']['label'])
|
||||
assert font is not None
|
||||
linkColor = trycast(QColor, Word._resources['colors']['link'])
|
||||
assert linkColor is not None
|
||||
subduedColor = trycast(QColor, Word._resources['colors']['subdued'])
|
||||
assert subduedColor is not None
|
||||
|
||||
for pr in prs:
|
||||
if 'pun' in pr:
|
||||
pun = pr['pun']
|
||||
else:
|
||||
pun = ' '
|
||||
if 'l' in pr:
|
||||
frags.append(
|
||||
Fragment(pr['l'] + pun, font, color=subduedColor)
|
||||
)
|
||||
frag = Fragment(pr['mw'], font, color=subduedColor)
|
||||
if 'sound' in pr:
|
||||
frag.setAudio(soundUrl(pr['sound']))
|
||||
frags.append(frag)
|
||||
if 'l2' in pr:
|
||||
frags.append(
|
||||
Fragment(pun + pr['l2'], font, color=subduedColor)
|
||||
)
|
||||
return frags
|
||||
|
||||
def getDef(definition: list[Entry]) -> list[Line]:
|
||||
lines = []
|
||||
headerFont = trycast(QFont, Word._resources['fonts']['header'])
|
||||
assert headerFont is not None
|
||||
textFont = trycast(QFont, Word._resources['fonts']['text'])
|
||||
assert textFont is not None
|
||||
labelFont = trycast(QFont, Word._resources['fonts']['label'])
|
||||
assert labelFont is not None
|
||||
|
||||
baseColor = trycast(QColor, Word._resources['colors']['base'])
|
||||
assert baseColor is not None
|
||||
linkColor = trycast(QColor, Word._resources['colors']['link'])
|
||||
assert linkColor is not None
|
||||
subduedColor = trycast(QColor, Word._resources['colors']['subdued'])
|
||||
assert subduedColor is not None
|
||||
entries = len(definition)
|
||||
for count, entry in enumerate(definition):
|
||||
#
|
||||
# Create the First line from the hwi and fl
|
||||
#
|
||||
line = Line()
|
||||
hwi = trycast(HeadWordInfo, entry['hwi'])
|
||||
assert hwi is not None
|
||||
hw = re.sub(r'\*', '', hwi['hw'])
|
||||
line.addFragment(Fragment(hw + ' ', headerFont, color=baseColor))
|
||||
frag = Fragment(f"{count} of {entries} ", textFont, color=linkColor)
|
||||
frag.setBackground(QColor(Qt.GlobalColor.gray))
|
||||
line.addFragment(frag)
|
||||
line.addFragment(Fragment(entry['fl'], labelFont, color=baseColor))
|
||||
lines.append(line)
|
||||
|
||||
#
|
||||
# Next is the pronunciation.
|
||||
#
|
||||
line = Line()
|
||||
hw = re.sub(r'\*', '\u00b7', hwi['hw'])
|
||||
line.addFragment(Fragment(hw + ' ', textFont, color=subduedColor))
|
||||
for frag in do_prs(hwi['prs']):
|
||||
line.addFragment(frag)
|
||||
return [Line()]
|
||||
Reference in New Issue
Block a user