mirror of
https://github.com/ankitects/anki.git
synced 2025-09-24 16:56:36 -04:00
image support
This commit is contained in:
parent
7d0eb6dd39
commit
a8e2f992c8
7 changed files with 83 additions and 18 deletions
|
@ -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,
|
||||
|
|
|
@ -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),
|
||||
|
|
|
@ -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")))
|
||||
|
||||
|
|
13
aqt/main.py
13
aqt/main.py
|
@ -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
58
aqt/mediasrv.py
Normal 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))
|
|
@ -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)
|
||||
|
|
12
aqt/utils.py
12
aqt/utils.py
|
@ -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:
|
||||
|
|
Loading…
Reference in a new issue