tsudoko / anki-sync-server

Self-hosted Anki sync server

Geek Repo:Geek Repo

Github PK Tool:Github PK Tool

Anki 2.1 ignores mysyncserver.py

colonelsmoothie opened this issue · comments

With the latest beta (beta 26), Anki will ignore mysyncserver.py if you leave it in the addons21 folder.

https://apps.ankiweb.net/docs/addons21.html

I followed the instructions and got it working:

  1. Create a folder in addons21, name it anything you want
  2. Within that folder create a file called __init__.py
  3. Inside __init__.py, enter the following lines:
import anki.sync
anki.sync.SYNC_BASE = 'http://127.0.0.1:27701/'
anki.sync.SYNC_MEDIA_BASE = 'http://127.0.0.1:27701/msync/'

After doing this, I'm able to sync.

There are still some issues though. Anki wants to keep doing full syncs and oftentimes says that the database is in an inconsistent state.

There are still some issues though. Anki wants to keep doing full syncs and oftentimes says that the database is in an inconsistent state.

Can you apply the patch below and check if the issues still occur?

diff --git a/AnkiServer/__init__.py b/AnkiServer/__init__.py
index 93d0db4..6a00e7f 100644
--- a/AnkiServer/__init__.py
+++ b/AnkiServer/__init__.py
@@ -16,10 +16,42 @@
 # along with this program.  If not, see <http://www.gnu.org/licenses/>.
 
 import sys, os.path
+import functools
+
+def __mediapatch():
+    """
+    Monkey-patch Anki's MediaManager to ignore the "server" attribute.
+
+    It's needed because MediaManager's __init__(), connect() and close() are
+    close to no-ops when self.col.server is True. If self.col.server is False,
+    Syncer.usnLim() doesn't match entities that are supposed to be sent to the
+    client, thus breaking server→client deck sync.
+    """
+
+    # we sacrifice thread safety here for not having to copy entire function
+    # bodies
+    def noserver(f):
+        @functools.wraps(f)
+        def wrapped(self, *args, **kwargs):
+            orig = self.col.server
+            self.col.server = False
+            ret = f(self, *args, **kwargs)
+            self.col.server = orig
+            return ret
+        return wrapped
+
+    from anki.media import MediaManager
+    orig_init = MediaManager.__init__
+
+    MediaManager.__init__ = functools.wraps(MediaManager.__init__)(lambda self, col, _: orig_init(self, col, False))
+    MediaManager.connect = noserver(MediaManager.connect)
+    MediaManager.close = noserver(MediaManager.close)
+
 # We put the system installed Anki first!
 sys.path.insert(0, "/usr/share/anki")
 # We'll put our bundled Anki after it
 sys.path.insert(1, os.path.join(os.path.dirname(os.path.dirname(__file__)), 'anki-bundled'))
+__mediapatch()
 
 __author__ = "David Snopek <dsnopek@gmail.com>"
 __copyright__ = "Copyright (C) 2013 David Snopek"
diff --git a/AnkiServer/apps/sync_app.py b/AnkiServer/apps/sync_app.py
index e9d2f41..a17f0e6 100644
--- a/AnkiServer/apps/sync_app.py
+++ b/AnkiServer/apps/sync_app.py
@@ -460,6 +460,7 @@ class SyncApp:
             os.rename(temp_db_path, session.get_collection_path())
         finally:
             col.reopen()
+            col.load()
 
         # If everything went fine, run hook_upload if one is defined.
         if self.hook_upload is not None:
@@ -477,6 +478,7 @@ class SyncApp:
             data = open(session.get_collection_path(), 'rb').read()
         finally:
             col.reopen()
+            col.load()
         return data
 
     @wsgify
diff --git a/AnkiServer/collection.py b/AnkiServer/collection.py
index 2d7b046..8e62f98 100644
--- a/AnkiServer/collection.py
+++ b/AnkiServer/collection.py
@@ -75,7 +75,7 @@ class CollectionWrapper:
             else:
                 raise
 
-        col = anki.storage.Collection(self.path)
+        col = anki.storage.Collection(self.path, server=True)
 
         # Do any special setup
         if self.setup_new_collection is not None:
@@ -87,7 +87,7 @@ class CollectionWrapper:
         """Open the collection, or create it if it doesn't exist."""
         if self.__col is None:
             if os.path.exists(self.path):
-                self.__col = anki.storage.Collection(self.path)
+                self.__col = anki.storage.Collection(self.path, server=True)
             else:
                 self.__col = self.__create_collection()
 

I saved the patch to a file called patch, and from the repo directory I ran:

patch -p1 < /home/test/patch

Then, I did sudo pip3 install file+git:///home/test/anki-sync-server and performed the setup as usual.

Now, anki is asking me to do a full sync every time, even when there have been no changes. I still am able to sync, though.

I had to do one more thing. After the pip3 install, I looked in /usr/local/lib/python3.6/dist-packages/AnkiServer/ and noticed the files weren't patched even though I had patched the repository before installing. I applied the patch to those files:
cd /usr/local/lib/python3.6/dist-packages/
git apply /home/test/patch

And then started the server. Syncing works fine now.

Good to know. Since the anki_2_1 branch was originally meant to be used in a pull request for dsnopek/anki-sync-server, I'm not going to apply that patch there since it addresses a different issue, but I've applied it to my master branch.

Hello,

With the latest release of Anki 2.1, I'm getting this error upon sync:

selection_999 496

I think it's due to some changes to the code here:

ankitects/anki@ae46bfa#diff-4aa6d61f17d2ffc142fa31d120f9b3ca

Any thoughts on how to fix this? Anyways, with 2.1 officially released, and the original anki-sync-server project dead, I'll be switching over to your master branch. I've got some questions on setup for that, so I'll open up a new issue.

Thanks

You need to add "%s" somewhere to SYNC_BASE, e.g. SYNC_BASE = "http://localhost:9999/%s". Also note SYNC_MEDIA_BASE is no longer honored, Anki just appends msync/ to SYNC_BASE.

I wouldn't use stable Anki 2.1 with anki-sync-server as of now, ankitects/anki@eb44584 introduced some changes to the protocol and I need to implement them first. I'd recommend syncing with 2.1.0rc1 or lower for now, sorry for the mess.

Syncing with Anki 2.1.0rc2+ should work now.