Panki Chinese


On this page you will find

What is “Panki Chinese”?

“Panki Chinese” is the combination of great Chinese study material with a decent program to study and repeat such material. It is recommended for daily use by students with at least a basic level of oral Chinese and is especially useful for learning Chinese characters. It contains in detail:

How to get and install “Panki Chinese”?


The details


The PankiChinese plugin has some side-effects within Anki. I hope it will get integrated into original Anki one day, so that this problem would go. – So, when you are not reviewing the Panki Chinese deck, switch the plugin “PankiChinese” off (Settings menu) and restart. This turns Anki back to normal, with all standard functionality. (Otherwise, latex, part of the card browser and media handling wont work.)

The other plugins from the package can stay on and won’t interfere.


For developers and power users

I made more hacks to Anki to meet my and Panki users’ needs even better. I do those hacks in Python, the source language of Anki. – Unfortunately it is not easy to provide those changes as a plugin. Likewise I don’t have a way to pack hacked Anki for Windows (if you can help me here, speak up).

This patch for Anki 1.2.8 was developed for use with the Panki Chinese Deck. To use it, you should be able to install and run Python Anki 1.2.8 and know how to apply patches. The modifications do the following (in order of appereance in the patch file):

file/function/locationfeature/advantages/caevats to myself: disable the'', file)
actionRepeatAudioshortcut set from F5 to F3
actionSuspendCardshortcut set from Ctrl+Shift+S to simply 0 (quick!)
tag handlingripped out wherever it came across
clearOldFact()superfluous code removed
rebuildCSS()gone for good (and not called all the time!), CSS is an external file, comming with the Panki deck
rebuildSortIndex()no indices anymore! Takes time to build, rebuild and maintain. For “just” flashcards: no gain.
deck.reset()Gone! A big time waster. Called way too often, did way too much and was not neccessary, obviously.
clayout.pycard “cache” bloat gone
main.pysnappy GUI with single card prefetching
setupErrorHandler()disabled; I want the tracebacks on the console
main.pyWhat is state “auto”? Strange name. Renamed to “reload”. That state is close to "initial": removed code repetition.
main.pyMy new scheduler has no “learn more”/“early review”. When you’re done with 38.000 cards, you know! leech handling code anymore. If something comes up too often and you don’t like it: suspend (shortcut “0”). If you do like it: schedule it further away (button 2, 3, 4), despite not knowing it (yet). ripped out.
moveToState()right-click reload does not trigger card refetch any more.
moveToState()No “timeboxing” (automatic review-stop after x minutes or cards) any more.
currentCard.startTimer()now in, but time taking should not be done in anyway..., revCount(), failedCount()those are a function now, because they work a little
DB code (where I touched it) it the sqlalchemy way: simpler code, less clutter. Example:
isEmpty(self): return not self.s.query(Card).first()
youngCardCount(self): return self.s.query(Card).filter(Card.interval < MATURE_THRESHOLD).filter(Card.reps != 0).count()
deck._dailyStatsHello? Do we have an underscore here? If you want those statistics, get them yourself! least print a stack trace of those silently eaten exceptions of all kind. This is exactly what QTimer.singleShot() does
unused code here and thereremoved
deck.pyremoved all data doubling/“caching” and it’s cumbersome maintenance
audiochange is also in Panki plugin: audio does not hang over into the next card. Played correctly for question or answer and does not replay by itself. Replay via button or shortcut F3 is done immediately. cleanup! Look at it. I call that art! :-)
view.pyAlso in Panki plugin: removed cumbersome HTML mangling. input to Unicode NFC before comparing
genFuzz()I streamlined a bunch of two-lines-used-once functions, but this one wasn’t even used...
htmlAnswer()/htmlQuestion()Most of it is part of the Pank plugin. I made one function out of it “questionanswer()”, which does: get the card template, get the card fields, put the fields in the card (“render()”). Done!
And look at this pearl here: self.fact.fieldsDict.copy() to get the fields. – So much nicer then that ugly original multiline construct to get them. And all that done with two lines of sqlalchemy configuration including r/w support! (I would call it “fact.fields” of course, but that name was taken.) to where it belongs...
schedulerRemoved a lot of scheduler code mixed into My simple new scheduler is in The original getCard() is now passed to the scheduler, and the ~50 lines answerCard() is reduced to well-arranged 10 lines including a call to updateAnsweredCard() in the scheduler
The scheduler is responsible of it’s own management, finding the next card and rescheduling answered cards. Nothing else.

The new scheduler takes a constant mix of 20% new cards and 80% review (when available). Failed cards are not rescheduled, but their statistics and scheduling householding is updated. To avoid them popping up directly again, a FIFO of the last 20 seen facts is consulted. This simple FIFO mechanism also solves sibling spacing with no extra efforts.

progressHandlerThat handler was called way too often. Instead of globally registering it, it should only be registered in those cases where long DB work is expected. – As I don’t have long DB work, I disabled it.
deck.pysessionmaker() is now called with expire_on_commit=False. That was a speed boost. As Anki tries hard to keep the DB under it’s control (locked), there is nobody who could possibly have changed the DB behind Anki’s back. So after a commit(), in a new transaction, we get no new data, so there is no need to reread from the DB (no need to expunge).
upgrade codeDefinitively the wrong place in But as the Panki deck is up-to-date, no need to have that code. Removed.
deck.pyI have definitively overdone myself here removing code: if Panki doesn’t need it, and I considered those parts at the wrong place or doing it the wrong way, I removed it.
_attach()One of those called-once functions with smaller footprint if inlined. Anki used sessionmaker() with autoflush=False and autocommit=True here, but then in it started a transaction immediately. – If I always want a transaction going: just use autocommit=False! ... and we get the possibility for autoflush=True back. By the way, both are default in sqlalchemy these days... the help of the association_proxy and the collection_class from sqlalchemy, setitem turn into: self.fieldsDict[key] = value. Very nice.
loadPanki=Falseyou still need the Panki Plugins with this patch, but the “main” Panki plugin is already incorporated here and needs instructions to not “patch from inside”.
MplayerReaderCompletely superfluous: putting effort into reading the output of mplayer in order to discard it? Pipe it directly to /dev/null instead.
sound.pysome restructuring
stats.pyglobalStats(), dailyStats()... almost did the same