diff --git a/aqt/addons.py b/aqt/addons.py index 22c0f1435..17a555575 100644 --- a/aqt/addons.py +++ b/aqt/addons.py @@ -410,6 +410,19 @@ Are you sure you want to continue?""" if not os.path.exists(bp): return os.rename(bp, p) + + # Web Exports + ###################################################################### + + _webExports = {} + + def setWebExports(self, module, pattern): + addon = self.addonFromModule(module) + self._webExports[addon] = pattern + + def getWebExports(self, addon): + return self._webExports.get(addon) + # Add-ons Dialog ###################################################################### diff --git a/aqt/main.py b/aqt/main.py index 74d506259..5ef98e1f4 100644 --- a/aqt/main.py +++ b/aqt/main.py @@ -1349,7 +1349,7 @@ Please ensure a profile is open and Anki is not busy, then try again."""), ########################################################################## def setupMediaServer(self): - self.mediaServer = aqt.mediasrv.MediaServer() + self.mediaServer = aqt.mediasrv.MediaServer(self) self.mediaServer.start() def baseHTML(self): diff --git a/aqt/mediasrv.py b/aqt/mediasrv.py index 963f7857a..cd9281ae2 100644 --- a/aqt/mediasrv.py +++ b/aqt/mediasrv.py @@ -9,6 +9,7 @@ import socketserver import socket from anki.utils import devMode import threading +import re # locate web folder in source/binary distribution def _getExportFolder(): @@ -47,7 +48,12 @@ class MediaServer(threading.Thread): _port = None _ready = threading.Event() + def __init__(self, mw, *args, **kwargs): + super().__init__(*args, **kwargs) + self.mw = mw + def run(self): + RequestHandler.mw = self.mw self.server = ThreadedHTTPServer(("127.0.0.1", 0), RequestHandler) self._ready.set() self.server.serve_forever() @@ -62,6 +68,7 @@ class MediaServer(threading.Thread): class RequestHandler(http.server.SimpleHTTPRequestHandler): timeout = 1 + mw = None def do_GET(self): f = self.send_head() @@ -120,12 +127,41 @@ class RequestHandler(http.server.SimpleHTTPRequestHandler): self.log_date_time_string(), format%args)) - # catch /_anki references and rewrite them to web export folder + def _redirectWebExports(self, path): + # catch /_anki references and rewrite them to web export folder targetPath = os.path.join(os.getcwd(), "_anki", "") if path.startswith(targetPath): newPath = os.path.join(_exportFolder, path[len(targetPath):]) return newPath + + # catch /_addons references and rewrite them to addons folder + targetPath = os.path.join(os.getcwd(), "_addons", "") + if path.startswith(targetPath): + try: + addMgr = self.mw.addonManager + except AttributeError: + return path + + addonPath = path[len(targetPath):] + + try: + addon, subPath = addonPath.split(os.path.sep, 1) + except ValueError: + return path + if not addon: + return path + + pattern = addMgr.getWebExports(addon) + if not pattern: + return path + + if not re.fullmatch(pattern, subPath): + return path + + newPath = os.path.join(addMgr.addonsFolder(), addonPath) + return newPath + return path # work around Windows machines with incorrect mime type