Remove support for Anki 2.0 and Python 2

This commit is contained in:
Alex Yatskov 2020-01-05 11:42:59 -08:00
parent bb62a1e93f
commit 6118d01de1

View File

@ -47,48 +47,24 @@ TICK_INTERVAL = 25
URL_TIMEOUT = 10 URL_TIMEOUT = 10
URL_UPGRADE = 'https://raw.githubusercontent.com/FooSoft/anki-connect/master/AnkiConnect.py' URL_UPGRADE = 'https://raw.githubusercontent.com/FooSoft/anki-connect/master/AnkiConnect.py'
ANKI21 = anki.version.startswith('2.1')
config = aqt.mw.addonManager.getConfig('AnkiConnect') config = aqt.mw.addonManager.getConfig('AnkiConnect')
# #
# Helpers # Helpers
# #
if sys.version_info[0] < 3: from anki.sync import AnkiRequestsClient
import urllib2 def download(url):
def download(url): contents = None
contents = None client = AnkiRequestsClient()
resp = urllib2.urlopen(url, timeout=URL_TIMEOUT) client.timeout = URL_TIMEOUT
if resp.code == 200: resp = client.get(url)
contents = resp.read() if resp.status_code == 200:
return (resp.code, contents) contents = client.streamContent(resp)
return (resp.status_code, contents)
from PyQt4.QtCore import QTimer from PyQt5.QtCore import QTimer
from PyQt4.QtGui import QMessageBox from PyQt5.QtWidgets import QMessageBox
else:
unicode = str
from anki.sync import AnkiRequestsClient
def download(url):
contents = None
client = AnkiRequestsClient()
client.timeout = URL_TIMEOUT
resp = client.get(url)
if resp.status_code == 200:
contents = client.streamContent(resp)
return (resp.status_code, contents)
from PyQt5.QtCore import QTimer
from PyQt5.QtWidgets import QMessageBox
def makeBytes(data):
return data.encode('utf-8')
def makeStr(data):
return data.decode('utf-8')
def api(*versions): def api(*versions):
@ -162,17 +138,17 @@ class WebClient:
def parseRequest(self, data): def parseRequest(self, data):
parts = data.split(makeBytes('\r\n\r\n'), 1) parts = data.split('\r\n\r\n'.encode('utf-8'), 1)
if len(parts) == 1: if len(parts) == 1:
return None, 0 return None, 0
headers = {} headers = {}
for line in parts[0].split(makeBytes('\r\n')): for line in parts[0].split('\r\n'.encode('utf-8')):
pair = line.split(makeBytes(': ')) pair = line.split(': '.encode('utf-8'))
headers[pair[0].lower()] = pair[1] if len(pair) > 1 else None headers[pair[0].lower()] = pair[1] if len(pair) > 1 else None
headerLength = len(parts[0]) + 4 headerLength = len(parts[0]) + 4
bodyLength = int(headers.get(makeBytes('content-length'), 0)) bodyLength = int(headers.get('content-length'.encode('utf-8'), 0))
totalLength = headerLength + bodyLength totalLength = headerLength + bodyLength
if totalLength > len(data): if totalLength > len(data):
@ -248,13 +224,13 @@ class WebServer:
def handlerWrapper(self, req): def handlerWrapper(self, req):
if len(req.body) == 0: if len(req.body) == 0:
body = makeBytes('AnkiConnect v.{}'.format(API_VERSION)) body = 'AnkiConnect v.{}'.format(API_VERSION).encode('utf-8')
else: else:
try: try:
params = json.loads(makeStr(req.body)) params = json.loads(req.body.decode('utf-8'))
body = makeBytes(json.dumps(self.handler(params))) body = json.dumps(self.handler(params)).encode('utf-8')
except ValueError: except ValueError:
body = makeBytes(json.dumps(None)) body = json.dumps(None).encode('utf-8')
resp = bytes() resp = bytes()
@ -263,11 +239,11 @@ class WebServer:
for key, value in headers: for key, value in headers:
if value is None: if value is None:
resp += makeBytes('{}\r\n'.format(key)) resp += '{}\r\n'.format(key).encode('utf-8')
else: else:
resp += makeBytes('{}: {}\r\n'.format(key, value)) resp += '{}: {}\r\n'.format(key, value).encode('utf-8')
resp += makeBytes('\r\n') resp += '\r\n'.encode('utf-8')
resp += body resp += body
return resp return resp
@ -498,7 +474,7 @@ class AnkiConnect:
data = self.download(URL_UPGRADE) data = self.download(URL_UPGRADE)
path = os.path.splitext(__file__)[0] + '.py' path = os.path.splitext(__file__)[0] + '.py'
with open(path, 'w') as fp: with open(path, 'w') as fp:
fp.write(makeStr(data)) fp.write(data.decode('utf-8'))
QMessageBox.information( QMessageBox.information(
self.window(), self.window(),
'AnkiConnect', 'AnkiConnect',
@ -1168,85 +1144,47 @@ class AnkiConnect:
randomString = ''.join(choice(ascii_letters) for _ in range(10)) randomString = ''.join(choice(ascii_letters) for _ in range(10))
windowName = 'AddCardsAndClose' + randomString windowName = 'AddCardsAndClose' + randomString
if ANKI21: class AddCardsAndClose(aqt.addcards.AddCards):
class AddCardsAndClose(aqt.addcards.AddCards):
def __init__(self, mw): def __init__(self, mw):
# the window must only reset if # the window must only reset if
# * function `onModelChange` has been called prior # * function `onModelChange` has been called prior
# * window was newly opened # * window was newly opened
self.modelHasChanged = True
super().__init__(mw)
self.addButton.setText("Add and Close")
self.addButton.setShortcut(aqt.qt.QKeySequence("Ctrl+Return"))
def _addCards(self):
super()._addCards()
# if adding was successful it must mean it was added to the history of the window
if len(self.history):
self.reject()
def onModelChange(self):
if self.isActiveWindow():
super().onModelChange()
self.modelHasChanged = True self.modelHasChanged = True
super().__init__(mw)
self.addButton.setText("Add and Close") def onReset(self, model=None, keep=False):
self.addButton.setShortcut(aqt.qt.QKeySequence("Ctrl+Return")) if self.isActiveWindow() or self.modelHasChanged:
super().onReset(model, keep)
self.modelHasChanged = False
def _addCards(self): else:
super()._addCards() # modelchoosers text is changed by a reset hook
# therefore we need to change it back manually
self.modelChooser.models.setText(self.editor.note.model()['name'])
self.modelHasChanged = False
# if adding was successful it must mean it was added to the history of the window def _reject(self):
if len(self.history): savedMarkClosed = aqt.dialogs.markClosed
self.reject() aqt.dialogs.markClosed = lambda _: savedMarkClosed(windowName)
super()._reject()
def onModelChange(self): aqt.dialogs.markClosed = savedMarkClosed
if self.isActiveWindow():
super().onModelChange()
self.modelHasChanged = True
def onReset(self, model=None, keep=False):
if self.isActiveWindow() or self.modelHasChanged:
super().onReset(model, keep)
self.modelHasChanged = False
else:
# modelchoosers text is changed by a reset hook
# therefore we need to change it back manually
self.modelChooser.models.setText(self.editor.note.model()['name'])
self.modelHasChanged = False
def _reject(self):
savedMarkClosed = aqt.dialogs.markClosed
aqt.dialogs.markClosed = lambda _: savedMarkClosed(windowName)
super()._reject()
aqt.dialogs.markClosed = savedMarkClosed
else:
class AddCardsAndClose(aqt.addcards.AddCards):
def __init__(self, mw):
self.modelHasChanged = True
super(AddCardsAndClose, self).__init__(mw)
self.addButton.setText("Add and Close")
self.addButton.setShortcut(aqt.qt.QKeySequence("Ctrl+Return"))
def addCards(self):
super(AddCardsAndClose, self).addCards()
# if adding was successful it must mean it was added to the history of the window
if len(self.history):
self.reject()
def onModelChange(self):
if self.isActiveWindow():
super(AddCardsAndClose, self).onModelChange()
self.modelHasChanged = True
def onReset(self, model=None, keep=False):
if self.isActiveWindow() or self.modelHasChanged:
super(AddCardsAndClose, self).onReset(model, keep)
self.modelHasChanged = False
else:
self.modelChooser.models.setText(self.editor.note.model()['name'])
self.modelHasChanged = False
def reject(self):
savedClose = aqt.dialogs.close
aqt.dialogs.close = lambda _: savedClose(windowName)
super(AddCardsAndClose, self).reject()
aqt.dialogs.close = savedClose
aqt.dialogs._dialogs[windowName] = [AddCardsAndClose, None] aqt.dialogs._dialogs[windowName] = [AddCardsAndClose, None]
addCards = aqt.dialogs.open(windowName, self.window()) addCards = aqt.dialogs.open(windowName, self.window())
@ -1270,8 +1208,7 @@ class AnkiConnect:
# if Anki does not Focus, the window will not notice that the # if Anki does not Focus, the window will not notice that the
# fields are actually filled # fields are actually filled
aqt.dialogs.open(windowName, self.window()) aqt.dialogs.open(windowName, self.window())
if ANKI21: addCards.setAndFocusNote(editor.note)
addCards.setAndFocusNote(editor.note)
elif note is not None: elif note is not None:
currentWindow = aqt.dialogs._dialogs['AddCards'][1] currentWindow = aqt.dialogs._dialogs['AddCards'][1]
@ -1300,15 +1237,10 @@ class AnkiConnect:
addCards.activateWindow() addCards.activateWindow()
aqt.dialogs.open('AddCards', self.window()) aqt.dialogs.open('AddCards', self.window())
if ANKI21: addCards.setAndFocusNote(editor.note)
addCards.setAndFocusNote(editor.note)
if currentWindow is not None: if currentWindow is not None:
if ANKI21: currentWindow.closeWithCallback(openNewWindow)
currentWindow.closeWithCallback(openNewWindow)
else:
currentWindow.reject()
openNewWindow()
else: else:
openNewWindow() openNewWindow()