anki-russian-stressmark

Anki addon to replace the selected Russian word with a version with stress marks.
git clone git://git.alex.balgavy.eu/anki-russian-stressmark.git
Log | Files | Refs

commit c6c92dcee24f8373397ec3cb9f1622eea414dffc
Author: Alex Balgavy <alex@balgavy.eu>
Date:   Thu,  8 Jul 2021 16:57:29 +0200

Initial commit

Diffstat:
A.gitignore | 172+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
AMakefile | 5+++++
A__init__.py | 1+
Aicons/add.png | 0
Amanifest.json | 4++++
Arelease/russian-stressmark.ankiaddon | 0
Arussiangram_parser.py | 23+++++++++++++++++++++++
Arussiangram_requests.py | 21+++++++++++++++++++++
Asetup_ui.py | 20++++++++++++++++++++
9 files changed, 246 insertions(+), 0 deletions(-)

diff --git a/.gitignore b/.gitignore @@ -0,0 +1,172 @@ +# Created by https://www.toptal.com/developers/gitignore/api/macos,python +# Edit at https://www.toptal.com/developers/gitignore?templates=macos,python + +### macOS ### +# General +.DS_Store +.AppleDouble +.LSOverride + +# Icon must end with two \r +Icon + +# Thumbnails +._* + +# Files that might appear in the root of a volume +.DocumentRevisions-V100 +.fseventsd +.Spotlight-V100 +.TemporaryItems +.Trashes +.VolumeIcon.icns +.com.apple.timemachine.donotpresent + +# Directories potentially created on remote AFP share +.AppleDB +.AppleDesktop +Network Trash Folder +Temporary Items +.apdisk + +### Python ### +# Byte-compiled / optimized / DLL files +__pycache__/ +*.py[cod] +*$py.class + +# C extensions +*.so + +# Distribution / packaging +.Python +build/ +develop-eggs/ +dist/ +downloads/ +eggs/ +.eggs/ +lib/ +lib64/ +parts/ +sdist/ +var/ +wheels/ +share/python-wheels/ +*.egg-info/ +.installed.cfg +*.egg +MANIFEST + +# PyInstaller +# Usually these files are written by a python script from a template +# before PyInstaller builds the exe, so as to inject date/other infos into it. +*.manifest +*.spec + +# Installer logs +pip-log.txt +pip-delete-this-directory.txt + +# Unit test / coverage reports +htmlcov/ +.tox/ +.nox/ +.coverage +.coverage.* +.cache +nosetests.xml +coverage.xml +*.cover +*.py,cover +.hypothesis/ +.pytest_cache/ +cover/ + +# Translations +*.mo +*.pot + +# Django stuff: +*.log +local_settings.py +db.sqlite3 +db.sqlite3-journal + +# Flask stuff: +instance/ +.webassets-cache + +# Scrapy stuff: +.scrapy + +# Sphinx documentation +docs/_build/ + +# PyBuilder +.pybuilder/ +target/ + +# Jupyter Notebook +.ipynb_checkpoints + +# IPython +profile_default/ +ipython_config.py + +# pyenv +# For a library or package, you might want to ignore these files since the code is +# intended to run in multiple environments; otherwise, check them in: +# .python-version + +# pipenv +# According to pypa/pipenv#598, it is recommended to include Pipfile.lock in version control. +# However, in case of collaboration, if having platform-specific dependencies or dependencies +# having no cross-platform support, pipenv may install dependencies that don't work, or not +# install all needed dependencies. +#Pipfile.lock + +# PEP 582; used by e.g. github.com/David-OConnor/pyflow +__pypackages__/ + +# Celery stuff +celerybeat-schedule +celerybeat.pid + +# SageMath parsed files +*.sage.py + +# Environments +.env +.venv +env/ +venv/ +ENV/ +env.bak/ +venv.bak/ + +# Spyder project settings +.spyderproject +.spyproject + +# Rope project settings +.ropeproject + +# mkdocs documentation +/site + +# mypy +.mypy_cache/ +.dmypy.json +dmypy.json + +# Pyre type checker +.pyre/ + +# pytype static type analyzer +.pytype/ + +# Cython debug symbols +cython_debug/ + +# End of https://www.toptal.com/developers/gitignore/api/macos,python diff --git a/Makefile b/Makefile @@ -0,0 +1,5 @@ +release: + -mkdir -p release/ + zip -r release/russian-stressmark.ankiaddon *.py manifest.json icons/ + +.PHONY: release diff --git a/__init__.py b/__init__.py @@ -0,0 +1 @@ +from . import setup_ui diff --git a/icons/add.png b/icons/add.png Binary files differ. diff --git a/manifest.json b/manifest.json @@ -0,0 +1,4 @@ +{ + "package": "russian-stressmark", + "name": "Russian Stress Mark" +} diff --git a/release/russian-stressmark.ankiaddon b/release/russian-stressmark.ankiaddon Binary files differ. diff --git a/russiangram_parser.py b/russiangram_parser.py @@ -0,0 +1,23 @@ +import codecs +from html.parser import HTMLParser + +class RussiangramParser(HTMLParser): + def __init__(self): + self.intextarea = False + self.data = '' + super().__init__() + + def handle_starttag(self, tag, attrs): + attrs = dict(attrs) + if tag == "textarea" and attrs['id'] == "MainContent_UserSentenceTextbox": + self.intextarea = True + + def handle_endtag(self, tag): + if tag == "textarea" and self.intextarea: + self.intextarea = False + + def handle_data(self, data): + if self.intextarea: + bstrings = filter(lambda y: '\\' not in y, data.split('\\x')) + bs = bytes(map(lambda x: int(x, 16), bstrings)) + self.data = bs.decode() diff --git a/russiangram_requests.py b/russiangram_requests.py @@ -0,0 +1,21 @@ +from urllib import request, parse +from .russiangram_parser import RussiangramParser + +def stressmark(s): + data = { '__VIEWSTATE': '/wEPDwUKMTMzOTA3OTU5N2Rk5MNrzf8M72AYC/+c+xWZbzp8Td8=', + '__VIEWSTATEGENERATOR': 'CA0B0334', + '__EVENTTARGET': '', + '__EVENTARGUMENT': '', + '__EVENTVALIDATION': '/wEdAAMDOEAYUxkPEDCURzqp69xETjsDcGH04u5hS3jwIIl38e/d1Dv61Nm9xfklcqY855XV2JJyoBPZpaGFe8T+7UtRw3M4iA==', + 'ctl00$MainContent$UserSentenceTextbox': s, + 'ctl00$MainContent$SubmitButton': 'Annotate'} + + request_url = "https://russiangram.com/" + encoded_data = parse.urlencode(data).encode() + req = request.Request(request_url, data=encoded_data) + resp = request.urlopen(req) + body = resp.read() + + rgparser = RussiangramParser() + rgparser.feed(str(body)) + return rgparser.data diff --git a/setup_ui.py b/setup_ui.py @@ -0,0 +1,20 @@ +from aqt.editor import Editor +from anki.hooks import addHook +import os +import json +from .russiangram_requests import stressmark + +def stressmarkSelection(editor) -> None: + selected = editor.web.selectedText() + if selected: + editor.web.eval(""" document.execCommand("insertHTML", false, %s); """ % json.dumps(stressmark(selected))) + +def addButton(buttons, editor): + tt = "Add Stress Marks" + icon_name = "add.png" + icon = os.path.join(os.path.join(os.path.dirname(__file__), "icons"), icon_name) + b = editor.addButton(icon, "STRESSMARK", stressmarkSelection, tip=_("{}".format(tt))) + buttons.append(b) + return buttons + +addHook('setupEditorButtons', addButton)