def _buildImg(col, latex, fname, model): # add header/footer & convert to utf8 latex = (model["latexPre"] + "\n" + latex + "\n" + model["latexPost"]) latex = latex.encode("utf8") # it's only really secure if run in a jail, but these are the most common tmplatex = latex.replace("\\includegraphics", "") for bad in ("\\write18", "\\readline", "\\input", "\\include", "\\catcode", "\\openout", "\\write", "\\loop", "\\def", "\\shipout"): # don't mind if the sequence is only part of a command bad_re = "\\" + bad + "[^a-zA-Z]" if re.search(bad_re, tmplatex): return _("""\ For security reasons, '%s' is not allowed on cards. You can still use \ it by placing the command in a different package, and importing that \ package in the LaTeX header instead.""") % bad # write into a temp file log = open(namedtmp("latex_log.txt"), "w") texpath = namedtmp("tmp.tex") texfile = file(texpath, "w") texfile.write(latex) texfile.close() mdir = col.media.dir() oldcwd = os.getcwd() png = namedtmp("tmp.png") try: # generate png os.chdir(tmpdir()) for latexCmd in latexCmds: if call(latexCmd, stdout=log, stderr=log): return _errMsg(latexCmd[0], texpath) # add to media shutil.copyfile(png, os.path.join(mdir, fname)) return finally: os.chdir(oldcwd)
def _buildImg(deck, latex, fname, model): # add header/footer latex = (model.conf["latexPre"] + "\n" + latex + "\n" + model.conf["latexPost"]) # write into a temp file log = open(namedtmp("latex_log.txt"), "w") texfile = file(namedtmp("tmp.tex"), "w") texfile.write(latex) texfile.close() # make sure we have a valid mediaDir mdir = deck.media.dir(create=True) oldcwd = os.getcwd() png = namedtmp("tmp.png") try: # generate dvi os.chdir(tmpdir()) if call(latexCmd + ["tmp.tex"], stdout=log, stderr=log): return _errMsg("latex") # and png if call(latexDviPngCmd + ["tmp.dvi", "-o", "tmp.png"], stdout=log, stderr=log): return _errMsg("dvipng") # add to media shutil.copy2(png, os.path.join(mdir, fname)) return finally: os.chdir(oldcwd)
def _buildImg(col, latex, fname, model): # add header/footer & convert to utf8 latex = (model["latexPre"] + "\n" + latex + "\n" + model["latexPost"]) latex = latex.encode("utf8") # it's only really secure if run in a jail, but these are the most common for bad in ("write18", "\\readline", "\\input", "\\include", "\\catcode", "\\openout", "\\write", "\\loop", "\\def", "\\shipout"): assert bad not in latex # write into a temp file log = open(namedtmp("latex_log.txt"), "w") texfile = file(namedtmp("tmp.tex"), "w") texfile.write(latex) texfile.close() mdir = col.media.dir() oldcwd = os.getcwd() png = namedtmp("tmp.png") try: # generate dvi os.chdir(tmpdir()) if call(latexCmd + ["tmp.tex"], stdout=log, stderr=log): return _errMsg("latex") # and png if call(latexDviPngCmd + ["tmp.dvi", "-o", "tmp.png"], stdout=log, stderr=log): return _errMsg("dvipng") # add to media shutil.copy2(png, os.path.join(mdir, fname)) return finally: os.chdir(oldcwd)
def _buildImg(col, latex, fname, model): # add header/footer & convert to utf8 latex = (model["latexPre"] + "\n" + latex + "\n" + model["latexPost"]) latex = latex.encode("utf8") # it's only really secure if run in a jail, but these are the most common for bad in ("write18", "\\readline", "\\input", "\\include", "\\catcode", "\\openout", "\\write", "\\loop", "\\def", "\\shipout"): assert bad not in latex # write into a temp file log = open(namedtmp("latex_log.txt"), "w") texfile = file(namedtmp("tmp.tex"), "w") texfile.write(latex) texfile.close() mdir = col.media.dir() oldcwd = os.getcwd() png = namedtmp("tmp.png") try: # generate dvi os.chdir(tmpdir()) if call(latexCmd + ["tmp.tex"], stdout=log, stderr=log): return _errMsg("latex") # and png if call(latexDviPngCmd + ["tmp.dvi", "-o", "tmp.png"], stdout=log, stderr=log): return _errMsg("dvipng") # add to media shutil.copyfile(png, os.path.join(mdir, fname)) return finally: os.chdir(oldcwd)
def _buildImg(col, latex, fname, model): # add header/footer & convert to utf8 latex = (model["latexPre"] + "\n" + latex + "\n" + model["latexPost"]) latex = latex.encode("utf8") # it's only really secure if run in a jail, but these are the most common tmplatex = latex.replace("\\includegraphics", "") for bad in ("write18", "\\readline", "\\input", "\\include", "\\catcode", "\\openout", "\\write", "\\loop", "\\def", "\\shipout"): if bad in tmplatex: return _("""\ For security reasons, '%s' is not allowed on cards. You can still use \ it by placing the command in a different package, and importing that \ package in the LaTeX header instead.""") % bad # write into a temp file log = open(namedtmp("latex_log.txt"), "w") texpath = namedtmp("tmp.tex") texfile = file(texpath, "w") texfile.write(latex) texfile.close() mdir = col.media.dir() oldcwd = os.getcwd() png = namedtmp("tmp.png") try: # generate png os.chdir(tmpdir()) for latexCmd in latexCmds: if call(latexCmd, stdout=log, stderr=log): return _errMsg(latexCmd[0], texpath) # add to media shutil.copyfile(png, os.path.join(mdir, fname)) return finally: os.chdir(oldcwd)
def _save_latex_image( col: anki.collection.Collection, extracted: ExtractedLatex, header: str, footer: str, svg: bool, ) -> str | None: # add header/footer latex = f"{header}\n{extracted.latex_body}\n{footer}" # it's only really secure if run in a jail, but these are the most common tmplatex = latex.replace("\\includegraphics", "") for bad in ( "\\write18", "\\readline", "\\input", "\\include", "\\catcode", "\\openout", "\\write", "\\loop", "\\def", "\\shipout", ): # don't mind if the sequence is only part of a command bad_re = f"\\{bad}[^a-zA-Z]" if re.search(bad_re, tmplatex): return col.tr.media_for_security_reasons_is_not(val=bad) # commands to use if svg: latex_cmds = svgCommands ext = "svg" else: latex_cmds = pngCommands ext = "png" # write into a temp file log = open(namedtmp("latex_log.txt"), "w", encoding="utf8") texpath = namedtmp("tmp.tex") texfile = open(texpath, "w", encoding="utf8") texfile.write(latex) texfile.close() oldcwd = os.getcwd() png_or_svg = namedtmp(f"tmp.{ext}") try: # generate png/svg os.chdir(tmpdir()) for latex_cmd in latex_cmds: if call(latex_cmd, stdout=log, stderr=log): return _err_msg(col, latex_cmd[0], texpath) # add to media with open(png_or_svg, "rb") as file: data = file.read() col.media.write_data(extracted.filename, data) os.unlink(png_or_svg) return None finally: os.chdir(oldcwd) log.close()
def _start_recording(self) -> None: driver = self.mw.pm.recording_driver() if driver is RecordingDriver.PyAudio: self._recorder = PyAudioRecorder(self.mw, namedtmp("rec.wav")) elif driver is RecordingDriver.QtAudioInput: self._recorder = QtAudioInputRecorder(namedtmp("rec.wav"), self.mw, self._parent) else: assert_exhaustive(driver) self._recorder.start(self._start_timer)
def _start_recording(self) -> None: if qtmajor > 5: self._recorder = QtAudioInputRecorder(namedtmp("rec.wav"), self.mw, self._parent) else: from .qt5 import QtAudioInputRecorder as Qt5Recorder self._recorder = Qt5Recorder(namedtmp("rec.wav"), self.mw, self._parent) self._recorder.start(self._start_timer)
def _start_recording(self) -> None: if qtmajor > 5: if macos_helper and platform.machine() == "arm64": self._recorder = NativeMacRecorder(namedtmp("rec.wav"), ) else: self._recorder = QtAudioInputRecorder(namedtmp("rec.wav"), self.mw, self._parent) else: from aqt.qt.qt5_audio import QtAudioInputRecorder as Qt5Recorder self._recorder = Qt5Recorder(namedtmp("rec.wav"), self.mw, self._parent) self._recorder.start(self._start_timer)
def _processImage(self, mime: QMimeData, extended: bool = False) -> Optional[str]: if not mime.hasImage(): return None im = QImage(mime.imageData()) uname = namedtmp("paste") if self.editor.mw.pm.profile.get("pastePNG", False): ext = ".png" im.save(uname + ext, None, 50) else: ext = ".jpg" im.save(uname + ext, None, 80) # invalid image? path = uname + ext if not os.path.exists(path): return None with open(path, "rb") as file: data = file.read() fname = self.editor._addPastedImage(data, ext) if fname: return self.editor.fnameToLink(fname) return None
def downloadRemote(self): raise Exception() mdir = self.deck.dir(create=True) refs = {} for (question, answer) in self.deck.db.all( "select question, answer from cards"): for txt in (question, answer): for f in mediaFiles(txt, remote=True): refs[f] = True failed = [] passed = [] for c, link in enumerate(refs.keys()): try: path = namedtmp(os.path.basename(link)) url = urllib2.urlopen(link) open(path, "wb").write(url.read()) newpath = copyToMedia(self.deck, path) passed.append([link, newpath]) except: failed.append(link) #self.deck.updateProgress(label=_("Download %d...") % c) for (url, name) in passed: self.deck.db.execute( "update fields set value = replace(value, :url, :name)", url=url, name=name) #self.deck.updateProgress(label=_("Updating references...")) #self.deck.updateProgress(label=_("Updating cards...")) # rebuild entire q/a cache for m in self.deck.models: self.deck.updateCardsFromModel(m, dirty=True) return (passed, failed)
def getVerse(self): ''' Lookup verse from ESV web-service and set results in current note. self should be set to Editor ''' #open ESV api connection and run query against reference esv = EsvSession() if not esv.query(self.note[REF_FIELD]): #query did not return successfully showInfo("No such passage: %s" % (self.note[REF_FIELD])) return #Retrive audio into a temporary folder path = namedtmp(os.path.basename(esv.esvMp3Link), True) urllib.urlretrieve(esv.esvMp3Link, path) #set note fields self.note[AUDIO_FIELD] = self._addMedia(path) self.note[TEXT_FIELD] = esv.esvText self.note[REF_FIELD] = esv.esvRef self.note[HINT_FIELD] = ",".join(esv.esvText.split()[:5]).replace(",", " ") #set 'y' for any additional card types that need to be generated for cardName in ADDTL_CARDS: self.note[cardName] = 'y' #reload note, makes things show up self.loadNote()
def _processImage(self, mime: QMimeData, extended: bool = False) -> str | None: if not mime.hasImage(): return None im = QImage(mime.imageData()) uname = namedtmp("paste") if self.editor.mw.col.get_config_bool(Config.Bool.PASTE_IMAGES_AS_PNG): ext = ".png" im.save(uname + ext, None, 50) else: ext = ".jpg" im.save(uname + ext, None, 80) # invalid image? path = uname + ext if not os.path.exists(path): return None with open(path, "rb") as file: data = file.read() fname = self.editor._addPastedImage(data, ext) if fname: return self.editor.fnameToLink(fname) return None
def _buildImg(col, latex, fname, model): # add header/footer latex = (model["latexPre"] + "\n" + latex + "\n" + model["latexPost"]) # it's only really secure if run in a jail, but these are the most common tmplatex = latex.replace("\\includegraphics", "") for bad in ("\\write18", "\\readline", "\\input", "\\include", "\\catcode", "\\openout", "\\write", "\\loop", "\\def", "\\shipout"): # don't mind if the sequence is only part of a command bad_re = "\\" + bad + "[^a-zA-Z]" if re.search(bad_re, tmplatex): return _("""\ For security reasons, '%s' is not allowed on cards. You can still use \ it by placing the command in a different package, and importing that \ package in the LaTeX header instead.""") % bad # commands to use? if model.get("latexsvg", False): latexCmds = svgCommands ext = "svg" else: latexCmds = pngCommands ext = "png" # write into a temp file log = open(namedtmp("latex_log.txt"), "w") texpath = namedtmp("tmp.tex") texfile = open(texpath, "w", encoding="utf8") texfile.write(latex) texfile.close() mdir = col.media.dir() oldcwd = os.getcwd() png = namedtmp("tmp.%s" % ext) try: # generate png os.chdir(tmpdir()) for latexCmd in latexCmds: if call(latexCmd, stdout=log, stderr=log): return _errMsg(latexCmd[0], texpath) # add to media shutil.copyfile(png, os.path.join(mdir, fname)) return finally: os.chdir(oldcwd) log.close()
def _processImage(self, mime): im = QImage(mime.imageData()) name = namedtmp("paste-%d.png" % im.cacheKey()) uname = unicode(name, sys.getfilesystemencoding()) if im.hasAlphaChannel(): im.save(uname) else: im.save(uname, None, 95) mime = QMimeData() mime.setHtml(self.editor._addMedia(uname)) return mime
def _addDummyCollection(self, zip): path = namedtmp("dummy.anki2") c = Collection(path) n = c.newNote() n[_('Front')] = "This file requires a newer version of Anki." c.addNote(n) c.save() c.close() zip.write(path, "collection.anki2") os.unlink(path)
def _errMsg(type): msg = (_("Error executing %s.") % type) + "<br>" try: log = open(namedtmp("latex_log.txt", rm=False)).read() if not log: raise Exception() msg += "<small><pre>" + cgi.escape(log) + "</pre></small>" except: msg += _("Have you installed latex and dvipng?") pass return msg
def _addDummyCollection(self, zip) -> None: path = namedtmp("dummy.anki2") c = Collection(path) n = c.newNote() n.fields[0] = "This file requires a newer version of Anki." c.addNote(n) c.save() c.close(downgrade=True) zip.write(path, "collection.anki2") os.unlink(path)
def _processImage(self, mime): im = QImage(mime.imageData()) uname = namedtmp("paste-%d" % im.cacheKey()) ext = ".jpg" im.save(uname+ext, None, 80) # invalid image? if not os.path.exists(uname+ext): return QMimeData() mime = QMimeData() mime.setHtml(self.editor._addMedia(uname+ext)) return mime
def _errMsg(col: anki.collection.Collection, type: str, texpath: str) -> Any: msg = f"{col.tr.media_error_executing(val=type)}<br>" msg += f"{col.tr.media_generated_file(val=texpath)}<br>" try: with open(namedtmp("latex_log.txt", rm=False)) as f: log = f.read() if not log: raise Exception() msg += f"<small><pre>{html.escape(log)}</pre></small>" except: msg += col.tr.media_have_you_installed_latex_and_dvipngdvisvgm() return msg
def _errMsg(type: str, texpath: str) -> Any: msg = (_("Error executing %s.") % type) + "<br>" msg += (_("Generated file: %s") % texpath) + "<br>" try: with open(namedtmp("latex_log.txt", rm=False)) as f: log = f.read() if not log: raise Exception() msg += "<small><pre>" + html.escape(log) + "</pre></small>" except: msg += _("Have you installed latex and dvipng/dvisvgm?") return msg
def _errMsg(type, texpath): msg = (_("Error executing %s.") % type) + "<br>" msg += (_("Generated file: %s") % texpath) + "<br>" try: with open(namedtmp("latex_log.txt", rm=False)) as f: log = f.read() if not log: raise Exception() msg += "<small><pre>" + html.escape(log) + "</pre></small>" except: msg += _("Have you installed latex and dvipng/dvisvgm?") return msg
def _errMsg(col: anki.collection.Collection, type: str, texpath: str) -> Any: msg = col.tr(TR.MEDIA_ERROR_EXECUTING, val=type) + "<br>" msg += col.tr(TR.MEDIA_GENERATED_FILE, val=texpath) + "<br>" try: with open(namedtmp("latex_log.txt", rm=False)) as f: log = f.read() if not log: raise Exception() msg += "<small><pre>" + html.escape(log) + "</pre></small>" except: msg += col.tr(TR.MEDIA_HAVE_YOU_INSTALLED_LATEX_AND_DVIPNGDVISVGM) return msg
def export_audio(output_folder, field_names, model_ids, cards_per_batch, num_batches, num_loops, include_separator): "Save all audio files into one large audio file" audio_files = get_card_audio(cards_per_batch * num_batches, field_names, model_ids) # get files on machine audio_files = [ os.path.join(mw.col.media.dir(), field) for field in audio_files ] for batch_id in range(num_batches): audio_files_in_batch = audio_files[batch_id * cards_per_batch:(batch_id + 1) * cards_per_batch] output_file = os.path.join(output_folder, "batch%d.mp3" % batch_id) audio_list_tmp_file = namedtmp("studyahead_audio_list.txt") separator_audio = os.path.join(mw.pm.addonFolder(), 'Studyahead_Audio', 'file_separator.mp3') with codecs.open(audio_list_tmp_file, "w", "utf-8") as f: for i, audio_file in enumerate(audio_files_in_batch): for j in range(num_loops): f.write("file '%s'\n" % os.path.relpath( audio_file, os.path.dirname(audio_list_tmp_file)).replace( "\\", "/")) if i < len(audio_files_in_batch) and include_separator: f.write("file '%s'\n" % os.path.relpath( separator_audio, os.path.dirname(audio_list_tmp_file)).replace( "\\", "/")) output_command = [ "ffmpeg", "-y", "-f", "concat", "-safe", "0", "-i", audio_list_tmp_file.replace("\\", "/"), "-vcodec", "copy", output_file ] with open(namedtmp("studyahead_audio_log.txt"), "w") as log: call(output_command, wait=True, stdout=log, stderr=log)
def browser(self): # dump to a temporary file path = namedtmp("report.png") p = self.form.web.page() oldsize = p.viewportSize() p.setViewportSize(p.mainFrame().contentsSize()) image = QImage(p.viewportSize(), QImage.Format_ARGB32) painter = QPainter(image) p.mainFrame().render(painter) painter.end() image.save(path, "png") p.setViewportSize(oldsize) openFolder(path)
def _buildImg(col, latex, fname, model): # add header/footer & convert to utf8 latex = (model["latexPre"] + "\n" + latex + "\n" + model["latexPost"]) latex = latex.encode("utf8") # it's only really secure if run in a jail, but these are the most common for bad in ("write18", "\\readline", "\\input", "\\include", "\\catcode", "\\openout", "\\write", "\\loop", "\\def", "\\shipout"): if bad in latex: return _("""\ For security reasons, '%s' is not allowed on cards. You can still use \ it by placing the command in a different package, and importing that \ package in the LaTeX header instead.""") % bad # write into a temp file log = open(namedtmp("latex_log.txt"), "w") texpath = namedtmp("tmp.tex") texfile = file(texpath, "w") texfile.write(latex) texfile.close() mdir = col.media.dir() oldcwd = os.getcwd() png = namedtmp("tmp.png") try: # generate dvi os.chdir(tmpdir()) if call(latexCmd + ["tmp.tex"], stdout=log, stderr=log): return _errMsg("latex", texpath) # and png if call(latexDviPngCmd + ["tmp.dvi", "-o", "tmp.png"], stdout=log, stderr=log): return _errMsg("dvipng", texpath) # add to media shutil.copyfile(png, os.path.join(mdir, fname)) return finally: os.chdir(oldcwd)
def _processImage(self, mime): im = QImage(mime.imageData()) uname = namedtmp("paste-%d" % im.cacheKey()) if self.editor.mw.pm.profile.get("pastePNG", False): ext = ".png" im.save(uname+ext, None, 50) else: ext = ".jpg" im.save(uname+ext, None, 80) # invalid image? if not os.path.exists(uname+ext): return QMimeData() mime = QMimeData() mime.setHtml(self.editor._addMedia(uname+ext)) return mime
def _processImage(self, mime): im = QImage(mime.imageData()) uname = namedtmp("paste") if self.editor.mw.pm.profile.get("pastePNG", False): ext = ".png" im.save(uname+ext, None, 50) else: ext = ".jpg" im.save(uname+ext, None, 80) # invalid image? path = uname+ext if not os.path.exists(path): return data = open(path, "rb").read() return self.editor._addPastedImage(data, ext)
def SaveImageToMedia(imageData, editor): im = QImage.fromData(imageData) uname = namedtmp("pasteHTML-%d" % im.cacheKey()) if editor.mw.pm.profile.get("pastePNG", False): ext = ".png" im.save(uname + ext, None, 50) else: ext = ".jpg" im.save(uname + ext, None, 80) # invalid image? if not os.path.exists(uname + ext): return "" fname = editor.mw.col.media.addFile(uname + ext) return fname
def _errMsg(type, texpath): """An error message, in html, concerning LaTeX compilation. This message contains LaTeX outputs if it exists, or a message asking whether the program latex and dvipng/dvisvgm are installed. Keyword arguments type -- the (begin of the) executed command texpath -- the path to the (temporary) file which was compiled """ msg = (_("Error executing %s.") % type) + "<br>" msg += (_("Generated file: %s") % texpath) + "<br>" try: log = open(namedtmp("latex_log.txt", rm=False)).read() if not log: raise Exception() msg += "<small><pre>" + cgi.escape(log) + "</pre></small>" except: msg += _("Have you installed latex and dvipng/dvisvgm?") pass return msg
def _processImage(self, mime): if not mime.hasImage(): return im = QImage(mime.imageData()) uname = namedtmp("paste") if self.editor.mw.pm.profile.get("pastePNG", False): ext = ".png" im.save(uname+ext, None, 50) else: ext = ".jpg" im.save(uname+ext, None, 80) # invalid image? path = uname+ext if not os.path.exists(path): return data = open(path, "rb").read() fname = self.editor._addPastedImage(data, ext) if fname: return self.editor.fnameToLink(fname)
def testWrap(): from anki.schedv2 import Scheduler path = namedtmp("humpty_dumpty_tmp.anki2") dummy_col = Collection(path) v2_sched = Scheduler(dummy_col) try: run_test.reset() v2_sched.moveToV1() assert run_test.state == 1, "The addon HumptyDumpty was not patched correctly. Error code 1" run_test.reset() v2_sched.moveToV2() assert run_test.state == 2, "The addon HumptyDumpty was not patched correctly. Error code 2" run_test.setTestState(run_test.STATE_FINISHED) #for pref menu # print("HumptyDumpty was patched correctly.") finally: dummy_col.close() del dummy_col
def _processImage(self, mime): im = QImage(mime.imageData()) uname = namedtmp("paste") if self.editor.mw.pm.profile.get("pastePNG", False): ext = ".png" im.save(uname + ext, None, 50) else: ext = ".jpg" im.save(uname + ext, None, 80) # invalid image? path = uname + ext if not os.path.exists(path): return # hash and rename csum = checksum(open(path, "rb").read()) newpath = "{}-{}{}".format(uname, csum, ext) os.rename(path, newpath) # add to media and return resulting html link return self.editor._addMedia(newpath)
def _processImage(self, mime): im = QImage(mime.imageData()) uname = namedtmp("paste") if self.editor.mw.pm.profile.get("pastePNG", False): ext = ".png" im.save(uname+ext, None, 50) else: ext = ".jpg" im.save(uname+ext, None, 80) # invalid image? path = uname+ext if not os.path.exists(path): return # hash and rename csum = checksum(open(path, "rb").read()) newpath = "{}-{}{}".format(uname, csum, ext) os.rename(path, newpath) # add to media and return resulting html link return self.editor._addMedia(newpath)
#Just a fix to an Anki add-on by unknown autor -1125592690 #Usage: #download the original (contains pictures) add-on and then replace file c:\Users\<your win login>\Documents\Anki\addons\showdogs.py with this one from aqt import mw from aqt.utils import showInfo from aqt.qt import * from anki.hooks import wrap import os import random import logging from anki.utils import namedtmp LOGFILE = namedtmp('showdogs.log') logging.basicConfig(level=logging.DEBUG, format='%(asctime)s %(levelname)s %(lineno)d: %(message)s', filename=LOGFILE, datefmt='%d.%m.%Y %H:%M:%S%p)') logger = logging.getLogger() mw.showdogs = {} mw.showdogs['card_count'] = 0 mw.showdogs['interval'] = 9 def showDog(): mw.showdogs['card_count'] = mw.showdogs['card_count'] + 1 if mw.showdogs['card_count'] % mw.showdogs['interval'] != 0: return dialog = QDialog(mw) layout = QVBoxLayout(dialog) dialog.setLayout(layout)
def _save_latex_image( col: anki.collection.Collection, extracted: ExtractedLatex, header: str, footer: str, svg: bool, ) -> Optional[str]: # add header/footer latex = header + "\n" + extracted.latex_body + "\n" + footer # it's only really secure if run in a jail, but these are the most common tmplatex = latex.replace("\\includegraphics", "") for bad in ( "\\write18", "\\readline", "\\input", "\\include", "\\catcode", "\\openout", "\\write", "\\loop", "\\def", "\\shipout", ): # don't mind if the sequence is only part of a command bad_re = "\\" + bad + "[^a-zA-Z]" if re.search(bad_re, tmplatex): return (_("""\ For security reasons, '%s' is not allowed on cards. You can still use \ it by placing the command in a different package, and importing that \ package in the LaTeX header instead.""") % bad) # commands to use if svg: latexCmds = svgCommands ext = "svg" else: latexCmds = pngCommands ext = "png" # write into a temp file log = open(namedtmp("latex_log.txt"), "w") texpath = namedtmp("tmp.tex") texfile = open(texpath, "w", encoding="utf8") texfile.write(latex) texfile.close() oldcwd = os.getcwd() png_or_svg = namedtmp("tmp.%s" % ext) try: # generate png/svg os.chdir(tmpdir()) for latexCmd in latexCmds: if call(latexCmd, stdout=log, stderr=log): return _errMsg(latexCmd[0], texpath) # add to media with open(png_or_svg, "rb") as file: data = file.read() col.media.write_data(extracted.filename, data) os.unlink(png_or_svg) return None finally: os.chdir(oldcwd) log.close()
class EditorWebView(AnkiWebView): def __init__(self, parent, editor): AnkiWebView.__init__(self) self.editor = editor self.errtxt = _("An error occured while opening %s") self.strip = self.editor.mw.pm.profile['stripHTML'] def keyPressEvent(self, evt): if evt.matches(QKeySequence.Paste): self.onPaste() return evt.accept() elif evt.matches(QKeySequence.Copy): self.onCopy() return evt.accept() elif evt.matches(QKeySequence.Cut): self.onCut() return evt.accept() QWebView.keyPressEvent(self, evt) def onCut(self): self.triggerPageAction(QWebPage.Cut) self._flagAnkiText() def onCopy(self): self.triggerPageAction(QWebPage.Copy) self._flagAnkiText() def onPaste(self): mime = self.prepareClip() self.triggerPageAction(QWebPage.Paste) self.restoreClip(mime) def mouseReleaseEvent(self, evt): if not isMac and not isWin and evt.button() == Qt.MidButton: # middle click on x11; munge the clipboard before standard # handling mime = self.prepareClip(mode=QClipboard.Selection) AnkiWebView.mouseReleaseEvent(self, evt) self.restoreClip(mime, mode=QClipboard.Selection) else: AnkiWebView.mouseReleaseEvent(self, evt) def focusInEvent(self, evt): window = False if evt.reason() in (Qt.ActiveWindowFocusReason, Qt.PopupFocusReason): # editor area got focus again; need to tell js not to adjust cursor self.eval("mouseDown++;") window = True AnkiWebView.focusInEvent(self, evt) if evt.reason() == Qt.TabFocusReason: self.eval("focusField(0);") elif evt.reason() == Qt.BacktabFocusReason: n = len(self.editor.note.fields) - 1 self.eval("focusField(%d);" % n) elif window: self.eval("mouseDown--;") def dropEvent(self, evt): oldmime = evt.mimeData() # coming from this program? if evt.source(): if oldmime.hasHtml(): mime = QMimeData() mime.setHtml(_filterHTML(oldmime.html())) else: # old qt on linux won't give us html when dragging an image; # in that case just do the default action (which is to ignore # the drag) return AnkiWebView.dropEvent(self, evt) else: mime = self._processMime(oldmime) # create a new event with the new mime data and run it new = QDropEvent(evt.pos(), evt.possibleActions(), mime, evt.mouseButtons(), evt.keyboardModifiers()) evt.accept() QWebView.dropEvent(self, new) # tell the drop target to take focus so the drop contents are saved self.eval("dropTarget.focus();") self.setFocus() def prepareClip(self, mode=QClipboard.Clipboard): clip = self.editor.mw.app.clipboard() mime = clip.mimeData(mode=mode) if mime.hasHtml() and mime.html().startswith("<!--anki-->"): # pasting from another field, filter extraneous webkit formatting html = mime.html()[11:] html = _filterHTML(html) mime.setHtml(html) return self.saveClip(mode=mode) mime = self._processMime(mime) clip.setMimeData(mime, mode=mode) def restoreClip(self, mime, mode=QClipboard.Clipboard): if not mime: return clip = self.editor.mw.app.clipboard() clip.setMimeData(mime, mode=mode) def saveClip(self, mode): # we don't own the clipboard object, so we need to copy it mime = self.editor.mw.app.clipboard().mimeData(mode=mode) n = QMimeData() if mime.hasText(): n.setText(mime.text()) if mime.hasHtml(): n.setHtml(mime.html()) if mime.hasUrls(): n.setUrls(mime.urls()) if mime.hasImage(): n.setImageData(mime.imageData()) return n def _processMime(self, mime): # print "html=%s image=%s urls=%s txt=%s" % ( # mime.hasHtml(), mime.hasImage(), mime.hasUrls(), mime.hasText()) # print "html", mime.html() # print "urls", mime.urls() # print "text", mime.text() if mime.hasImage(): return self._processImage(mime) elif mime.hasUrls(): return self._processUrls(mime) elif mime.hasText() and (self.strip or not mime.hasHtml()): return self._processText(mime) elif mime.hasHtml(): return self._processHtml(mime) else: # nothing return QMimeData() def _processUrls(self, mime): url = mime.urls()[0].toString() link = self._localizedMediaLink(url) mime = QMimeData() mime.setHtml(link) return mime def _localizedMediaLink(self, url): l = url.lower() for suffix in pics + audio: if l.endswith(suffix): return self._retrieveURL(url) # not a supported type; return link verbatim return url def _processText(self, mime): txt = unicode(mime.text()) l = txt.lower() html = None # if the user is pasting an image or sound link, convert it to local if l.startswith("http://") or l.startswith("https://") or l.startswith( "file://"): txt = txt.split("\r\n")[0] html = self._localizedMediaLink(txt) if html == txt: # wasn't of a supported media type; don't change html = None new = QMimeData() if html: new.setHtml(html) else: new.setText(mime.text()) return new def _processHtml(self, mime): html = mime.html() if self.strip: html = stripHTML(html) else: html = _filterHTML(html) mime = QMimeData() mime.setHtml(html) return mime def _processImage(self, mime): im = QImage(mime.imageData()) uname = namedtmp("paste-%d" % im.cacheKey()) if self.editor.mw.pm.profile.get("pastePNG", False): ext = ".png" im.save(uname + ext, None, 50) else: ext = ".jpg" im.save(uname + ext, None, 80) # invalid image? if not os.path.exists(uname + ext): return QMimeData() mime = QMimeData() mime.setHtml(self.editor._addMedia(uname + ext)) return mime def _retrieveURL(self, url): # is it media? ext = url.split(".")[-1].lower() if ext not in pics and ext not in audio: return # fetch it into a temporary folder self.editor.mw.progress.start(immediate=True) try: req = urllib2.Request( url, None, {'User-Agent': 'Mozilla/5.0 (compatible; Anki)'}) filecontents = urllib2.urlopen(req).read() except urllib2.URLError, e: showWarning(self.errtxt % e) return path = namedtmp(os.path.basename(url)) file = open(path, "wb") file.write(filecontents) file.close() self.editor.mw.progress.finish() return self.editor._addMedia(path)
# is it media? ext = url.split(".")[-1].lower() if ext not in pics and ext not in audio: return # fetch it into a temporary folder self.editor.mw.progress.start(immediate=True) try: req = urllib2.Request(url, None, { 'User-Agent': 'Mozilla/5.0 (compatible; Anki)'}) filecontents = urllib2.urlopen(req).read() except urllib2.URLError, e: showWarning(self.errtxt % e) return finally: self.editor.mw.progress.finish() path = namedtmp(os.path.basename(urllib2.unquote(url))) file = open(path, "wb") file.write(filecontents) file.close() return self.editor._addMedia(path) def _flagAnkiText(self): # add a comment in the clipboard html so we can tell text is copied # from us and doesn't need to be stripped clip = self.editor.mw.app.clipboard() mime = clip.mimeData() if not mime.hasHtml(): return html = mime.html() mime.setHtml("<!--anki-->" + mime.html())
# fetch it into a temporary folder self.editor.mw.progress.start(immediate=True, parent=self.editor.parentWindow) try: req = urllib2.Request( url, None, {'User-Agent': 'Mozilla/5.0 (compatible; Anki)'}) filecontents = urllib2.urlopen(req).read() except urllib2.URLError, e: showWarning(self.errtxt % e) return finally: self.editor.mw.progress.finish() path = unicode(urllib2.unquote(url.encode("utf8")), "utf8") for badChar in "#%\"": path = path.replace(badChar, "") path = namedtmp(os.path.basename(path)) file = open(path, "wb") file.write(filecontents) file.close() return self.editor._addMedia(path) def _flagAnkiText(self): # add a comment in the clipboard html so we can tell text is copied # from us and doesn't need to be stripped clip = self.editor.mw.app.clipboard() mime = clip.mimeData() if not mime.hasHtml(): return html = mime.html() mime.setHtml("<!--anki-->" + mime.html())
class EditorWebView(AnkiWebView): def __init__(self, parent, editor): AnkiWebView.__init__(self, parent) self.editor = editor self.errtxt = _("An error occured while opening %s") self.strip = self.editor.mw.config['stripHTML'] def keyPressEvent(self, evt): self._curKey = True self.origClip = None shiftPaste = (evt.modifiers() == (Qt.ShiftModifier | Qt.ControlModifier) and evt.key() == Qt.Key_V) if evt.matches(QKeySequence.Paste) or shiftPaste: self.prepareClip(shiftPaste) if shiftPaste: self.triggerPageAction(QWebPage.Paste) QWebView.keyPressEvent(self, evt) if self.origClip: self.restoreClip() def contextMenuEvent(self, evt): # adjust in case the user is going to paste self.prepareClip() QWebView.contextMenuEvent(self, evt) self.restoreClip() def dropEvent(self, evt): oldmime = evt.mimeData() # coming from this program? if evt.source(): # if they're copying just an image, we need to turn it into html # again txt = "" mime = QMimeData() if not oldmime.hasHtml() and oldmime.hasUrls(): # qt gives it to us twice txt += '<img src="%s">' % os.path.basename( oldmime.urls()[0].toString()) mime.setHtml(txt) else: mime.setHtml(oldmime.html()) else: mime = self._processMime(oldmime) # create a new event with the new mime data new = QDropEvent(evt.pos(), evt.possibleActions(), mime, evt.mouseButtons(), evt.keyboardModifiers()) evt.accept() QWebView.dropEvent(self, new) def prepareClip(self, keep=False): clip = self.editor.mw.app.clipboard() mime = clip.mimeData() self.saveClip() if keep: new = QMimeData() if mime.hasHtml(): new.setHtml(mime.html()) else: new.setText(mime.text()) mime = new else: mime = self._processMime(mime) clip.setMimeData(mime) def restoreClip(self): clip = self.editor.mw.app.clipboard() clip.setMimeData(self.origClip) def saveClip(self): # we don't own the clipboard object, so we need to copy it mime = self.editor.mw.app.clipboard().mimeData() n = QMimeData() if mime.hasText(): n.setText(mime.text()) if mime.hasHtml(): n.setHtml(mime.html()) if mime.hasUrls(): n.setUrls(mime.urls()) if mime.hasImage(): n.setImageData(mime.imageData()) self.origClip = n def _processMime(self, mime): # print "html=%s image=%s urls=%s txt=%s" % ( # mime.hasHtml(), mime.hasImage(), mime.hasUrls(), mime.hasText()) # print "html", mime.html() # print "urls", mime.urls() # print "text", mime.text() if mime.hasUrls(): return self._processUrls(mime) elif mime.hasImage(): return self._processImage(mime) elif mime.hasText() and (self.strip or not mime.hasHtml()): return self._processText(mime) elif mime.hasHtml(): return self._processHtml(mime) else: # nothing return QMimeData() def _processUrls(self, mime): links = [] for url in mime.urls(): url = url.toString() link = self._retrieveURL(url) if link: links.append(link) mime = QMimeData() mime.setHtml("".join(links)) return mime def _processText(self, mime): txt = unicode(mime.text()) l = txt.lower() html = None # firefox on linux just gives us a url for an image if "\n" in l and (l.startswith("http://") or l.startswith("file://")): txt = txt.split("\r\n")[0] html = self._retrieveURL(txt) new = QMimeData() if html: new.setHtml(html) else: new.setText(mime.text()) return new def _processHtml(self, mime): html = mime.html() if self.strip: html = stripHTML(html) mime = QMimeData() mime.setHtml(html) return mime def _processImage(self, mime): im = QImage(mime.imageData()) name = namedtmp("paste-%d.png" % im.cacheKey()) uname = unicode(name, sys.getfilesystemencoding()) if im.hasAlphaChannel(): im.save(uname) else: im.save(uname, None, 95) mime = QMimeData() mime.setHtml(self.editor._addMedia(uname)) return mime def _retrieveURL(self, url): # is it media? ext = name.split(".")[-1].lower() if ext not in pics and ext not in audio: return # fetch it into a temporary folder try: req = urllib2.Request( url, None, {'User-Agent': 'Mozilla/5.0 (compatible; Anki)'}) filecontents = urllib2.urlopen(req).read() except urllib2.URLError, e: showWarning(self.errtxt % e) return path = namedtmp(os.path.basename(url)) file = open(path, "wb") file.write(filecontents) file.close() return self.editor._addMedia(path)
# fetch it into a temporary folder self.editor.mw.progress.start( immediate=True, parent=self.editor.parentWindow) try: req = urllib2.Request(url, None, { 'User-Agent': 'Mozilla/5.0 (compatible; Anki)'}) filecontents = urllib2.urlopen(req).read() except urllib2.URLError, e: showWarning(self.errtxt % e) return finally: self.editor.mw.progress.finish() path = unicode(urllib2.unquote(url.encode("utf8")), "utf8") path = path.replace("#", "") path = path.replace("%", "") path = namedtmp(os.path.basename(path)) file = open(path, "wb") file.write(filecontents) file.close() return self.editor._addMedia(path) def _flagAnkiText(self): # add a comment in the clipboard html so we can tell text is copied # from us and doesn't need to be stripped clip = self.editor.mw.app.clipboard() mime = clip.mimeData() if not mime.hasHtml(): return html = mime.html() mime.setHtml("<!--anki-->" + mime.html())
#Just a fix to an Anki add-on by unknown autor -1125592690 #Usage: #download the original (contains pictures) add-on and then replace file c:\Users\<your win login>\Documents\Anki\addons\showdogs.py with this one from aqt import mw from aqt.utils import showInfo from aqt.qt import * from anki.hooks import wrap import os import random import logging from anki.utils import namedtmp LOGFILE = namedtmp('showdogs.log') logging.basicConfig(level=logging.DEBUG, format='%(asctime)s %(levelname)s %(lineno)d: %(message)s', filename=LOGFILE, datefmt='%d.%m.%Y %H:%M:%S%p)') logger = logging.getLogger() mw.showdogs = {} mw.showdogs['card_count'] = 0 mw.showdogs['interval'] = 9 def showDog(): mw.showdogs['card_count'] = mw.showdogs['card_count'] + 1 if mw.showdogs['card_count'] % mw.showdogs['interval'] != 0: return