From 9d8df81e117fb879cecb4bcfdcfb7b1d5a48fa98 Mon Sep 17 00:00:00 2001 From: Damien Elmes Date: Fri, 12 Jun 2009 20:26:00 +0900 Subject: [PATCH 01/12] cleanup mplayer slave on exit --- anki/sound.py | 11 ++++++++++- 1 file changed, 10 insertions(+), 1 deletion(-) diff --git a/anki/sound.py b/anki/sound.py index f9dce324b..33f2e6e43 100644 --- a/anki/sound.py +++ b/anki/sound.py @@ -8,7 +8,7 @@ Sound support """ __docformat__ = 'restructuredtext' -import re, sys, threading, time, subprocess, os, signal +import re, sys, threading, time, subprocess, os, signal, atexit # Shared utils ########################################################################## @@ -160,8 +160,17 @@ def clearMplayerQueue(): mplayerQueue.append(None) mplayerCond.release() +def stopMplayer(): + mplayerCond.acquire() + if mplayerManager.mplayer: + mplayerManager.mplayer.communicate("quit\n") + mplayerManager.mplayer = -1 + mplayerCond.notify() + mplayerCond.release() + mplayerManager = MplayerMonitor() mplayerManager.start() +atexit.register(stopMplayer) # PyAudio recording ########################################################################## From b5da38474f94b9be70cfdb3d8bda7f9ec879550f Mon Sep 17 00:00:00 2001 From: Damien Elmes Date: Fri, 12 Jun 2009 22:21:57 +0900 Subject: [PATCH 02/12] allow arbitrary number of args in filters --- anki/hooks.py | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/anki/hooks.py b/anki/hooks.py index 3880defb8..c43e104bf 100644 --- a/anki/hooks.py +++ b/anki/hooks.py @@ -25,11 +25,11 @@ def runHook(hook, *args): for func in hook: func(*args) -def runFilter(hook, arg): +def runFilter(hook, arg, *args): hook = _hooks.get(hook, None) if hook: for func in hook: - arg = func(arg) + arg = func(arg, *args) return arg def addHook(hook, func): From e08a86c28dfe6a0b8f846f98f1f8b1365c8f9fba Mon Sep 17 00:00:00 2001 From: Damien Elmes Date: Fri, 12 Jun 2009 22:22:10 +0900 Subject: [PATCH 03/12] strip samples & unihan from dist --- setup.py | 5 ++--- 1 file changed, 2 insertions(+), 3 deletions(-) diff --git a/setup.py b/setup.py index 239a8ad9b..6c959a6a9 100644 --- a/setup.py +++ b/setup.py @@ -24,9 +24,8 @@ setup(name='anki', author_email='anki@ichi2.net', url='http://ichi2.net/anki/index.html', license='GPLv3', - packages=["anki", "anki.features", "anki.features.chinese", "anki.importing"], - package_data={'anki': ['samples/*','locale/*/*/*'], - 'anki.features.chinese': ['unihan.db']}, + packages=["anki", "anki.importing"], + package_data={'anki': ['locale/*/*/*'],}, include_package_data=True, zip_safe=False, install_requires=[ From 2db2b65df09028b540322869f7ce5a9652d38fde Mon Sep 17 00:00:00 2001 From: Damien Elmes Date: Fri, 12 Jun 2009 22:41:21 +0900 Subject: [PATCH 04/12] set deck created time on download --- anki/deck.py | 1 + 1 file changed, 1 insertion(+) diff --git a/anki/deck.py b/anki/deck.py index 2301d4994..c1387d6f6 100644 --- a/anki/deck.py +++ b/anki/deck.py @@ -2651,6 +2651,7 @@ class DeckStorage(object): DeckStorage._addIndices(deck) for m in deck.models: deck.updateCardsFromModel(m) + deck.created = time.time() deck.finishProgress() # fix a bug with current model being unset if not deck.currentModel and deck.models: From efb71c754caff441076b2e1952bf941dadb66b2d Mon Sep 17 00:00:00 2001 From: Damien Elmes Date: Sat, 13 Jun 2009 01:14:54 +0900 Subject: [PATCH 05/12] bump protocol version --- anki/sync.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/anki/sync.py b/anki/sync.py index 72db20c98..1297e96da 100644 --- a/anki/sync.py +++ b/anki/sync.py @@ -1053,7 +1053,7 @@ class HttpSyncServerProxy(SyncServer): self.deckName = None self.username = user self.password = passwd - self.protocolVersion = 4 + self.protocolVersion = 5 self.sourcesToCheck = [] def connect(self, clientVersion=""): From e578ffc721c1abcb7f1659bfdd2d26b7bb64df42 Mon Sep 17 00:00:00 2001 From: Damien Elmes Date: Sat, 13 Jun 2009 16:01:58 +0900 Subject: [PATCH 06/12] map all file descriptors to work with py2exe --- anki/sound.py | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/anki/sound.py b/anki/sound.py index 33f2e6e43..27b36855a 100644 --- a/anki/sound.py +++ b/anki/sound.py @@ -144,7 +144,8 @@ class MplayerMonitor(threading.Thread): def startProcess(self): try: self.mplayer = subprocess.Popen( - mplayerCmd, startupinfo=si, stdin=subprocess.PIPE) + mplayerCmd, startupinfo=si, stdin=subprocess.PIPE, + stdout=subprocess.PIPE, stderr=subprocess.STDOUT) except OSError: raise Exception("Audio player not found") From fb8f2bd09f474f396553a5eed4092b5c8ef6423c Mon Sep 17 00:00:00 2001 From: Damien Elmes Date: Mon, 15 Jun 2009 06:57:36 +0900 Subject: [PATCH 07/12] handle interrupted system call errors on mplayer shutdown --- anki/sound.py | 8 +++++++- 1 file changed, 7 insertions(+), 1 deletion(-) diff --git a/anki/sound.py b/anki/sound.py index 27b36855a..f5db2c426 100644 --- a/anki/sound.py +++ b/anki/sound.py @@ -164,7 +164,13 @@ def clearMplayerQueue(): def stopMplayer(): mplayerCond.acquire() if mplayerManager.mplayer: - mplayerManager.mplayer.communicate("quit\n") + while 1: + try: + mplayerManager.mplayer.communicate("quit\n") + break + except OSError: + # osx throws these regularly + pass mplayerManager.mplayer = -1 mplayerCond.notify() mplayerCond.release() From 8d3678b9fbc870533d10ba909cda3efe298ef42d Mon Sep 17 00:00:00 2001 From: Damien Elmes Date: Mon, 15 Jun 2009 06:57:50 +0900 Subject: [PATCH 08/12] mark deck dirty on reset cards --- anki/deck.py | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/anki/deck.py b/anki/deck.py index c1387d6f6..d88b47943 100644 --- a/anki/deck.py +++ b/anki/deck.py @@ -471,7 +471,7 @@ where id != :id and factId = :factId""", else: due = self.delay0 else: - due = card.interval * 86400.0 + due = card.interval * 86400.0 return due + time.time() def updateFactor(self, card, ease): @@ -515,6 +515,7 @@ where id in %s""" % ids2str(ids), now=time.time(), new=0) if self.newCardOrder == NEW_CARDS_RANDOM: # we need to re-randomize now self.randomizeNewCards(ids) + self.flushMod() self.refresh() def randomizeNewCards(self, cardIds=None): From 7cac17a543d4576c6019e4d331bc4afb148ceec9 Mon Sep 17 00:00:00 2001 From: Damien Elmes Date: Mon, 15 Jun 2009 11:26:42 +0900 Subject: [PATCH 09/12] restart mplayer if it has stopped --- anki/sound.py | 3 +++ 1 file changed, 3 insertions(+) diff --git a/anki/sound.py b/anki/sound.py index f5db2c426..a30ddac40 100644 --- a/anki/sound.py +++ b/anki/sound.py @@ -126,6 +126,9 @@ class MplayerMonitor(threading.Thread): mplayerCond.wait() if not self.mplayer: self.startProcess() + if self.mplayer.poll() is not None: + self.mplayer.wait() + self.startProcess() nextClears = False while mplayerQueue: item = mplayerQueue.pop(0) From e66e66c614c82658c461a3975b647bd238ca11c3 Mon Sep 17 00:00:00 2001 From: Damien Elmes Date: Mon, 15 Jun 2009 11:37:02 +0900 Subject: [PATCH 10/12] don't catch all osx errors --- anki/sound.py | 10 ++++++---- 1 file changed, 6 insertions(+), 4 deletions(-) diff --git a/anki/sound.py b/anki/sound.py index a30ddac40..502326041 100644 --- a/anki/sound.py +++ b/anki/sound.py @@ -8,7 +8,7 @@ Sound support """ __docformat__ = 'restructuredtext' -import re, sys, threading, time, subprocess, os, signal, atexit +import re, sys, threading, time, subprocess, os, signal, atexit, errno # Shared utils ########################################################################## @@ -171,9 +171,11 @@ def stopMplayer(): try: mplayerManager.mplayer.communicate("quit\n") break - except OSError: - # osx throws these regularly - pass + except OSError, e: + if e.errno != errno.EINTR: + # osx throws interrupt errors regularly, but we want to + # ignore other errors on shutdown + break mplayerManager.mplayer = -1 mplayerCond.notify() mplayerCond.release() From 8e92a4dfc82c6b04289b08a79bf12aaee430663b Mon Sep 17 00:00:00 2001 From: Damien Elmes Date: Mon, 15 Jun 2009 11:45:11 +0900 Subject: [PATCH 11/12] don't poll empty mplayer --- anki/sound.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/anki/sound.py b/anki/sound.py index 502326041..5da54c671 100644 --- a/anki/sound.py +++ b/anki/sound.py @@ -126,7 +126,7 @@ class MplayerMonitor(threading.Thread): mplayerCond.wait() if not self.mplayer: self.startProcess() - if self.mplayer.poll() is not None: + if self.mplayer != -1 and self.mplayer.poll() is not None: self.mplayer.wait() self.startProcess() nextClears = False From 09e002c8d619aef305b65fa181e0b963c6a86c9d Mon Sep 17 00:00:00 2001 From: Damien Elmes Date: Mon, 15 Jun 2009 11:57:25 +0900 Subject: [PATCH 12/12] when generating cards in ordered mode, set due = fact creation + ordinal --- anki/cards.py | 9 ++++++--- anki/deck.py | 3 ++- 2 files changed, 8 insertions(+), 4 deletions(-) diff --git a/anki/cards.py b/anki/cards.py index 8fd2bbcbb..599ef0ab5 100644 --- a/anki/cards.py +++ b/anki/cards.py @@ -68,7 +68,7 @@ cardsTable = Table( class Card(object): "A card." - def __init__(self, fact=None, cardModel=None): + def __init__(self, fact=None, cardModel=None, due=None): self.tags = u"" self.id = genID() # new cards start as new & due @@ -77,8 +77,11 @@ class Card(object): self.timerStarted = False self.timerStopped = False self.modified = time.time() - self.due = self.modified - self.combinedDue = self.modified + if due: + self.due = due + else: + self.due = self.modified + self.combinedDue = self.due if fact: self.fact = fact if cardModel: diff --git a/anki/deck.py b/anki/deck.py index d88b47943..16a61ce26 100644 --- a/anki/deck.py +++ b/anki/deck.py @@ -1033,7 +1033,8 @@ where type = 2 and priority in (1,2,3,4)""") or 0 select count(id) from cards where factId = :fid and cardModelId = :cmid""", fid=fact.id, cmid=cardModel.id) == 0: - card = anki.cards.Card(fact, cardModel) + card = anki.cards.Card( + fact, cardModel, due=fact.created+cardModel.ordinal) self.updateCardTags([card.id]) self.updatePriority(card) self.cardCount += 1