image support

This commit is contained in:
Damien Elmes 2016-07-07 23:39:48 +10:00
parent 7d0eb6dd39
commit a8e2f992c8
7 changed files with 83 additions and 18 deletions

View file

@ -15,7 +15,7 @@ import aqt.forms
from anki.utils import fmtTimeSpan, ids2str, stripHTMLMedia, isWin, intTime, isMac
from aqt.utils import saveGeom, restoreGeom, saveSplitter, restoreSplitter, \
saveHeader, restoreHeader, saveState, restoreState, applyStyles, getTag, \
showInfo, askUser, tooltip, openHelp, showWarning, shortcut, getBase, mungeQA
showInfo, askUser, tooltip, openHelp, showWarning, shortcut, mungeQA
from anki.hooks import runHook, addHook, remHook
from aqt.webview import AnkiWebView
from aqt.toolbar import Toolbar
@ -1089,7 +1089,7 @@ where id in %s""" % ids2str(sf))
txt = c.a()
txt = re.sub("\[\[type:[^]]+\]\]", "", txt)
ti = lambda x: x
base = getBase(self.mw.col)
base = self.mw.baseHTML()
self._previewWeb.stdHtml(
ti(mungeQA(self.col, txt)), self.mw.reviewer._styles(),
bodyClass="card card%d" % (c.ord+1), head=base,

View file

@ -8,7 +8,7 @@ from aqt.qt import *
from anki.consts import *
import aqt
from anki.sound import playFromText, clearAudioQueue
from aqt.utils import saveGeom, restoreGeom, getBase, mungeQA,\
from aqt.utils import saveGeom, restoreGeom, mungeQA,\
showInfo, askUser, getOnlyText, \
showWarning, openHelp, downArrow
from anki.utils import isMac, isWin, joinFields
@ -225,7 +225,7 @@ Please create a new card type first."""))
def renderPreview(self):
c = self.card
ti = self.maybeTextInput
base = getBase(self.mw.col)
base = self.mw.baseHTML()
self.tab['pform'].frontWeb.stdHtml(
ti(mungeQA(self.mw.col, c.q(reload=True))), self.mw.reviewer._styles(),
bodyClass="card card%d" % (c.ord+1), head=base),

View file

@ -14,7 +14,7 @@ import anki.sound
from anki.hooks import runHook, runFilter
from aqt.sound import getAudio
from aqt.webview import AnkiWebView
from aqt.utils import shortcut, showInfo, showWarning, getBase, getFile, \
from aqt.utils import shortcut, showInfo, showWarning, getFile, \
openHelp, tooltip, downArrow
import aqt
import anki.js
@ -370,7 +370,7 @@ class Editor(object):
</div>
""" % dict(flds=_("Fields"), cards=_("Cards"))
self.web.stdHtml(_html % (
getBase(self.mw.col), anki.js.jquery,
self.mw.baseHTML(), anki.js.jquery,
topbuts,
_("Show Duplicates")))

View file

@ -18,6 +18,7 @@ import aqt.progress
import aqt.webview
import aqt.toolbar
import aqt.stats
import aqt.mediasrv
from aqt.utils import saveGeom, restoreGeom, showInfo, showWarning, \
restoreState, getOnlyText, askUser, applyStyles, showText, tooltip, \
openHelp, openLink, checkInvalidFilename
@ -79,6 +80,7 @@ class AnkiQt(QMainWindow):
self.setupHooks()
self.setupRefreshTimer()
self.updateTitleBar()
self.setupMediaServer()
# screens
self.setupDeckBrowser()
self.setupOverview()
@ -1157,3 +1159,14 @@ Please ensure a profile is open and Anki is not busy, then try again."""),
def _onCollect(self):
gc.collect()
# Media server
##########################################################################
# prevent malicious decks from accessing the local filesystem
def setupMediaServer(self):
self.mediaServer = aqt.mediasrv.MediaServer()
self.mediaServer.start()
def baseHTML(self):
return '<base href="http://localhost:%d/">' % self.mediaServer.port

58
aqt/mediasrv.py Normal file
View file

@ -0,0 +1,58 @@
# Copyright: Damien Elmes <anki@ichi2.net>
# -*- coding: utf-8 -*-
# License: GNU AGPL, version 3 or later; http://www.gnu.org/licenses/agpl.html
from aqt.qt import *
from http import HTTPStatus
import http.server
import errno
class MediaServer(QThread):
def run(self):
self.port = 8080
self.server = None
while not self.server:
try:
self.server = http.server.HTTPServer(
("localhost", self.port), RequestHandler)
except OSError as e:
if e.errno == errno.EADDRINUSE:
self.port += 1
continue
raise
break
self.server.serve_forever()
class RequestHandler(http.server.SimpleHTTPRequestHandler):
def send_head(self):
path = self.translate_path(self.path)
if os.path.isdir(path):
self.send_error(HTTPStatus.NOT_FOUND, "File not found")
return None
ctype = self.guess_type(path)
try:
f = open(path, 'rb')
except OSError:
self.send_error(HTTPStatus.NOT_FOUND, "File not found")
return None
try:
self.send_response(HTTPStatus.OK)
self.send_header("Content-type", ctype)
fs = os.fstat(f.fileno())
self.send_header("Content-Length", str(fs[6]))
self.send_header("Last-Modified", self.date_time_string(fs.st_mtime))
self.end_headers()
return f
except:
f.close()
raise
def log_message(self, format, *args):
if not os.getenv("ANKIDEV"):
return
print("%s - - [%s] %s" %
(self.address_string(),
self.log_date_time_string(),
format%args))

View file

@ -10,10 +10,10 @@ import html.parser
from anki.lang import _, ngettext
from aqt.qt import *
from anki.utils import stripHTML, isMac, json
from anki.utils import stripHTML, json
from anki.hooks import addHook, runHook
from anki.sound import playFromText, clearAudioQueue, play
from aqt.utils import mungeQA, getBase, openLink, tooltip, askUserDialog, \
from aqt.utils import mungeQA, tooltip, askUserDialog, \
downArrow
from aqt.sound import getAudio
import aqt
@ -166,7 +166,7 @@ function _typeAnsPress() {
def _initWeb(self):
self._reps = 0
self._bottomReady = False
base = getBase(self.mw.col)
base = self.mw.baseHTML()
# main window
self.web.onLoadFinished = self._showQuestion
self.web.stdHtml(self._revHtml, self._styles(), head=base)

View file

@ -338,16 +338,10 @@ def applyStyles(widget):
if os.path.exists(p):
widget.setStyleSheet(open(p).read())
# this will go away in the future - please use mw.baseHTML() instead
def getBase(col):
base = None
mdir = col.media.dir()
if isWin and not mdir.startswith("\\\\"):
prefix = "file:///"
else:
prefix = "file://"
mdir = mdir.replace("\\", "/")
base = prefix + urllib.parse.quote(mdir) + "/"
return '<base href="%s">' % base
from aqt import mw
return mw.baseHTML()
def openFolder(path):
if isWin: