Skip to content

Commit

Permalink
Merge pull request #30 from am-silex/29-add-on-compatibility-with-ank…
Browse files Browse the repository at this point in the history
…i-qt6

Upgrade to Qt6
  • Loading branch information
am-silex authored Feb 11, 2024
2 parents 04519f7 + b07767a commit 8bfb484
Show file tree
Hide file tree
Showing 15 changed files with 347 additions and 375 deletions.
3 changes: 2 additions & 1 deletion .gitattributes
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
###############################################################################
# Set default behavior to automatically normalize line endings.
###############################################################################
* text=auto
* text=auto eol=lf

###############################################################################
# Set default behavior for command prompt diff.
Expand Down Expand Up @@ -43,6 +43,7 @@
#*.jpg binary
#*.png binary
#*.gif binary
*.png binary

###############################################################################
# diff behavior for common document formats
Expand Down
269 changes: 138 additions & 131 deletions Cambridge.py

Large diffs are not rendered by default.

23 changes: 7 additions & 16 deletions README.md
Original file line number Diff line number Diff line change
@@ -1,33 +1,24 @@
![Publish on ankiweb.net](https://github.com/am-silex/anki_cambridge/actions/workflows/main.yml/badge.svg)

Anki Add-on for integration with Cambridge Dictionary web site - https://dictionary.cambridge.org/
Anki Add-on for integration with Cambridge Dictionary website - https://dictionary.cambridge.org/

IMPORTANT: This add-on doesn't use official API - only web-scraping.

What it's done (so far):
### What it's new:
- Upgraded to Qt6
- Creating notes from link to a word (word title, definition, grammar, IPA, sound, meanings, examples)
- Fetching words from your word lists - if you supply cookie for you account and word list IDs
- Fetching words from your word lists (with auto-deletion)
- Config settings management - save cookie, word list IDs
- Native authentication - through Cambridge account

## Auth with native authentication
### Auth with native authentication

- Click on Sign in
- Write your Cambridge email and password
- Click on Log in
- Once you are authenticated, you can close the web window
- The cookie will be stored automatically in the configuration

To do (contributors are welcome):
- OpenID authorization - through Google/Facebook
- Token management - keeping and renewal
- Refine UI
### Development

## Development

For local development create a symbolic link to your anki's add-on folder

```sh
ln -s {path_to_this_project} {path_to_anki_addon_folder}/anki_cambridge
ln -s /path/to/code/anki_cambridge "/path/to/anki/Anki2/addons21/anki_cambridge"
```
Official Anki Add-on writing [reference](https://addon-docs.ankiweb.net/intro.html)
2 changes: 1 addition & 1 deletion __init__.py
Original file line number Diff line number Diff line change
Expand Up @@ -14,7 +14,7 @@

sys.path.append(join(dirname(__file__), 'lib'))

__version__ = "0.0.1"
__version__ = "0.0.2"

from . import main

Expand Down
2 changes: 1 addition & 1 deletion _names.py
Original file line number Diff line number Diff line change
Expand Up @@ -9,7 +9,7 @@
WORD_DEFS_NAME = 'word_defs_name'
CAMBRIDGE_MODEL = 'Cambridge Dictionary'
ADDON_NAME = 'anki_cambridge'

CREATE_NEW_NOTES_SHORTCUT = "Ctrl+l"

# Request constants
WORDLIST_URL = 'https://dictionary.cambridge.org/plus/wordlist'
Expand Down
14 changes: 7 additions & 7 deletions download.py
Original file line number Diff line number Diff line change
Expand Up @@ -10,8 +10,8 @@
"""

import os
from PyQt5.QtGui import QIcon
from PyQt5.QtWidgets import QAction, QMenu
from PyQt6.QtGui import QIcon
from PyQt6.QtWidgets import QAction, QMenu


from aqt import mw
Expand Down Expand Up @@ -134,7 +134,7 @@ def download_for_note(ask_user=False, note=None, editor=None):
field_data = get_note_fields(note)
if not field_data:
# Complain before we show the empty dialog.
tooltip(u'Nothing to download.')
tooltip('Nothing to download.')
return

if ask_user:
Expand All @@ -152,26 +152,26 @@ def download_for_note(ask_user=False, note=None, editor=None):


def download_manual():
u"""Do the download with the dialog before we go."""
"""Do the download with the dialog before we go."""
download_for_note(ask_user=True)


def download_off():
u"""Deactivate the download menus."""
"""Deactivate the download menus."""
mw.note_download_action.setEnabled(False)
mw.side_download_action.setEnabled(False)
mw.manual_download_action.setEnabled(False)


def download_on():
u"""Activate the download menus."""
"""Activate the download menus."""
mw.note_download_action.setEnabled(True)
mw.side_download_action.setEnabled(True)
mw.manual_download_action.setEnabled(True)


def editor_download_editing(self):
u"""Do the download when we are in the note editor."""
"""Do the download when we are in the note editor."""
self.saveNow()
download_for_note(ask_user=True, note=self.note, editor=self)
# Fix for issue #10.
Expand Down
10 changes: 5 additions & 5 deletions download_entry.py
Original file line number Diff line number Diff line change
Expand Up @@ -18,14 +18,14 @@
# a processor, this import should work.

class DownloadEntry(object):
u"""Data about a single file downloaded by a downloader"""
"""Data about a single file downloaded by a downloader"""
def __init__(self, field_data, file_path, extras, icon):
self.file_path = file_path
# Absolute file path of the downloaded audio file
self.word = field_data.word
self.word_field_name = field_data.word_field_name
self.audio_field_name = field_data.audio_field_name
self.file_extension = u'.mp3'
self.file_extension = '.mp3'
# The file extension (with dot)
self.extras = extras
# A dict with strings of interesting informations, like
Expand All @@ -52,7 +52,7 @@ def entry_hash(self):
# has an interesting value. And that is set in JpodDownleadEntry

def process(self):
u"""Normalize &c. the audio file, if possible
"""Normalize &c. the audio file, if possible
When we have an audio processor, process the file
(i.e. normalize, remove silence, convert to preferred format)
Expand All @@ -68,7 +68,7 @@ def process(self):
self.file_extension = new_sffx

def dispatch(self, note):
u"""Do what should be done with the downloaded file
"""Do what should be done with the downloaded file
Depending on self.action, do that action.
Expand All @@ -88,7 +88,7 @@ def dispatch(self, note):


class JpodDownloadEntry(DownloadEntry):
u"""Data about a single file downloaded by a downloader"""
"""Data about a single file downloaded by a downloader"""
def __init__(
self, japanese_field_data, file_path, extras, icon, file_hash):
DownloadEntry.__init__(
Expand Down
12 changes: 6 additions & 6 deletions downloader.py
Original file line number Diff line number Diff line change
Expand Up @@ -21,8 +21,8 @@
# Make this work without PyQt
with_pyqt = True
try:
from PyQt5.QtGui import QImage
from PyQt5.QtCore import QSize, Qt
from PyQt6.QtGui import QImage
from PyQt6.QtCore import QSize, Qt
except ImportError:
with_pyqt = False

Expand Down Expand Up @@ -76,7 +76,7 @@ def __init__(self):
# False) we use the current directory.
self.site_icon = None
# The sites’s favicon.
self.file_extension = u'.mp3'
self.file_extension = '.mp3'
# Most sites have mp3 files.
self.word_data = []
# List contains dictionary(s) of word's definition(s)
Expand Down Expand Up @@ -110,7 +110,7 @@ def download_files(self, field_data):
raise NotImplementedError("Use a class derived from this.")

def maybe_get_icon(self):
u"""
"""
Get icon for the site as a QImage if we haven’t already.
Get the site icon, either the 'rel="icon"' or the favicon, for
Expand Down Expand Up @@ -157,7 +157,7 @@ def maybe_get_icon(self):
max_size, Qt.KeepAspectRatio, Qt.SmoothTransformation)

def get_favicon(self):
u"""
"""
Get favicon for the site.
This is called when the site_url can’t be loaded or when that
Expand Down Expand Up @@ -212,7 +212,7 @@ def get_tempfile_from_url(self, url_in):
# get_data raises all kinds of exceptions that fly through
# here.)
tfile = tempfile.NamedTemporaryFile(
delete=False, prefix=u'anki_audio_', suffix=self.file_extension)
delete=False, prefix='anki_audio_', suffix=self.file_extension)
tfile.write(data)
tfile.close()
return tfile.name
Expand Down
8 changes: 4 additions & 4 deletions field_data.py
Original file line number Diff line number Diff line change
Expand Up @@ -25,14 +25,14 @@ def __init__(self, w_field, a_field, word):
self.word_field_name = w_field
self.audio_field_name = a_field
# This is taken from aqt/browser.py.
self.word = word.replace(u'<br>', u' ')
self.word = self.word.replace(u'<br />', u' ')
self.word = word.replace('<br>', ' ')
self.word = self.word.replace('<br />', ' ')
if strip_interpunct:
self.word = self.word.replace(u'・', u'')
self.word = self.word.replace('・', '')
# self.word = stripHTML(self.word)
# self.word = stripSounds(self.word)
# Reformat so we have exactly one space between words.
self.word = u' '.join(self.word.split())
self.word = ' '.join(self.word.split())

@property
def empty(self):
Expand Down
16 changes: 8 additions & 8 deletions get_fields.py
Original file line number Diff line number Diff line change
Expand Up @@ -22,22 +22,22 @@
# # versions of the field names. When these lists contain upper-case
# # letters, no field will ever be matched and nothing will be
# # downloaded.
expression_fields = [u'expression', u'word']
expression_fields = ['expression', 'word']
# Fields we get the ‘normal’ download text from.
#
# Text from these fields is used by most downloaders. When no field is
# found here, we use the first field.


reading_keys = [u'reading', u'kana', u'かな', u'仮名']
reading_keys = ['reading', 'kana', 'かな', '仮名']
# Fields we get our Japanese text from.
#
# For Japanesepod we use these fields as source. A ‘Reading’ field is
# typically filled automatically by the Japanese Support add-on in a
# useful way (that is, with the reading in square brackets).


audio_field_keys = [u'audio', u'sound']
audio_field_keys = ['audio', 'sound']
# Fields we put our downloaded sounds in. Don’t try crazy stuff here.

split_kanji_kana = False
Expand All @@ -56,7 +56,7 @@ def uniqify_list(seq):


def field_data(note, audio_field, reading=False):
u"""Return FieldData when we have a source field
"""Return FieldData when we have a source field
Return FieldData when we have a matching source field for our
audio field. """
Expand Down Expand Up @@ -138,15 +138,15 @@ def field_data_from_kanji_kana(note, fn):


def get_side_fields(card, note):
u"""Return a list of FieldDatas for the currently visible side
"""Return a list of FieldDatas for the currently visible side
Go through the fields of the currently visible side and return
relevant data, as FieldData objects, for audio fields where we
have matching text fields."""
if 'question' == mw.reviewer.state:
template = card.template()[u'qfmt']
template = card.template()['qfmt']
else:
template = card.template()[u'afmt']
template = card.template()['afmt']
audio_field_names = []
all_field_names = [item[0] for item in note.items()]
for afk in audio_field_keys:
Expand Down Expand Up @@ -184,7 +184,7 @@ def get_side_fields(card, note):


def get_note_fields(note):
u"""Return a list of FieldDatas for the note
"""Return a list of FieldDatas for the note
Go through the note’s fields and return relevant data, as
FieldData objects, for audio fields where we have matching text
Expand Down
Loading

0 comments on commit 8bfb484

Please sign in to comment.