专栏首页0x0001自建 Anki 同步服务器遇到的坑

自建 Anki 同步服务器遇到的坑

一直以来都想着拯救我的 broken English,好准备接下来的六级考试。前段时间在 V2EX 看到一位大神分享了一份实用的英语学习指导 https://github.com/byoungd/English-level-up-tips-for-Chinese,遂被种草。同时我也认识到了自己单词量的匮乏,想通过背单词的方式把基础的词汇攒起来。恰好教程提供了一份「麦克米伦7000高频词」的 Anki 牌组,便打算从这里开始。

添加了一个 6000+ 卡牌的牌组的后果是,媒体文件同步AnkiWeb的时候巨慢无比,毕竟AnkiWeb的服务器远在德国,这也使我催生了搭建自己的 Anki 同步服务器的想法。

参考 手把手教你搭建自己专属的Anki服务器 - 简书 这篇教程,我很快在VPS上把这玩意儿搭建好了,但同步的时候却莫名奇妙出现 500 错误的问题,查看日志,发现了如下的报错信息:

ERROR:root:CollectionThread[/home/anki/anki/collections/qing/collection.anki2]: Unable to uploadChanges(*[], **{}): 'latin-1' codec can't encode characters in position 51-52: ordinal not in range(256)
Traceback (most recent call last):
  File "/usr/local/lib/python2.7/dist-packages/AnkiServer-2.0.6-py2.7.egg/AnkiServer/threading.py", line 99, in _run
    ret = self.wrapper.execute(func, args, kw, return_queue)
  File "/usr/local/lib/python2.7/dist-packages/AnkiServer-2.0.6-py2.7.egg/AnkiServer/collection.py", line 58, in execute
    ret = func(*args, **kw)
  File "/usr/local/lib/python2.7/dist-packages/AnkiServer-2.0.6-py2.7.egg/AnkiServer/apps/sync_app.py", line 651, in run_func
    res = handler_method(**keyword_args)
  File "/usr/local/lib/python2.7/dist-packages/AnkiServer-2.0.6-py2.7.egg/AnkiServer/apps/sync_app.py", line 113, in uploadChanges
    processed_count = self._adopt_media_changes_from_zip(data)
  File "/usr/local/lib/python2.7/dist-packages/AnkiServer-2.0.6-py2.7.egg/AnkiServer/apps/sync_app.py", line 179, in _adopt_media_changes_from_zip
    open(file_path, 'wb').write(file_data)
UnicodeEncodeError: 'latin-1' codec can't encode characters in position 51-52: ordinal not in range(256)

经过测试发现,媒体文件名是全英文的时候不会存在这个问题,当路径中出现中文的时候就会报错。

计算媒体文件夹完整路径的字符串的长度,恰好是50,报错位置是 51-52,也印证了我之前的判断。

搜索各类 py2.7 关于编码问题的文章,研究了一晚上,百思不得其解。。

上午我在本地的 Ubuntu 也搭建了一个测试,竟一切正常。所以问题应该和服务器与本地环境的差异有关。

几经周折,终于发现了问题所在,是Python2在不同操作系统的文件系统编码的差异导致的问题。

本地的系统的文件系统编码是UTF-8

而我的VPS上的系统的文件系统编码是ANSI_X3.4-1968

所以最终我给文件路径加上了一个 UTF-8 编码的转换,解决了这个问题。

具体操作如下:

修改文件 vim /usr/local/lib/python2.7/dist-packages/AnkiServer-2.0.6-py2.7.egg/AnkiServer/apps/sync_app.py 的 176 行

把
file_path = os.path.join(self.col.media.dir(), filename)
改为
file_path = os.path.join(self.col.media.dir(), filename).encode('utf-8')

重新编译 pyc

python -m py_compile /usr/local/lib/python2.7/dist-packages/AnkiServer-2.0.6-py2.7.egg/AnkiServer/apps/sync_app.py

再重启一下服务

supervisorctl restart anki-server

同步恢复正常了。

这改法的缺点是,如果用 pip 升级原来的包的话,原本的记录就没了,之后再考虑重新部署一下吧╮(╯▽╰)╭

第一次近距离感受 py2 的坑,还是很酸爽的233333

搜索的时候发现有不少的哥们也遇到了这个问题

--------------补充--------------- delete删除的部分也会遇到这个问题,重新修改一下即可

参考文章:Python2编码之殇 | nMask's Blog

本文参与腾讯云自媒体分享计划,欢迎正在阅读的你也加入,一起分享。

我来说两句

0 条评论
登录 后参与评论

相关文章

  • Python之dict、set

    Python里面保存数据,使用最多的是数据字典,也称之为dict,这里的dict可以理解为c++里面的map,使用key-value存储,它的查找速度。很快,...

    AsiaYe
  • Python之函数编程(2)

    在上面的命令中,我们定义一个return_sum()的函数,这个函数返回一个sum的函数,sum函数的作用是求一个可迭代对象的所有元素的和,当我们直接调...

    AsiaYe
  • Python之高级性能

    这里需要注意的是,test[0:3]当中并不包含test[3],它的真实含义是,从下标为0的元素开始,直到索引3为止,但是不包含索引3。切记不要理解为连续取3个...

    AsiaYe
  • Python之异常处理

    在程序运行的过程中,难免会出现这样那样的错误,有些错误是我们自己程序编写上有问题,也就是程序员听了会砍人的那句话,"哟,写bug呢!",还有一种是无法预测...

    AsiaYe
  • Python之list、tuple

    前段时间看了看Python,最近在工作中频繁使用,发现自己对Python的掌握还是不够,于是决定,好好整理一阵子关于Python的东西,如果工作当天有更好...

    AsiaYe
  • Python调试方法简介

    在我们写Python的时候,很难保证一次性写完并且不出错,一个程序写完之后,总有各种各样的bug需要修正,这些错误有的可以通过查看错误信息查看,有的则无...

    AsiaYe
  • Python之面向对象

    在Python中,实例的变量名如果以双下划线”__”开头,它就变成了一个私有变量,类似于C++当中的private属性,只有内部可以访问,外部不能访问,...

    AsiaYe
  • Python之函数编程(1)

    第一次接触到这个知识点的时候,我还不是特别适应,内置的函数怎么可以用一个变量来代替?但是python确实是这么做的,这也不妨碍它的顺利执行。举个例子说明...

    AsiaYe
  • Python之面向对象高级编程

    正常情况下,当我们定义了一个class,创建了一个class的实例后,我们可以给该实例绑定任何属性和方法,这就是Python的灵活性,我们先来看看具体的操作...

    AsiaYe
  • Python之高级特性(2)

    加入我们想要生成一个list,它的内容是从1到8的整数,我们可以用list(range(1:9))来进行生成:

    AsiaYe

扫码关注云+社区

领取腾讯云代金券