Beispiel #1
0
def ensureMplayerThreads():
    global mplayerManager
    if not mplayerManager:
        mplayerManager = MplayerMonitor()
        mplayerManager.daemon = True
        mplayerManager.start()
        # ensure the tmpdir() exit handler is registered first so it runs
        # after the mplayer exit
        tmpdir()
        # clean up mplayer on exit
        atexit.register(stopMplayer)
Beispiel #2
0
def ensureMplayerThreads():
    global mplayerManager
    if not mplayerManager:
        mplayerManager = MplayerMonitor()
        mplayerManager.daemon = True
        mplayerManager.start()
        # ensure the tmpdir() exit handler is registered first so it runs
        # after the mplayer exit
        tmpdir()
        # clean up mplayer on exit
        atexit.register(stopMplayer)
Beispiel #3
0
def ensureMplayerThreads():
    global mplayerManager
    if not mplayerManager:
        mplayerManager = MplayerMonitor()
        mplayerManager.daemon = True
        mplayerManager.start()
        # ensure the tmpdir() exit handler is registered first so it runs
        # after the mplayer exit
        if not aqt.mw.pm.profile.get("mpv.directAccess", True):
            tmpdir()  #TODO: rm if testNoCache passes
        # clean up mplayer on exit
        atexit.register(stopMplayer)
Beispiel #4
0
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)
Beispiel #5
0
    def boss_key(self):
        cmd = self.pm.profile.get("ccbc.bossCmd","notepad.exe")
        if not cmd:
            # TODO: Write gui for this option
            #   Use debugger to set command for ccbc.bossCmd
            showInfo("No external text editor was set.")
            return
        if isWin:
            cmd = cmd.replace('/','\\')

        anki.sound.clearAudioQueue()

        import subprocess, time
        from anki.utils import tmpdir
        fname = os.path.join(tmpdir(), "note%d.txt"%time.time())

        f = open(fname, "w")
        f.write(self.pm.profile.get("ccbc.bossText","To Whom It May Concern:"))
        f.close()

        runHook("BOSS_KEY", True)
        self.hideAllCollectionWindows()
        self.hide()
        try:
            self.debugDiag.close()
        except AttributeError: pass

        self.pm.save()
        self.col.autosave()

        subprocess.call('''%s "%s"'''%(cmd,fname), shell=True)
        self.show()
        self.showAllCollectionWindows()
        runHook("BOSS_KEY", False)
def queueMplayerWithCache(path):
    if DEV_MODE:
        selfTest()

    s.ensureMplayerThreads()
    if conf.get("direct_access_mode", False):
        # Modern versions of mplayer seems to have this unicode bug fixed.
        path=path.replace("\\", "/")
    elif os.path.exists(path):
        if path in audio_cached:
            path=audio_cached[path]
        else:
            # mplayer on windows doesn't like the encoding, so we create a
            # temporary file instead. oddly, foreign characters in the dirname
            # don't seem to matter.
            key=path
            dir = tmpdir()
            name = os.path.join(dir, "audio%s%s" % (
                random.randrange(0, 1000000), os.path.splitext(path)[1]))
            f = open(name, "wb")
            f.write(open(path, "rb").read())
            f.close()
            # it wants unix paths, too!
            path = name.replace("\\", "/")
            audio_cached[key]=path

    s.mplayerQueue.append(path)
    s.mplayerEvt.set()
Beispiel #7
0
def queueMplayer(path, start_sec_p=0, end_sec_p=0):
    global media_to_play, start_sec, end_sec, stop_play_timer
    ensureMplayerThreads()
    if isWin and os.path.exists(path):
        # mplayer on windows doesn't like the encoding, so we create a
        # temporary file instead. oddly, foreign characters in the dirname
        # don't seem to matter.
        config = mw.addonManager.getConfig(__name__)
        if "my_mplayer_need_copying_file_to_temp" in config \
                and config["my_mplayer_need_copying_file_to_temp"]:
            dir = tmpdir()
            name = os.path.join(dir, "audio%s%s" % (
                random.randrange(0, 1000000), os.path.splitext(path)[1]))
            f = open(name, "wb")
            f.write(open(path, "rb").read())
            f.close()
            # it wants unix paths, too!
            path = name
        path = path.replace("\\", "/")
    media_to_play = path
    if isinstance(start_sec_p, int) and start_sec_p >= 0:
        start_sec = start_sec_p
    else:
        start_sec = 0
    if isinstance(end_sec_p, int) and end_sec_p > start_sec:
        end_sec = end_sec_p
        if stop_play_timer and stop_play_timer.is_alive():
            stop_play_timer.cancel()
        stop_play_timer = threading.Timer(end_sec - start_sec, stop_as_planned, kwargs={"media_path_to_stop": media_to_play})
        stop_play_timer.start()
    else:
        end_sec = 0
    mplayerEvt.set()
Beispiel #8
0
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)
Beispiel #9
0
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)
Beispiel #10
0
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)
Beispiel #11
0
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)
Beispiel #12
0
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)
Beispiel #13
0
    def temp_file_for_tag_and_voice(self, tag: AVTag, voice: TTSVoice) -> str:
        """Return a hashed filename, to allow for caching generated files.

        No file extension is included."""
        assert isinstance(tag, TTSTag)
        buf = f"{voice.name}-{voice.lang}-{tag.field_text}"
        return os.path.join(tmpdir(), f"tts-{checksum(buf)}")
Beispiel #14
0
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()
Beispiel #15
0
class MacTTSFilePlayer(MacTTSPlayer):
    "Generates an .aiff file, which is played using av_player."

    tmppath = os.path.join(tmpdir(), "tts.aiff")

    def _play(self, tag: AVTag) -> None:
        assert isinstance(tag, TTSTag)
        match = self.voice_for_tag(tag)
        assert match
        voice = match.voice
        assert isinstance(voice, MacVoice)

        default_wpm = 170
        words_per_min = str(int(default_wpm * tag.speed))

        self._process = subprocess.Popen(
            [
                "say",
                "-v",
                voice.original_name,
                "-r",
                words_per_min,
                "-f",
                "-",
                "-o",
                self.tmppath,
            ],
            stdin=subprocess.PIPE,
            stdout=subprocess.DEVNULL,
            stderr=subprocess.DEVNULL,
        )
        # write the input text to stdin
        self._process.stdin.write(tag.field_text.encode("utf8"))
        self._process.stdin.close()
        self._wait_for_termination(tag)

    def _on_done(self, ret: Future, cb: OnDoneCallback) -> None:
        try:
            ret.result()
        except PlayerInterrupted:
            # don't fire done callback when interrupted
            return

        # inject file into the top of the audio queue
        from aqt.sound import av_player

        av_player.insert_file(self.tmppath)

        # then tell player to advance, which will cause the file to be played
        cb()
Beispiel #16
0
def queueMplayer(path):
    ensureMplayerThreads()
    if isWin and os.path.exists(path):
        # mplayer on windows doesn't like the encoding, so we create a
        # temporary file instead. oddly, foreign characters in the dirname
        # don't seem to matter.
        dir = tmpdir()
        name = os.path.join(dir, "audio%s%s" % (
            random.randrange(0, 1000000), os.path.splitext(path)[1]))
        f = open(name, "wb")
        f.write(open(path, "rb").read())
        f.close()
        # it wants unix paths, too!
        path = name.replace("\\", "/")
    mplayerQueue.append(path)
    mplayerEvt.set()
Beispiel #17
0
def queueMplayer(path):
    ensureMplayerThreads()
    if isWin and os.path.exists(path):
        # mplayer on windows doesn't like the encoding, so we create a
        # temporary file instead. oddly, foreign characters in the dirname
        # don't seem to matter.
        dir = tmpdir()
        name = os.path.join(dir, "audio%s%s" % (
            random.randrange(0, 1000000), os.path.splitext(path)[1]))
        f = open(name, "wb")
        f.write(open(path, "rb").read())
        f.close()
        # it wants unix paths, too!
        path = name.replace("\\", "/")
    mplayerQueue.append(path)
    mplayerEvt.set()
Beispiel #18
0
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()
Beispiel #19
0
def queueMplayer(path):
    ensureMplayerThreads()
    while mplayerEvt.isSet():
        time.sleep(0.1)
    if isWin and os.path.exists(path):
        # mplayer on windows doesn't like the encoding, so we create a
        # temporary file instead. oddly, foreign characters in the dirname
        # don't seem to matter.
        dir = tmpdir().encode(sys.getfilesystemencoding())
        name = os.path.join(dir, "audio"+os.path.splitext(path)[1])
        f = open(name, "wb")
        f.write(open(path, "rb").read())
        f.close()
        # it wants unix paths, too!
        path = name.replace("\\", "/")
        path = path.encode(sys.getfilesystemencoding())
    else:
        path = path.encode("utf-8")
    mplayerQueue.append(path)
    mplayerEvt.set()
Beispiel #20
0
def review_link_handler_wrapper(reviewer, url):
    """Play the sound or call the original link handler."""
    if url.startswith("urlplayhttp://") or url.startswith("urlplayhttps://"):
        if isWin:
            # download audio from url
            name = os.path.join(
                tmpdir(),
                hashlib.md5(url.encode(encoding="UTF-8")).hexdigest() + ".mp3")
            if not os.path.exists(name):
                f = open(name, "wb")
                f.write(requests.get(url[7:]).content)
                f.close()
            # it wants unix paths, too!
            path = name.replace("\\", "/")
            play(path)
        else:
            # use mpv directly
            mpvManager.command("loadfile", url[7:], "append-play")
    else:
        original_review_link_handler(reviewer, url)
Beispiel #21
0
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)
Beispiel #22
0
def queueMplayer(path):
    ensureMplayerThreads()
    if isWin and os.path.exists(path):
        # mplayer on windows doesn't like the encoding, so we create a
        # temporary file instead. oddly, foreign characters in the dirname
        # don't seem to matter.
        if aqt.mw.pm.profile.get("mpv.directAccess", True):  #TODO: testNoCache
            path = path.replace("\\", "/")
        elif path in audio_cached:
            path = audio_cached[path]
        else:
            key = path
            dir = tmpdir()
            name = os.path.join(
                dir, "audio%s%s" %
                (random.randrange(0, 1000000), os.path.splitext(path)[1]))
            f = open(name, "wb")
            f.write(open(path, "rb").read())
            f.close()
            # it wants unix paths, too!
            path = name.replace("\\", "/")
            audio_cached[key] = path
    mplayerQueue.append(path)
    mplayerEvt.set()
Beispiel #23
0
def _buildImg(col, latex, fname, model):
    """Generate an image file from latex code

    latex's header and foot is added as in the model. The image is
    named fname and added to the media folder of this collection.    

    The compiled file is in tmp.tex and its output (err and std) in
    latex_log.tex, replacing previous files of the same name. Both of
    those file are in the tmpdir as in utils.py

    Compiles to svg if latexsvg is set to true in the model, otherwise
    to png. The compilation commands are given above.

    In case of error, return an error message to be displayed instead
    of the LaTeX document. (Note that this image is not displayed in
    AnkiDroid. It is probably shown only in computer mode)

    Keyword arguments:
    col -- the current collection. It deals with media folder
    latex -- the code LaTeX to compile, as given in fields
    fname -- the name given to the generated png
    model -- the model in which is compiled the note. It deals with
    the header/footer, and the image file format
    """
    # 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 an image
        os.chdir(tmpdir())
        for latexCmd in latexCmds:
            if call(latexCmd, stdout=log, stderr=log):
                return _errMsg(latexCmd[0], texpath)
        # add the image to the media folder
        shutil.copyfile(png, os.path.join(mdir, fname))
        return
    finally:
        os.chdir(oldcwd)
        log.close()
Beispiel #24
0
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()
Beispiel #25
0
    class WindowsRTTTSFilePlayer(TTSProcessPlayer):
        voice_list = None
        tmppath = os.path.join(tmpdir(), "tts.wav")

        def import_voices(self) -> None:
            import winrt.windows.media.speechsynthesis as speechsynthesis  # type: ignore

            try:
                self.voice_list = speechsynthesis.SpeechSynthesizer.get_all_voices(
                )
            except Exception as e:
                print("winrt tts voices unavailable:", e)
                self.voice_list = []

        def get_available_voices(self) -> List[TTSVoice]:
            t = threading.Thread(target=self.import_voices)
            t.start()
            t.join()
            return list(map(self._voice_to_object, self.voice_list))

        def _voice_to_object(self, voice: Any) -> TTSVoice:
            return WindowsRTVoice(
                id=voice.id,
                name=voice.display_name.replace(" ", "_"),
                lang=voice.language.replace("-", "_"),
            )

        def _play(self, tag: AVTag) -> None:
            assert isinstance(tag, TTSTag)
            match = self.voice_for_tag(tag)
            assert match
            voice = cast(WindowsRTVoice, match.voice)

            self._taskman.run_on_main(
                lambda: gui_hooks.av_player_did_begin_playing(self, tag))
            asyncio.run(self.speakText(tag, voice.id))

        def _on_done(self, ret: Future, cb: OnDoneCallback):
            ret.result()

            # inject file into the top of the audio queue
            from aqt.sound import av_player

            av_player.insert_file(self.tmppath)

            # then tell player to advance, which will cause the file to be played
            cb()

        async def speakText(self, tag: TTSTag, voice_id):
            import winrt.windows.media.speechsynthesis as speechsynthesis  # type: ignore
            import winrt.windows.storage.streams as streams  # type: ignore

            synthesizer = speechsynthesis.SpeechSynthesizer()

            voices = speechsynthesis.SpeechSynthesizer.get_all_voices()
            voice_match = next(filter(lambda v: v.id == voice_id, voices))

            assert voice_match

            synthesizer.voice = voice_match
            synthesizer.options.speaking_rate = tag.speed

            stream = await synthesizer.synthesize_text_to_stream_async(
                tag.field_text)
            inputStream = stream.get_input_stream_at(0)
            dataReader = streams.DataReader(inputStream)
            dataReader.load_async(stream.size)
            f = open(self.tmppath, "wb")
            for x in range(stream.size):
                f.write(bytes([dataReader.read_byte()]))
            f.close()