markdown 中启用音频支持

markdown 中启用音频支持

markdown 默认不支持音频文件,我们通过 html 标签渲染

flask项目

其中音频文件放在 /static/audios/vad_example.wav

markdown 内容如下:

复制代码
## 音频播放器示例
<audio controls  >
    <source src="vad_example.wav" type="audio/wav">
</audio>

预览显示为html

html 复制代码
<p>&lt;audio controls &gt;<br> &lt;source src="vad_example.wav" type="audio/wav"&gt;<br>&lt;/audio&gt;</p>

我们需要把上面代码变为如下html:

html 复制代码
<audio controls  >
    <source src="{{ url_for('static', filename='audios/vad_example.wav') }}" type="audio/wav">
</audio>

1编辑器预览区替换

markdown编辑器的html 代码:

html 复制代码
        <div id="create-editormd" class="editor">
            <textarea name="doc" id="doc">{{ request.form['doc'] or post['body'] if post else '' }}</textarea>
        </div>

js脚本:

预览区域默认html标签 editormd-preview

通过 onload 预览触发替换

js 复制代码
<script type="text/javascript">
    var testEditor;
    var textarea = document.getElementById('doc');

    $(function () {

        testEditor = editormd("create-editormd",
            {
                width: "90%",
                height: 640,
                syncScrolling: "single",
                path: "{{ url_for('static',filename='editormd/lib/') }}",
                imageUpload: true,
                imageFormats: ["jpg", "jpeg", "gif", "png", "bmp", "webp"],
                imageUploadURL: "/upload/upload_image",  // 设置图片上传的服务器路径
                onload: function () {
                    console.log("onload");
                    // 动态替换音频文件路径
                    const audioPathPrefix = "{{ url_for('static', filename='audios/') }}";
                    const previewContainer = document.querySelector('.editormd-preview');

                    if (previewContainer) {
                        console.log("Found preview container:", previewContainer);

                        // 查找并替换 <p> 标签内的音频标签
                        const pElements = previewContainer.querySelectorAll('p');
                        pElements.forEach(pElement => {
                            const htmlContent = pElement.innerHTML;

                            // 使用正则表达式匹配 <p> 标签内的音频标签
                            const audioRegex = /&lt;audio\s+controls[^&gt;]*&gt;[\s\S]*&lt;source\s+src="([^"]+)"\s+type="audio\/wav"[^&gt;]*&gt;[\s\S]*&lt;\/audio&gt;/g;
                            const matches = htmlContent.match(audioRegex);

                            if (matches) {
                                matches.forEach(match => {
                                    // 替换 &lt; 和 &gt; 为 < 和 >
                                    let actualHtml = match.replace(/&lt;/g, '<').replace(/&gt;/g, '>');

                                    // 移除 <br> 标签
                                    actualHtml = actualHtml.replace(/<br>/g, '');

                                    // 替换 <p> 标签内的内容
                                    pElement.innerHTML = pElement.innerHTML.replace(match, actualHtml);
                                    console.log("Replaced audio tag:", actualHtml);
                                });
                            }else{
                                console.log("No audio tags found in p element.");
                            }
                        });

                        // 更新音频文件路径
                        const audioElements = previewContainer.querySelectorAll('audio source');

                        if (audioElements.length > 0) {
                            console.log("Found audio elements:", audioElements);
                            audioElements.forEach(element => {
                                const originalSrc = element.getAttribute('src');
                                const newSrc = audioPathPrefix + originalSrc;
                                element.setAttribute('src', newSrc);
                                console.log("Updated src from", originalSrc, "to", newSrc);
                            });
                        } else {
                            console.log("No audio elements found.");
                        }
                    } else {
                        console.log("No preview container found.");
                    }
                }
            });
    });

</script>

显示页面 :

2 显示页面替换

html:

html 复制代码
    <!-- 预览区域 -->
    <div id="preview-wrapper" class="markdown-body">
        <!-- 这里会显示Markdown的渲染内容 -->
    </div>

js 脚本:

html 复制代码
<script type="text/javascript">

    document.addEventListener("DOMContentLoaded", function () {

        const preview = document.getElementById("preview-wrapper")

	// 更新预览
	preview.innerHTML = '';
	editormd.markdownToHTML(preview.id, {
		markdown: docBody,
		htmlDecode: "style,script,iframe",
		emoji: true,
		taskList: true,
		tex: true,
		flowChart: true,
		sequenceDiagram: true,
	});

	// 动态替换音频文件路径
	// 假设 audio_path 是从 Flask 传递过来的变量
	const audioPathPrefix = "{{ url_for('static', filename='audios/') }}";
	const audioElements = preview.querySelectorAll('audio source');
	audioElements.forEach(element => {
		const originalSrc = element.getAttribute('src');
		const newSrc = audioPathPrefix + originalSrc;
		element.setAttribute('src', newSrc);
	});

    });

</script>

显示页面 :

相关推荐
To_OC4 小时前
从一次栈溢出报错说起,我把递归彻底扒明白了
javascript·算法·程序员
kyriewen6 小时前
面试官问你:“AI 能写 80% 的代码了,公司为什么还需要你?”
前端·javascript·面试
Goodbye9 小时前
从 Token 到 Embedding:LLM 核心基础深度解析
javascript·人工智能
用户938515635079 小时前
工具调用背后:LLM 如何突破“缸中大脑”,操控真实世界?
javascript·人工智能
Goodbye9 小时前
从函数到智能:LLM Tool Use 深度解析
javascript·人工智能
半个落月9 小时前
大模型到底是怎么“调用工具”的?从一个 Node.js Demo 看懂 Tool Use
javascript·人工智能
烬羽9 小时前
中英文 token 数量差一倍?两段 JS 代码搞懂 LLM 底层是怎么"读"文字的
javascript·程序员·架构
山河木马9 小时前
矩阵专题1-怎么创建模型矩阵(uModelMatrix)
javascript·webgl·计算机图形学
前端开发爱好者14 小时前
支持 110 种文件预览!兼容 Vue、React、Svelte!
前端·javascript·vue.js
大家的林语冰15 小时前
👍 尤大重学 Webpack,Vite 8.1 再进化,打包模式复活!
前端·javascript·vite