Giter VIP home page Giter VIP logo

Comments (18)

RumovZ avatar RumovZ commented on June 15, 2024

I regularly encounter this when developing, it even seems to happen more frequently now than compared to a few months ago. However, I have never had the issue when launching the binaries. When running from source I don't have a way to reproduce it reliably, either, but rerunning a couple of times usually does the trick.
Once the issue has occured, nothing except restarting seems to help.

I'm not proficient in web development or Anki's webview code, so I have no idea how to go about debugging. Sending the file in mediarsv.py seems successful to me and reloading in Chrome DevTools does nothing to the missing css.
If you want me to try anything just let me know.

from anki.

dae avatar dae commented on June 15, 2024

Does running with ./scripts/runopt make a difference to how often it happens? Wondering if it's a race condition

Does the css file show up in the list of page resources when viewing the buggy page with the devtools?

from anki.

RumovZ avatar RumovZ commented on June 15, 2024

Does running with ./scripts/runopt make a difference to how often it happens? Wondering if it's a race condition

That will be hard to quantify, but I just gave it a go and immediately encountered the issue.

Does the css file show up in the list of page resources when viewing the buggy page with the devtools?

No, there's no css at all, but I just realised, if I inspect the bottom toolbar page, there is not only toolbar-bottom.css, but also toolbar.css and webview.css.

from anki.

dae avatar dae commented on June 15, 2024

The top area should have toolbar.css and webview.css when viewing the Sources tab:
Screen Shot 2021-03-16 at 9 02 33 pm

Neither of those are showing up, but they show up in the requests with ANKIDEV? Is _onHeight() being called for the top toolbar? Does commenting out acceptNavigationRequest make any difference? Any difference when loading a profile directly vs opening up the profiles screen first?

from anki.

RumovZ avatar RumovZ commented on June 15, 2024

Neither of those are showing up, but they show up in the requests with ANKIDEV?

Exactly:

grafik

Is _onHeight() being called for the top toolbar?

It gets called the same number of times, twice for loading the main page. Only the arguments differ (not surprising, I assume).
Broken (one example, height is not uniform here):
grafik
Ok:
grafik

Does commenting out acceptNavigationRequest make any difference?

Where do I do that? I tried returning immediately in webview.py/acceptNavigationRequest(), that didn't make a difference.

Any difference when loading a profile directly vs opening up the profiles screen first?

It seems that way. I got the issue the first time I ran with a profile name, but not once in my countless trials after that, even when I started switching the profile at runtime.
It never takes more than a few trials to trigger the issue when I run without the p paramter, so I think it could be called statistically significant.

from anki.

dae avatar dae commented on June 15, 2024

The (no domain) section has two entries, but I'm only seeing one. Do you see only one entry when the problem doesn't occur? I wonder what the colour represents? Was the same text returned both times? If you comment out the .redraw() line in the deck browser, does that fix it? Maybe we're loading the HTML, then loading it again before the first load finishes, resulting in a partially loaded page.

from anki.

RumovZ avatar RumovZ commented on June 15, 2024

Indeed, the violet entry only seems to occur when the CSS is missing. The two files show different ports then.
According to this answer, violet means CSS and grey means HTML. Curious.

<!doctype html>
<html class="">
<head>
    <title>top toolbar</title>
<base href="http://127.0.0.1:55000/"><link rel="stylesheet" type="text/css" href="http://127.0.0.1:55000/_anki/css/webview.css"><style>
body { zoom: 1; background: #f0f0f0; direction: ltr; font-size:12px;font-family:"Segoe UI"; }
button { font-family:"Segoe UI"; }
:focus { outline: 1px solid #0078d7; }
:root { --window-bg: #f0f0f0 }
:root[class*=night-mode] { --window-bg: #f0f0f0 }
</style><link rel="stylesheet" type="text/css" href="http://127.0.0.1:55000/_anki/css/toolbar.css"><script src="http://127.0.0.1:55000/_anki/js/webview.js"></script>
<script src="http://127.0.0.1:55000/_anki/js/webview.js"></script>
<script src="http://127.0.0.1:55000/_anki/js/vendor/jquery.min.js"></script>
<script src="http://127.0.0.1:55000/_anki/js/toolbar.js"></script>
</head>

<body class="isWin">
<center id=outer>
<table id=header width=100%>
<tr>
<td class=tdcenter align=center><a class=hitem tabindex="-1" aria-label="Decks" title="Shortcut key: ⁨D⁩" id="decks" href=# onclick="return pycmd('decks')">Decks</a>
<a class=hitem tabindex="-1" aria-label="Add" title="Shortcut key: ⁨A⁩" id="add" href=# onclick="return pycmd('add')">Add</a>
<a class=hitem tabindex="-1" aria-label="Browse" title="Shortcut key: ⁨B⁩" id="browse" href=# onclick="return pycmd('browse')">Browse</a>
<a class=hitem tabindex="-1" aria-label="Stats" title="Shortcut key: ⁨T⁩" id="stats" href=# onclick="return pycmd('stats')">Stats</a>

<a class=hitem tabindex="-1" aria-label="Sync" title="Shortcut key: ⁨Y⁩" id="sync" href=# onclick="return pycmd('sync')">Sync
<img id=sync-spinner src='/_anki/imgs/refresh.svg'>        
</a></td>
</tr></table>
</center>
</body>
</html>
<!doctype html>
<html class="">
<head>
    <title>top toolbar</title>
<base href="http://127.0.0.1:54822/"><link rel="stylesheet" type="text/css" href="http://127.0.0.1:54822/_anki/css/webview.css"><style>
body { zoom: 1; background: #f0f0f0; direction: ltr; font-size:12px;font-family:"Segoe UI"; }
button { font-family:"Segoe UI"; }
:focus { outline: 1px solid #0078d7; }
:root { --window-bg: #f0f0f0 }
:root[class*=night-mode] { --window-bg: #f0f0f0 }
</style><link rel="stylesheet" type="text/css" href="http://127.0.0.1:54822/_anki/css/toolbar.css"><script src="http://127.0.0.1:54822/_anki/js/webview.js"></script>
<script src="http://127.0.0.1:54822/_anki/js/webview.js"></script>
<script src="http://127.0.0.1:54822/_anki/js/vendor/jquery.min.js"></script>
<script src="http://127.0.0.1:54822/_anki/js/toolbar.js"></script>
</head>

<body class="isWin">
<center id=outer>
<table id=header width=100%>
<tr>
<td class=tdcenter align=center><a class=hitem tabindex="-1" aria-label="Decks" title="Shortcut key: ⁨D⁩" id="decks" href=# onclick="return pycmd('decks')">Decks</a>
<a class=hitem tabindex="-1" aria-label="Add" title="Shortcut key: ⁨A⁩" id="add" href=# onclick="return pycmd('add')">Add</a>
<a class=hitem tabindex="-1" aria-label="Browse" title="Shortcut key: ⁨B⁩" id="browse" href=# onclick="return pycmd('browse')">Browse</a>
<a class=hitem tabindex="-1" aria-label="Stats" title="Shortcut key: ⁨T⁩" id="stats" href=# onclick="return pycmd('stats')">Stats</a>

<a class=hitem tabindex="-1" aria-label="Sync" title="Shortcut key: ⁨Y⁩" id="sync" href=# onclick="return pycmd('sync')">Sync
<img id=sync-spinner src='/_anki/imgs/refresh.svg'>        
</a></td>
</tr></table>
</center>
</body>
</html>

Commenting out the redraw line doesn't help.

from anki.

dae avatar dae commented on June 15, 2024

I'd expect the port numbers to change over multiple program invocations, but are you saying they were different in the first and second request in a single Anki session? Does setting the env var ANKI_API_PORT to 40000 change the behaviour at all?

from anki.

RumovZ avatar RumovZ commented on June 15, 2024

Yes, those are the files from a single Anki session. At least I thought that. Now when I try that again, the second file looks like this:

:root{--text-fg: black;--window-bg: #ececec;--frame-bg: white;--border: #aaa;--medium-border: #b6b6b6;--faint-border: #e7e7e7;--link: #00a;--review-count: #0a0;--new-count: #00a;--learn-count: #c35617;--zero-count: #ddd;--slightly-grey-text: #333;--highlight-bg: #77ccff;--highlight-fg: black;--disabled: #777;--flag1-fg: #c35617;--flag2-fg: #ffb347;--flag3-fg: #0a0;--flag4-fg: #77ccff;--flag1-bg: #ffaaaa;--flag2-bg: #ffb347;--flag3-bg: #82e0aa;--flag4-bg: #85c1e9;--buried-fg: #aaaa33;--suspended-fg: #dd0;--suspended-bg: #ffffb2;--marked-bg: #cce;--tooltip-bg: #fcfcfc}:root[class*=night-mode]{--text-fg: white;--window-bg: #2f2f31;--frame-bg: #3a3a3a;--border: #777;--medium-border: #444;--faint-border: #29292b;--link: #77ccff;--review-count: #5ccc00;--new-count: #77ccff;--learn-count: #ff935b;--zero-count: #444;--slightly-grey-text: #ccc;--highlight-bg: #77ccff;--highlight-fg: white;--disabled: #777;--flag1-fg: #ffaaaa;--flag2-fg: #ffb347;--flag3-fg: #82e0aa;--flag4-fg: #85c1e9;--flag1-bg: #aa5555;--flag2-bg: #aa6337;--flag3-bg: #33a055;--flag4-bg: #3581a9;--buried-fg: #777733;--suspended-fg: #ffffb2;--suspended-bg: #aaaa33;--marked-bg: #77c;--tooltip-bg: #272727}*{box-sizing:border-box}body{font-family:Helvetica,Arial;color:var(--text-fg);background:var(--window-bg);margin:1em}a{color:var(--link);text-decoration:none}.isWin button{font-size:12px}.isMac button{font-size:13px}.isLin button{font-size:14px;-webkit-appearance:none;border-radius:3px;padding:5px;border:1px solid var(--border)}.nightMode button{-webkit-appearance:none;color:var(--text-fg);background:linear-gradient(0deg, #555555 0%, #656565 100%);box-shadow:0 0 3px #222;border:1px solid #646464;border-radius:2px;padding:10px;padding-top:3px;padding-bottom:3px}.nightMode button:hover{background:#656565}.isMac.nightMode.macos-dark-mode button:not(.linkb){background:#656565;box-shadow:0 1px 2px #222;border-top-color:#848484;border-top-width:.5px;border-bottom:0;border-left:0;border-right:0;padding-top:2px;padding-bottom:2px;padding-left:15px;padding-right:15px;color:#e5e5e5}*{box-sizing:content-box}body{margin:2em;overscroll-behavior:none}h1{margin-bottom:.2em}.nightMode::-webkit-scrollbar{background:var(--window-bg)}.nightMode::-webkit-scrollbar:horizontal{height:12px}.nightMode::-webkit-scrollbar:vertical{width:12px}.nightMode::-webkit-scrollbar-thumb{background:#656565;border-radius:8px}.nightMode::-webkit-scrollbar-thumb:horizontal{min-width:50px}.nightMode::-webkit-scrollbar-thumb:vertical{min-height:50px}

The two files look the same in Chrome, but I think Chrome is getting confused because they have the same name and always opens the first. What I've posted here is what I see when I download the files and open them in Notepad.
Now I'm wondering if I made a mistake yesterday. That would explain why one is coloured violet because it really contains CSS whereas the other one with the same name contains HTML.

I assume ANKI_API_PORT is an environment variable? Setting it doesn't seem to make a difference.

from anki.

dae avatar dae commented on June 15, 2024

When you say "download the files", do you mean you are surfing to localhost:xxxxx/_anki/css/... something? What I'm more interested in is the two entries in the (no domain) section. Maybe this is a bug in Qt's setHtml() call. Does the following patch make a difference?

diff --git a/qt/aqt/mediasrv.py b/qt/aqt/mediasrv.py
index 9f3177a6e..ad5d79e51 100644
--- a/qt/aqt/mediasrv.py
+++ b/qt/aqt/mediasrv.py
@@ -98,6 +98,9 @@ class MediaServer(threading.Thread):
 
 @app.route("/<path:pathin>", methods=["GET", "POST"])
 def allroutes(pathin: str) -> Response:
+    if pathin == "_anki/toolbar.html":
+        return handle_toolbar()
+
     try:
         directory, path = _redirectWebExports(pathin)
     except TypeError:
@@ -300,3 +303,42 @@ def handle_post(path: str) -> Response:
         )
 
     return response
+
+def handle_toolbar() -> Response:
+    from aqt import mw
+    server = mw.serverURL()
+    return flask.make_response(f"""
+<!doctype html>
+<html class="night-mode">
+<head>
+<title>top toolbar</title>
+<base href="{server}"><link rel="stylesheet" type="text/css" href="{server}_anki/css/webview.css"><style>
+body {{ zoom: 1; background: #2f2f31; direction: ltr; font-size:15px;font-family:"Helvetica"; }}
+
+button {{ -webkit-appearance: none; background: #fff; border: 1px solid #ccc;
+border-radius:5px; font-family: Helvetica }}
+:root {{ --window-bg: #2f2f31 }}
+:root[class*=night-mode] {{ --window-bg: #2f2f31 }}
+    </style><link rel="stylesheet" type="text/css" href="{server}_anki/css/toolbar.css"><script src="{server}_anki/js/webview.js"></script>
+<script src="{server}_anki/js/webview.js"></script>
+<script src="{server}_anki/js/vendor/jquery.min.js"></script>
+<script src="{server}_anki/js/toolbar.js"></script>
+</head>
+
+<body class="isMac nightMode night_mode">
+<center id=outer>
+<table id=header width=100%>
+<tr>
+<td class=tdcenter align=center><a class=hitem tabindex="-1" aria-label="Decks" title="Shortcut key: ⁨D⁩" id="decks" href=# onclick="return pycmd('decks')">Decks</a>
+<a class=hitem tabindex="-1" aria-label="Add" title="Shortcut key: ⁨A⁩" id="add" href=# onclick="return pycmd('add')">Add</a>
+<a class=hitem tabindex="-1" aria-label="Browse" title="Shortcut key: ⁨B⁩" id="browse" href=# onclick="return pycmd('browse')">Browse</a>
+<a class=hitem tabindex="-1" aria-label="Stats" title="Shortcut key: ⁨T⁩" id="stats" href=# onclick="return pycmd('stats')">Stats</a>
+
+<a class=hitem tabindex="-1" aria-label="Sync" title="Shortcut key: ⁨Y⁩" id="sync" href=# onclick="return pycmd('sync')">Sync
+<img id=sync-spinner src='/_anki/imgs/refresh.svg'>
+</a></td>
+</tr></table>
+</center>
+</body>
+</html>
+""")
\ No newline at end of file
diff --git a/qt/aqt/toolbar.py b/qt/aqt/toolbar.py
index 5e3c7505b..210869b24 100644
--- a/qt/aqt/toolbar.py
+++ b/qt/aqt/toolbar.py
@@ -44,12 +44,8 @@ class Toolbar:
         web_context = web_context or TopToolbar(self)
         link_handler = link_handler or self._linkHandler
         self.web.set_bridge_command(link_handler, web_context)
-        self.web.stdHtml(
-            self._body % self._centerLinks(),
-            css=["css/toolbar.css"],
-            js=["js/webview.js", "js/vendor/jquery.min.js", "js/toolbar.js"],
-            context=web_context,
-        )
+        self.web.set_open_links_externally(False)
+        self.web.load_url(QUrl(f"{self.mw.serverURL()}_anki/toolbar.html"))
         self.web.adjustHeightToFit()
 
     def redraw(self) -> None:

from anki.

RumovZ avatar RumovZ commented on June 15, 2024

When you say "download the files", do you mean you are surfing to localhost:xxxxx/_anki/css/... something? What I'm more interested in is the two entries in the (no domain) section.

Yes, I was talking about these two entries. You can open them in Chrome or download them. Now, in Chrome it looks like they contain the same data, but as I said above, that seems to be a bug in Chrome for files with the same name and the actual content of the second file is different as can be seen in the downloaded file.

mVlepy8Euy

self.web.load_url(QUrl(f"{self.mw.serverURL()}_anki/toolbar.html"))

Should be self.web.load(...) I think.

With the patch, instead of just the CSS the whole toolbar is missing sometimes.

grafik

grafik

from anki.

dae avatar dae commented on June 15, 2024

load_url() should be present in the latest main

One more thing to try:

diff --git a/qt/aqt/main.py b/qt/aqt/main.py
index f8d09ff1d..edd03722e 100644
--- a/qt/aqt/main.py
+++ b/qt/aqt/main.py
@@ -143,7 +143,6 @@ class AnkiQt(QMainWindow):
         try:
             self.setupUI()
             self.setupAddons(args)
-            self.finish_ui_setup()
         except:
             showInfo(tr(TR.QT_MISC_ERROR_DURING_STARTUP, val=traceback.format_exc()))
             sys.exit(1)
@@ -161,6 +160,7 @@ class AnkiQt(QMainWindow):
             fn = self.setupProfile

         def on_window_init() -> None:
+            self.finish_ui_setup()
             fn()
             gui_hooks.main_window_did_init()

If that doesn't help, does changing 10 to 500 make a difference?

from anki.

RumovZ avatar RumovZ commented on June 15, 2024

What 10? The other thing didn't work.

from anki.

dae avatar dae commented on June 15, 2024

Directly below on_window_init() is a 10ms timer

from anki.

RumovZ avatar RumovZ commented on June 15, 2024

Looks like that did the trick. 😮
As always, it's hard to tell with such a flaky issue, so I'll try some more later.

from anki.

RumovZ avatar RumovZ commented on June 15, 2024

So the issue occured only once with the timer set to 500 ms and I tried a lot of times. I also tried with the timer set to 1 ms and couldn't repdruce the issue at all, though I didn't try that quite as often. (Starting to think I have to log the trials and analyse them statiscally...)
That would indicate a race condition, wouldn't it?

from anki.

dae avatar dae commented on June 15, 2024

Yeah, I suspect it's a bug in Qt :-( To confirm, that's a 1ms timer w/ the finish_ui_setup() call inside on_window_init()?

from anki.

RumovZ avatar RumovZ commented on June 15, 2024

This one:

diff --git a/qt/aqt/main.py b/qt/aqt/main.py
index f8d09ff1..6035a07b 100644
--- a/qt/aqt/main.py
+++ b/qt/aqt/main.py
@@ -164,7 +164,7 @@ class AnkiQt(QMainWindow):
             fn()
             gui_hooks.main_window_did_init()

-        self.progress.timer(10, on_window_init, False, requiresCollection=False)
+        self.progress.timer(1, on_window_init, False, requiresCollection=False)

     def setupUI(self) -> None:
         self.col = None

from anki.

Related Issues (20)

Recommend Projects

  • React photo React

    A declarative, efficient, and flexible JavaScript library for building user interfaces.

  • Vue.js photo Vue.js

    🖖 Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.

  • Typescript photo Typescript

    TypeScript is a superset of JavaScript that compiles to clean JavaScript output.

  • TensorFlow photo TensorFlow

    An Open Source Machine Learning Framework for Everyone

  • Django photo Django

    The Web framework for perfectionists with deadlines.

  • D3 photo D3

    Bring data to life with SVG, Canvas and HTML. 📊📈🎉

Recommend Topics

  • javascript

    JavaScript (JS) is a lightweight interpreted programming language with first-class functions.

  • web

    Some thing interesting about web. New door for the world.

  • server

    A server is a program made to process requests and deliver data to clients.

  • Machine learning

    Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.

  • Game

    Some thing interesting about game, make everyone happy.

Recommend Org

  • Facebook photo Facebook

    We are working to build community through open source technology. NB: members must have two-factor auth.

  • Microsoft photo Microsoft

    Open source projects and samples from Microsoft.

  • Google photo Google

    Google ❤️ Open Source for everyone.

  • D3 photo D3

    Data-Driven Documents codes.