mirror of
https://github.com/ankitects/anki.git
synced 2025-09-25 01:06:35 -04:00
Merge branch 'master' of https://github.com/dae/anki
This commit is contained in:
commit
019249269b
7 changed files with 42 additions and 13 deletions
|
@ -2,7 +2,13 @@
|
||||||
# Copyright: Damien Elmes <anki@ichi2.net>
|
# Copyright: Damien Elmes <anki@ichi2.net>
|
||||||
# License: GNU AGPL, version 3 or later; http://www.gnu.org/licenses/agpl.html
|
# 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.lang import _, ngettext
|
||||||
from anki.utils import ids2str, fieldChecksum, stripHTML, \
|
from anki.utils import ids2str, fieldChecksum, stripHTML, \
|
||||||
intTime, splitFields, joinFields, maxID, json
|
intTime, splitFields, joinFields, maxID, json
|
||||||
|
@ -15,9 +21,12 @@ from anki.tags import TagManager
|
||||||
from anki.consts import *
|
from anki.consts import *
|
||||||
from anki.errors import AnkiError
|
from anki.errors import AnkiError
|
||||||
from anki.sound import stripSounds
|
from anki.sound import stripSounds
|
||||||
|
|
||||||
import anki.latex # sets up hook
|
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 = {
|
defaultConf = {
|
||||||
# review options
|
# review options
|
||||||
|
@ -176,15 +185,20 @@ crt=?, mod=?, scm=?, dty=?, usn=?, ls=?, conf=?""",
|
||||||
|
|
||||||
def beforeUpload(self):
|
def beforeUpload(self):
|
||||||
"Called before a full upload."
|
"Called before a full upload."
|
||||||
tbls = "notes", "cards", "revlog", "graves"
|
tbls = "notes", "cards", "revlog"
|
||||||
for t in tbls:
|
for t in tbls:
|
||||||
self.db.execute("update %s set usn=0 where usn=-1" % t)
|
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._usn += 1
|
||||||
self.models.beforeUpload()
|
self.models.beforeUpload()
|
||||||
self.tags.beforeUpload()
|
self.tags.beforeUpload()
|
||||||
self.decks.beforeUpload()
|
self.decks.beforeUpload()
|
||||||
self.modSchema()
|
self.modSchema()
|
||||||
self.ls = self.scm
|
self.ls = self.scm
|
||||||
|
# ensure db is compacted before upload
|
||||||
|
self.db.execute("vacuum")
|
||||||
|
self.db.execute("analyze")
|
||||||
self.close()
|
self.close()
|
||||||
|
|
||||||
# Object creation helpers
|
# Object creation helpers
|
||||||
|
|
|
@ -47,7 +47,7 @@ SCHEMA_VERSION = 11
|
||||||
SYNC_ZIP_SIZE = int(2.5*1024*1024)
|
SYNC_ZIP_SIZE = int(2.5*1024*1024)
|
||||||
SYNC_ZIP_COUNT = 100
|
SYNC_ZIP_COUNT = 100
|
||||||
SYNC_URL = os.environ.get("SYNC_URL") or "https://ankiweb.net/sync/"
|
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"
|
HELP_SITE="http://ankisrs.net/docs/manual.html"
|
||||||
|
|
||||||
|
|
|
@ -152,7 +152,8 @@ class AnkiExporter(Exporter):
|
||||||
else:
|
else:
|
||||||
# need to reset card state
|
# need to reset card state
|
||||||
self.dst.sched.resetCards(cids)
|
self.dst.sched.resetCards(cids)
|
||||||
# models
|
# models - start with zero
|
||||||
|
self.dst.models.models = {}
|
||||||
for m in self.src.models.all():
|
for m in self.src.models.all():
|
||||||
if int(m['id']) in mids:
|
if int(m['id']) in mids:
|
||||||
self.dst.models.update(m)
|
self.dst.models.update(m)
|
||||||
|
|
|
@ -124,8 +124,8 @@ class ModelManager(object):
|
||||||
"Get all models."
|
"Get all models."
|
||||||
return self.models.values()
|
return self.models.values()
|
||||||
|
|
||||||
def allNames(self, curm=None):
|
def allNames(self):
|
||||||
return [m['name'] for m in self.all() if m!=curm]
|
return [m['name'] for m in self.all()]
|
||||||
|
|
||||||
def byName(self, name):
|
def byName(self, name):
|
||||||
"Get model with 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
|
if (mcur['name'] == m['name'] and
|
||||||
mcur['id'] != m['id']):
|
mcur['id'] != m['id']):
|
||||||
m['name'] += "-" + checksum(str(time.time()))[:5]
|
m['name'] += "-" + checksum(str(time.time()))[:5]
|
||||||
|
break
|
||||||
|
|
||||||
def update(self, m):
|
def update(self, m):
|
||||||
"Add or update an existing model. Used for syncing and merging."
|
"Add or update an existing model. Used for syncing and merging."
|
||||||
|
|
12
anki/sync.py
12
anki/sync.py
|
@ -2,10 +2,16 @@
|
||||||
# Copyright: Damien Elmes <anki@ichi2.net>
|
# Copyright: Damien Elmes <anki@ichi2.net>
|
||||||
# License: GNU AGPL, version 3 or later; http://www.gnu.org/licenses/agpl.html
|
# 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
|
from cStringIO import StringIO
|
||||||
|
|
||||||
|
import httplib2
|
||||||
from anki.db import DB
|
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 anki.consts import *
|
||||||
from hooks import runHook
|
from hooks import runHook
|
||||||
import anki
|
import anki
|
||||||
|
@ -519,6 +525,7 @@ class HttpSyncer(object):
|
||||||
|
|
||||||
def __init__(self, hkey=None, con=None):
|
def __init__(self, hkey=None, con=None):
|
||||||
self.hkey = hkey
|
self.hkey = hkey
|
||||||
|
self.skey = checksum(str(random.random()))[:8]
|
||||||
self.con = con or httpCon()
|
self.con = con or httpCon()
|
||||||
|
|
||||||
def assertOk(self, resp):
|
def assertOk(self, resp):
|
||||||
|
@ -541,6 +548,7 @@ class HttpSyncer(object):
|
||||||
vars['c'] = 1 if comp else 0
|
vars['c'] = 1 if comp else 0
|
||||||
if hkey:
|
if hkey:
|
||||||
vars['k'] = self.hkey
|
vars['k'] = self.hkey
|
||||||
|
vars['s'] = self.skey
|
||||||
for (key, value) in vars.items():
|
for (key, value) in vars.items():
|
||||||
buf.write(bdry + "\r\n")
|
buf.write(bdry + "\r\n")
|
||||||
buf.write(
|
buf.write(
|
||||||
|
|
|
@ -236,7 +236,7 @@ class DataModel(QAbstractTableModel):
|
||||||
elif type == "cardLapses":
|
elif type == "cardLapses":
|
||||||
return str(c.lapses)
|
return str(c.lapses)
|
||||||
elif type == "noteTags":
|
elif type == "noteTags":
|
||||||
return str(" ".join(c.note().tags))
|
return " ".join(c.note().tags)
|
||||||
elif type == "note":
|
elif type == "note":
|
||||||
return c.model()['name']
|
return c.model()['name']
|
||||||
elif type == "cardIvl":
|
elif type == "cardIvl":
|
||||||
|
|
|
@ -2,8 +2,12 @@
|
||||||
# License: GNU AGPL, version 3 or later; http://www.gnu.org/licenses/agpl.html
|
# License: GNU AGPL, version 3 or later; http://www.gnu.org/licenses/agpl.html
|
||||||
|
|
||||||
from __future__ import division
|
from __future__ import division
|
||||||
|
import socket
|
||||||
|
import time
|
||||||
|
import traceback
|
||||||
|
import gc
|
||||||
|
|
||||||
from aqt.qt import *
|
from aqt.qt import *
|
||||||
import socket, time, traceback, gc
|
|
||||||
import aqt
|
import aqt
|
||||||
from anki import Collection
|
from anki import Collection
|
||||||
from anki.sync import Syncer, RemoteServer, FullSyncer, MediaSyncer, \
|
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 anki.hooks import addHook, remHook
|
||||||
from aqt.utils import tooltip, askUserDialog, showWarning, showText, showInfo
|
from aqt.utils import tooltip, askUserDialog, showWarning, showText, showInfo
|
||||||
|
|
||||||
|
|
||||||
# Sync manager
|
# Sync manager
|
||||||
######################################################################
|
######################################################################
|
||||||
|
|
||||||
|
@ -161,7 +166,7 @@ AnkiWeb is too busy at the moment. Please try again in a few minutes.""")
|
||||||
elif "504" in err:
|
elif "504" in err:
|
||||||
return _("504 gateway timeout error received. Please try temporarily disabling your antivirus.")
|
return _("504 gateway timeout error received. Please try temporarily disabling your antivirus.")
|
||||||
elif "409" in err:
|
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:
|
elif "10061" in err or "10013" in err:
|
||||||
return _(
|
return _(
|
||||||
"Antivirus or firewall software is preventing Anki from connecting to the internet.")
|
"Antivirus or firewall software is preventing Anki from connecting to the internet.")
|
||||||
|
|
Loading…
Reference in a new issue