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>

显示页面 :

相关推荐
天若有情67311 分钟前
程序员原创|借鉴JS事件冒泡,根治电脑文件混乱的“冒泡整理法”
开发语言·javascript·windows·ecmascript·电脑·办公·日常
特种加菲猫1 小时前
继承,一场跨越时空的对话
开发语言·c++
FYKJ_20102 小时前
springboot校园兼职平台--附源码02041
java·javascript·spring boot·python·eclipse·django·php
玩转单片机与嵌入式2 小时前
玩转边缘AI(TInyML):需要掌握的C++知识汇总!
开发语言·c++·人工智能
茉莉玫瑰花茶2 小时前
Qt 信号与槽 [ 1 ]
开发语言·数据库·qt
AI人工智能+电脑小能手3 小时前
【大白话说Java面试题】【Java基础篇】第30题:JDK动态代理和CGLIB动态代理有什么区别
java·开发语言·后端·面试·代理模式
张健11564096484 小时前
临界区和同一线程上锁
java·开发语言·jvm
头发够用的程序员4 小时前
C++和Python面试经典算法汇总(一)
开发语言·c++·python·算法·容器·面试
夜猫逐梦4 小时前
【逆向经验】一篇文章讲透为什么CE搜不到Python游戏的内存值
开发语言·python·游戏