diff --git a/qt/aqt/mediasrv.py b/qt/aqt/mediasrv.py index aab4e58c0..cd80b816a 100644 --- a/qt/aqt/mediasrv.py +++ b/qt/aqt/mediasrv.py @@ -56,6 +56,7 @@ waitress.wasyncore._DISCONNECTED = waitress.wasyncore._DISCONNECTED.union({EPROT logger = logging.getLogger(__name__) app = flask.Flask(__name__, root_path="/fake") +card_data_app = flask.Flask(__name__, root_path="/fake") flask_cors.CORS(app, resources={r"/*": {"origins": "127.0.0.1"}}) @@ -115,20 +116,35 @@ class MediaServer(threading.Thread): try: desired_host = os.getenv("ANKI_API_HOST", "127.0.0.1") desired_port = int(os.getenv("ANKI_API_PORT") or 0) + desired_card_data_port = int(os.getenv("ANKI_CARD_DATA_PORT") or 0) self.server = create_server( app, host=desired_host, port=desired_port, clear_untrusted_proxy_headers=True, ) + self.card_data_server = create_server( + card_data_app, + host=desired_host, + port=desired_card_data_port, + clear_untrusted_proxy_headers=True, + ) logger.info( "Serving on http://%s:%s", self.server.effective_host, # type: ignore[union-attr] self.server.effective_port, # type: ignore[union-attr] ) + logger.info( + "Serving iframes on http://%s:%s", + self.card_data_server.effective_host, # type: ignore[union-attr] + self.card_data_server.effective_port, # type: ignore[union-attr] + ) self._ready.set() + card_data_thread = threading.Thread(target=self.card_data_server.run) + card_data_thread.start() self.server.run() + card_data_thread.join() except Exception: if not self.is_shutdown: @@ -179,6 +195,19 @@ def favicon() -> Response: return _handle_builtin_file_request(request) +@card_data_app.route("/reviewer-inner.") +def card_data(ext): + if ext not in ("html", "js", "css"): + abort(404) + response = _handle_builtin_file_request( + BundledFileRequest(path=os.path.join("pages", f"reviewer-inner.{ext}")) + ) + print(response.headers) + response.headers["Content-Security-Policy"] = "" + print(response.headers) + return response + + def _mime_for_path(path: str) -> str: "Mime type for provided path/filename." diff --git a/qt/aqt/reviewer.py b/qt/aqt/reviewer.py index f8cb9a754..3e552aedd 100644 --- a/qt/aqt/reviewer.py +++ b/qt/aqt/reviewer.py @@ -1297,7 +1297,8 @@ class SvelteReviewer(Reviewer): # hide the bottom bar self.bottom.web.setHtml("") # main window - self.web.load_sveltekit_page("reviewer") + inner_port = self.mw.mediaServer.card_data_server.effective_port + self.web.load_sveltekit_page(f"reviewer?p={inner_port}") # block default drag & drop behavior while allowing drop events to be received by JS handlers self.web.allow_drops = True self.web.eval("_blockDefaultDragDropBehavior();") diff --git a/ts/routes/reviewer/Reviewer.svelte b/ts/routes/reviewer/Reviewer.svelte index 7c958ecea..15150cb27 100644 --- a/ts/routes/reviewer/Reviewer.svelte +++ b/ts/routes/reviewer/Reviewer.svelte @@ -12,15 +12,27 @@ License: GNU AGPL, version 3 or later; http://www.gnu.org/licenses/agpl.html state.registerIFrame(iframe); state.registerShortcuts(); } + + const innerPort = new URLSearchParams(window.location.search).get("p"); + + $: hostname = innerPort + ? `${window.location.protocol}//${window.location.hostname}:${innerPort}/reviewer-inner.html` + : "/_anki/pages/reviewer-inner.html"; // fallback + + $: sandboxAllowList = + "allow-scripts" + + (new URL(hostname).origin != window.location.origin + ? " allow-same-origin" + : "");