原创文章,欢迎转载。转载请注明:转载自 祥的博客
原文链接:https://blog.csdn.net/humanking7/article/details/89299138


搭建Anki同步服务器(针对Anki2.0)

针对Anki2.1的版本:https://blog.csdn.net/humanking7/article/details/94999409

0.环境

  • Ubuntu 16.04
  • python2.7.12
  • PC: anki 2.0.52
  • Android: ankiDroid 2.8.4

1.原因

Anki的官方服务器在国外,而且官方资金也不是很充足,导致在国内使用他们的同步服务速度巨慢无比,经常失败。特别是有大量媒体数据需要同步的时候,简直了…

我用梯子都慢的让我崩溃,尤其是我用PC的Anki编辑卡片,用手机Anki学习卡片,所以有了自己搭建Anki同步服务器的想法。

至于Anki是什么,我只能说,我把它当做学英语的一个工具,正在使用中,不过当初为了学习如何使用这玩意儿基本上是花了我半天的时间。这软件很小众,好几年前都知道这东西,不过当时没有耐下心来研究,突然间想背单词了,好好学学英语,而且被知乎大佬安利了好久,终于下定决心要研究一下,没想到,用起来感觉就是神器,不过真的需要捣腾精神。

不过我感觉我开始研究Anki这个软件的那一刻起,已经偏离了学英语的初衷,捂脸逃。

先来立一个flag

  1. 先背六级单词,有2000多个单词;
  2. 再背四级单词,有4000多单词;
  3. 最后被麦克米伦,有6000个单词吧。

这种安排,是基于我的英语水平,这样背诵会有成就感,因为觉得四级的词汇大部分应该都ok,这样背诵估计抵抗心理应该没有那么强吧。

当然这也是我这样觉得的,这些年立下的flag太多了,脸打的生疼。

好了,下面就是正题。

2.安装Anki配置服务器

2.1. 安装AnkiServer

pip install AnkiServer

2.2. 配置AnkiServer

先找到anki的配置文件(找了半天,没有在安装文件夹中找到example.ini,所以直接搜索example.ini

root@qfx:/# updatedb
root@qfx:/# find -name AnkiServer*
./root/.cache/pip/wheels/fb/c8/fc/3795d4e6b83dc7697fdfd7392622a3b5c991cb2f7db11c20c5/AnkiServer-2.0.6-cp27-none-any.whl
./usr/local/lib/python2.7/dist-packages/AnkiServer-2.0.6.dist-info
./usr/local/lib/python2.7/dist-packages/AnkiServer
find: `./run/user/1000/gvfs': 权限不够
root@qfx:/# 

发现文件夹 AnkiServer-2.0.6.dist-infoAnkiServer 中没有配置文件example.ini,所以直接配置文件example.ini

root@qfx:/# find -name example.ini
./usr/local/examples/example.ini
find: `./run/user/1000/gvfs': 权限不够
root@qfx:/# 

example.ini拷贝到我自定义的文件夹中,并重命名为production.ini

root@qfx:~# cp /usr/local/examples/example.ini  ~/anki_code/production.ini
root@qfx:~# cd ~/anki_code/
root@qfx:~/anki_code# ls
production.ini
root@qfx:~/anki_code# vim production.ini

修改production.ini

# 服务器的地址
host = 10.10.123.123

# 允许同步的客户端IP地址,可以枚举每个你允许的IP,也可以设置0.0.0.0 允许任何IP地址连接
# allowed_hosts = 192.168.5.30,192.168.5.40
allowed_hosts = 0.0.0.0

配置文件全文:

[server:main]
use = egg:AnkiServer#server
host = 10.10.123.123
port = 27701

[filter-app:main]
use = egg:Paste#translogger
next = real

[app:real]
use = egg:Paste#urlmap
/ = rest_app
/msync = sync_app
/sync = sync_app

[app:rest_app]
use = egg:AnkiServer#rest_app
data_root = ./collections
allowed_hosts = 0.0.0.0
;logging.config_file = logging.conf

[app:sync_app]
use = egg:AnkiServer#sync_app
data_root = ./collections
base_url = /sync/
base_media_url = /msync/
session_db_path = ./session.db
auth_db_path = ./auth.db

2.3. 添加AnkiServer账户

这个账户相当于AnkiWeb上的账户,不同客户端同步时候要用到。

添加账户ankiQfx(自己自定义),根据提示输入密码:

root@qfx:~/anki_code# ankiserverctl.py  adduser ankiQfx
Enter password for ankiQfx: 
Password: 
root@qfx:~/anki_code# 

2.4. 配置防火墙

firewall-cmd --list-all
firewall-cmd --permanent --add-port=27701/tcp
firewall-cmd --reload

3. 运行AnkiServer及解决问题

root@qfx:~/anki_code# ankiserverctl.py -help
usage: /usr/local/bin/ankiserverctl.py <command> [<args>]

Commands:
  start [configfile] - start the server
  debug [configfile] - start the server in debug mode
  stop               - stop the server
  adduser <username> - add a new user
  deluser <username> - delete a user
  lsuser             - list users
  passwd <username>  - change password of a user

先测试一下AnkiServer

运行命令:

ankiserverctl.py debug [configfile]

3.1. 问题1

root@qfx:~/anki_code# ankiserverctl.py debug production.ini 
Traceback (most recent call last):
  File "/usr/local/bin/paster", line 11, in <module>
    sys.exit(run())
  File "/usr/local/lib/python2.7/dist-packages/paste/script/command.py", line 101, in run
    command = commands[command_name].load()
  File "/usr/lib/python2.7/dist-packages/pkg_resources/__init__.py", line 2228, in load
    self.require(*args, **kwargs)
  File "/usr/lib/python2.7/dist-packages/pkg_resources/__init__.py", line 2245, in require
    items = working_set.resolve(reqs, env, installer)
  File "/usr/lib/python2.7/dist-packages/pkg_resources/__init__.py", line 808, in resolve
    if not req_extras.markers_pass(req):
  File "/usr/lib/python2.7/dist-packages/pkg_resources/__init__.py", line 993, in markers_pass
    return not req.marker or any(extra_evals) or req.marker.evaluate()
  File "/usr/lib/python2.7/dist-packages/pkg_resources/_vendor/packaging/markers.py", line 278, in evaluate
    return _evaluate_markers(self._markers, current_environment)
  File "/usr/lib/python2.7/dist-packages/pkg_resources/_vendor/packaging/markers.py", line 203, in _evaluate_markers
    lhs_value = _get_env(environment, lhs.value)
  File "/usr/lib/python2.7/dist-packages/pkg_resources/_vendor/packaging/markers.py", line 185, in _get_env
    "{0!r} does not exist in evaluation environment.".format(name)
pkg_resources._vendor.packaging.markers.UndefinedEnvironmentName: 'extra' does not exist in evaluation environment.
root@qfx:~/anki_code# 

原因:

setuptools版本太低(我的是20.7.0 ,实际上应该要升级到35.0.1)

解决:

pip install --upgrade setuptools
root@qfx:~/anki_code# pip install --upgrade setuptools
Collecting setuptools
  Downloading https://files.pythonhosted.org/packages/c8/b0/cc6b7ba28d5fb790cf0d5946df849233e32b8872b6baca10c9e002ff5b41/setuptools-41.0.0-py2.py3-none-any.whl (575kB)
    100% |████████████████████████████████| 583kB 16kB/s 
Installing collected packages: setuptools
  Found existing installation: setuptools 20.7.0
    Uninstalling setuptools-20.7.0:
      Successfully uninstalled setuptools-20.7.0
Successfully installed setuptools-41.0.0
root@qfx:~/anki_code# 

3.2. 问题2

root@qfx:~/anki_code# ankiserverctl.py debug production.ini 
Traceback (most recent call last):
  File "/usr/local/bin/paster", line 11, in <module>
    sys.exit(run())
  File "/usr/local/lib/python2.7/dist-packages/paste/script/command.py", line 102, in run
    invoke(command, command_name, options, args[1:])
  File "/usr/local/lib/python2.7/dist-packages/paste/script/command.py", line 141, in invoke
    exit_code = runner.run(args)
  File "/usr/local/lib/python2.7/dist-packages/paste/script/command.py", line 236, in run
    result = self.command()
  File "/usr/local/lib/python2.7/dist-packages/paste/script/serve.py", line 284, in command
    relative_to=base, global_conf=vars)
  File "/usr/local/lib/python2.7/dist-packages/paste/script/serve.py", line 329, in loadapp
    **kw)
  File "/usr/local/lib/python2.7/dist-packages/paste/deploy/loadwsgi.py", line 253, in loadapp
    return loadobj(APP, uri, name=name, **kw)
  File "/usr/local/lib/python2.7/dist-packages/paste/deploy/loadwsgi.py", line 278, in loadobj
    return context.create()
  File "/usr/local/lib/python2.7/dist-packages/paste/deploy/loadwsgi.py", line 715, in create
    return self.object_type.invoke(self)
  File "/usr/local/lib/python2.7/dist-packages/paste/deploy/loadwsgi.py", line 223, in invoke
    next_app = context.next_context.create()
  File "/usr/local/lib/python2.7/dist-packages/paste/deploy/loadwsgi.py", line 715, in create
    return self.object_type.invoke(self)
  File "/usr/local/lib/python2.7/dist-packages/paste/deploy/loadwsgi.py", line 150, in invoke
    **context.local_conf)
  File "/usr/local/lib/python2.7/dist-packages/paste/deploy/util.py", line 55, in fix_call
    val = callable(*args, **kw)
  File "/usr/local/lib/python2.7/dist-packages/paste/urlmap.py", line 31, in urlmap_factory
    app = loader.get_app(app_name, global_conf=global_conf)
  File "/usr/local/lib/python2.7/dist-packages/paste/deploy/loadwsgi.py", line 356, in get_app
    name=name, global_conf=global_conf).create()
  File "/usr/local/lib/python2.7/dist-packages/paste/deploy/loadwsgi.py", line 368, in app_context
    APP, name=name, global_conf=global_conf)
  File "/usr/local/lib/python2.7/dist-packages/paste/deploy/loadwsgi.py", line 459, in get_context
    section)
  File "/usr/local/lib/python2.7/dist-packages/paste/deploy/loadwsgi.py", line 481, in _context_from_use
    object_type, name=use, global_conf=global_conf)
  File "/usr/local/lib/python2.7/dist-packages/paste/deploy/loadwsgi.py", line 412, in get_context
    global_conf=global_conf)
  File "/usr/local/lib/python2.7/dist-packages/paste/deploy/loadwsgi.py", line 302, in loadcontext
    global_conf=global_conf)
  File "/usr/local/lib/python2.7/dist-packages/paste/deploy/loadwsgi.py", line 334, in _loadegg
    return loader.get_context(object_type, name, global_conf)
  File "/usr/local/lib/python2.7/dist-packages/paste/deploy/loadwsgi.py", line 625, in get_context
    object_type, name=name)
  File "/usr/local/lib/python2.7/dist-packages/paste/deploy/loadwsgi.py", line 651, in find_egg_entry_point
    possible.append((entry.load(), protocol, entry.name))
  File "/usr/local/lib/python2.7/dist-packages/pkg_resources/__init__.py", line 2434, in load
    return self.resolve()
  File "/usr/local/lib/python2.7/dist-packages/pkg_resources/__init__.py", line 2440, in resolve
    module = __import__(self.module_name, fromlist=['__name__'], level=0)
  File "/usr/local/lib/python2.7/dist-packages/AnkiServer/apps/sync_app.py", line 32, in <module>
    import anki
ImportError: No module named anki

这是发现没有安装Anki,于是乎我想到了,AnkiServerAnki是不一样的,于是乎先得给我的服务器上装一个Anki(我一般用Windows上的anki编辑单词,用手机上的anki进行学习背诵,Linux上的anki讲真,没用过)

先去下载ankiLinux版本,然后解压安装:

# 下载anki
wget https://apps.ankiweb.net/downloads/archive/anki-2.0.52-i386.tar.bz2

# 解压
tar -xjvf anki-2.0.52-i386.tar.bz2

# 进入解压目录的bin目录
cd anki-2.0.52/bin/

# 安装anki
apt install anki

3.3. 成功测试,并进行运行

现在再来测试一下(终于成功了)

root@qfx:~/anki_code# ankiserverctl.py debug production.ini 
Starting server in PID 23912.
serving on http://10.70.166.156:27701

现在就可以运行AnkiServer

root@qfx:~/anki_code# ankiserverctl.py start ./production.ini 
root@qfx:~/anki_code#

4. PC端配置(Windows)

Anki界面

文件夹界面

新建一个python脚本,命名为mysyncserver.py在里面填入以下内容:

# just for sync -- add by Qfx
import anki.sync

# 服务器地址和端口号
serverAddr = 'http://10.70.166.156:27701/'

anki.sync.SYNC_BASE = serverAddr
anki.sync.SYNC_MEDIA_BASE = serverAddr + 'msync/'

登录账号

登录后就可以愉快的同步了,我设在了局域网里,非常快。

5. AnkiDroid端配置

配置
记住是http不是https,刚开始我就在这里懵逼了一段时间

登录账号2

6.iOS上

由于在App Store上看到ankiiOS版168元,所以就放弃了,虽然觉得用iPad背单词估计效率更高一点(受干扰,而且我的卡片内容很多,在平板上显示的比较全面),不过还是贫穷限制了想象力。

7.补充 - 防火墙相关配置

2019.5.2日补充,停电了,服务器重启,重启AnkiSambaFTP服务器后,发现只有Anki可以用,主要原因就是我当初没有给SambaFTP配置防火墙,当时配置了AnkiServer发现他们用不了之后,就简单粗暴的把防火墙关了,所以留下了隐患,现在把配置防火墙的代码贴出来:

# 永久开放 ftp 服務:
# firewall-cmd --add-service=ftp --permanent 
# 关闭ftp服务:
# firewall-cmd --remove-service=ftp --permanent

# 放开21端口
firewall-cmd --zone=public --add-port=21/tcp --permanent

# 开放samba端口
firewall-cmd --zone=public --add-port=139/tcp --permanent
firewall-cmd --zone=public --add-port=445/tcp --permanent
firewall-cmd --zone=public --add-port=137/udp --permanent
firewall-cmd --zone=public --add-port=138/udp --permanent

# 重新加载firewall配置
firewall-cmd --reload

PS: 为什么CSND MarkdownShell的高亮颜色这么丑!在下真的无法直视。。。


OK!
以上,Enjoy~


赞赏码New

Logo

更多推荐