From 7aee582a58e8c8c854635d9cec4faa10becf1279 Mon Sep 17 00:00:00 2001 From: Damien Elmes Date: Sun, 6 Oct 2013 09:25:04 +0900 Subject: [PATCH 1/8] loop should exit early, and allNames() doesn't need modification --- anki/models.py | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/anki/models.py b/anki/models.py index fade814b9..8ad5b158d 100644 --- a/anki/models.py +++ b/anki/models.py @@ -124,8 +124,8 @@ class ModelManager(object): "Get all models." return self.models.values() - def allNames(self, curm=None): - return [m['name'] for m in self.all() if m!=curm] + def allNames(self): + return [m['name'] for m in self.all()] def byName(self, name): "Get model with NAME." @@ -171,6 +171,7 @@ select id from cards where nid in (select id from notes where mid = ?)""", if (mcur['name'] == m['name'] and mcur['id'] != m['id']): m['name'] += "-" + checksum(str(time.time()))[:5] + break def update(self, m): "Add or update an existing model. Used for syncing and merging." From bc96a00fd2da468cf1586e20a97c21d77c0cef45 Mon Sep 17 00:00:00 2001 From: Damien Elmes Date: Sun, 6 Oct 2013 09:45:38 +0900 Subject: [PATCH 2/8] we need to clear out std models on export or we end up renaming and the rename affects the exporting deck as well --- anki/exporting.py | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/anki/exporting.py b/anki/exporting.py index 0d711d146..cc12e3d5a 100644 --- a/anki/exporting.py +++ b/anki/exporting.py @@ -152,7 +152,8 @@ class AnkiExporter(Exporter): else: # need to reset card state self.dst.sched.resetCards(cids) - # models + # models - start with zero + self.dst.models.models = {} for m in self.src.models.all(): if int(m['id']) in mids: self.dst.models.update(m) From d503b62cd1915fc311fb55ce0d975d0b7280fe4b Mon Sep 17 00:00:00 2001 From: Damien Elmes Date: Tue, 8 Oct 2013 07:42:06 +0900 Subject: [PATCH 3/8] fix display of non-latin tags --- aqt/browser.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/aqt/browser.py b/aqt/browser.py index b9f18b971..91c4b5644 100644 --- a/aqt/browser.py +++ b/aqt/browser.py @@ -236,7 +236,7 @@ class DataModel(QAbstractTableModel): elif type == "cardLapses": return str(c.lapses) elif type == "noteTags": - return str(" ".join(c.note().tags)) + return " ".join(c.note().tags) elif type == "note": return c.model()['name'] elif type == "cardIvl": From 2d4e88afbd04f392ff7c3a89428d1bf7fb27da49 Mon Sep 17 00:00:00 2001 From: Damien Elmes Date: Wed, 9 Oct 2013 13:13:48 +0900 Subject: [PATCH 4/8] tolerate a str arg to writeData() --- anki/media.py | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/anki/media.py b/anki/media.py index 6a76594af..a4ded8ca0 100644 --- a/anki/media.py +++ b/anki/media.py @@ -89,6 +89,10 @@ class MediaManager(object): return self.writeData(opath, open(opath, "rb").read()) def writeData(self, opath, data): + if not isinstance(opath, unicode): + # old code/addons were passing as str + print "writeData() should be called with unicode" + opath = unicode(opath, "utf8", "ignore") # if fname is a full path, use only the basename fname = os.path.basename(opath) # make sure we write it in NFC form (on mac will autoconvert to NFD), From b42c0c725b3c727ec31ed367edb2d98001122cf2 Mon Sep 17 00:00:00 2001 From: Damien Elmes Date: Thu, 10 Oct 2013 11:08:39 +0900 Subject: [PATCH 5/8] Revert "tolerate a str arg to writeData()" This reverts commit 2d4e88afbd04f392ff7c3a89428d1bf7fb27da49. On second thought, this change is likely to mask the error in most cases, and we want add-on authors to update their add-ons anyway as they would not be handling non-latin text in 2.0.12. --- anki/media.py | 4 ---- 1 file changed, 4 deletions(-) diff --git a/anki/media.py b/anki/media.py index a4ded8ca0..6a76594af 100644 --- a/anki/media.py +++ b/anki/media.py @@ -89,10 +89,6 @@ class MediaManager(object): return self.writeData(opath, open(opath, "rb").read()) def writeData(self, opath, data): - if not isinstance(opath, unicode): - # old code/addons were passing as str - print "writeData() should be called with unicode" - opath = unicode(opath, "utf8", "ignore") # if fname is a full path, use only the basename fname = os.path.basename(opath) # make sure we write it in NFC form (on mac will autoconvert to NFD), From 2f3f285528f599c6df19ee9c210f60a3bb6a74de Mon Sep 17 00:00:00 2001 From: Damien Elmes Date: Thu, 10 Oct 2013 11:48:38 +0900 Subject: [PATCH 6/8] clarify 409 msg --- aqt/sync.py | 9 +++++++-- 1 file changed, 7 insertions(+), 2 deletions(-) diff --git a/aqt/sync.py b/aqt/sync.py index b8a29a39a..9660ea436 100644 --- a/aqt/sync.py +++ b/aqt/sync.py @@ -2,8 +2,12 @@ # License: GNU AGPL, version 3 or later; http://www.gnu.org/licenses/agpl.html from __future__ import division +import socket +import time +import traceback +import gc + from aqt.qt import * -import socket, time, traceback, gc import aqt from anki import Collection from anki.sync import Syncer, RemoteServer, FullSyncer, MediaSyncer, \ @@ -11,6 +15,7 @@ from anki.sync import Syncer, RemoteServer, FullSyncer, MediaSyncer, \ from anki.hooks import addHook, remHook from aqt.utils import tooltip, askUserDialog, showWarning, showText, showInfo + # Sync manager ###################################################################### @@ -161,7 +166,7 @@ AnkiWeb is too busy at the moment. Please try again in a few minutes.""") elif "504" in err: return _("504 gateway timeout error received. Please try temporarily disabling your antivirus.") elif "409" in err: - return _("A previous sync failed; please try again in a few minutes.") + return _("Only one client can access AnkiWeb at a time. If a previous sync failed, please try again in a few minutes.") elif "10061" in err or "10013" in err: return _( "Antivirus or firewall software is preventing Anki from connecting to the internet.") From 8d7edcb2bb80a83903d648399b7df7ed25a7910d Mon Sep 17 00:00:00 2001 From: Damien Elmes Date: Thu, 10 Oct 2013 12:02:11 +0900 Subject: [PATCH 7/8] include a session key when syncing --- anki/consts.py | 2 +- anki/sync.py | 12 ++++++++++-- 2 files changed, 11 insertions(+), 3 deletions(-) diff --git a/anki/consts.py b/anki/consts.py index 682314a23..1b219941b 100644 --- a/anki/consts.py +++ b/anki/consts.py @@ -47,7 +47,7 @@ SCHEMA_VERSION = 11 SYNC_ZIP_SIZE = int(2.5*1024*1024) SYNC_ZIP_COUNT = 100 SYNC_URL = os.environ.get("SYNC_URL") or "https://ankiweb.net/sync/" -SYNC_VER = 7 +SYNC_VER = 8 HELP_SITE="http://ankisrs.net/docs/manual.html" diff --git a/anki/sync.py b/anki/sync.py index c854ea249..e8a53a002 100644 --- a/anki/sync.py +++ b/anki/sync.py @@ -2,10 +2,16 @@ # Copyright: Damien Elmes # License: GNU AGPL, version 3 or later; http://www.gnu.org/licenses/agpl.html -import urllib, os, sys, httplib2, gzip +import urllib +import os +import sys +import gzip +import random from cStringIO import StringIO + +import httplib2 from anki.db import DB -from anki.utils import ids2str, intTime, json, isWin, isMac, platDesc +from anki.utils import ids2str, intTime, json, isWin, isMac, platDesc, checksum from anki.consts import * from hooks import runHook import anki @@ -519,6 +525,7 @@ class HttpSyncer(object): def __init__(self, hkey=None, con=None): self.hkey = hkey + self.skey = checksum(str(random.random()))[:8] self.con = con or httpCon() def assertOk(self, resp): @@ -541,6 +548,7 @@ class HttpSyncer(object): vars['c'] = 1 if comp else 0 if hkey: vars['k'] = self.hkey + vars['s'] = self.skey for (key, value) in vars.items(): buf.write(bdry + "\r\n") buf.write( From e9ab9128c874ff516941cce0c6e18b51c1862f5f Mon Sep 17 00:00:00 2001 From: Damien Elmes Date: Fri, 11 Oct 2013 12:21:59 +0900 Subject: [PATCH 8/8] we can remove graves when uploading and save space --- anki/collection.py | 22 ++++++++++++++++++---- 1 file changed, 18 insertions(+), 4 deletions(-) diff --git a/anki/collection.py b/anki/collection.py index a468eaca5..dcb74c7b7 100644 --- a/anki/collection.py +++ b/anki/collection.py @@ -2,7 +2,13 @@ # Copyright: Damien Elmes # License: GNU AGPL, version 3 or later; http://www.gnu.org/licenses/agpl.html -import time, os, random, stat, datetime, copy +import time +import os +import random +import stat +import datetime +import copy + from anki.lang import _, ngettext from anki.utils import ids2str, fieldChecksum, stripHTML, \ intTime, splitFields, joinFields, maxID, json @@ -15,9 +21,12 @@ from anki.tags import TagManager from anki.consts import * from anki.errors import AnkiError from anki.sound import stripSounds - import anki.latex # sets up hook -import anki.cards, anki.notes, anki.template, anki.find +import anki.cards +import anki.notes +import anki.template +import anki.find + defaultConf = { # review options @@ -176,15 +185,20 @@ crt=?, mod=?, scm=?, dty=?, usn=?, ls=?, conf=?""", def beforeUpload(self): "Called before a full upload." - tbls = "notes", "cards", "revlog", "graves" + tbls = "notes", "cards", "revlog" for t in tbls: self.db.execute("update %s set usn=0 where usn=-1" % t) + # we can save space by removing the log of deletions + self.db.execute("delete from graves") self._usn += 1 self.models.beforeUpload() self.tags.beforeUpload() self.decks.beforeUpload() self.modSchema() self.ls = self.scm + # ensure db is compacted before upload + self.db.execute("vacuum") + self.db.execute("analyze") self.close() # Object creation helpers