nodejs:express + js-mdict 網頁查詢英漢詞典,能播放.spx 聲音

向 DeepSeek R1 提問:
我想寫一個Web 前端網頁,后臺用 nodejs + js-mdict?, 實現在線查詢英語單詞,并能播放.spx 聲音文件

1. 項目結構

首先,創建一個項目目錄,結構如下:

mydict-app/
├── public/
│   ├── index.html
│   ├── styles.css
│   └── script.js
├── server/
│   └── server.js
├── package.json
└── README.md

英漢詞典文件(*.mdx , *.mdd)? 已經放在 /js/testdict/?

2. 安裝依賴

在項目根目錄下運行以下命令,初始化項目并安裝所需的依賴:
cd mydict-app
npm init -y
npm install express
added 69 packages in 6s

npm install js-mdict
added 3 packages in 2s

3. 創建前端頁面

在?public/index1.htm?中創建一個簡單的HTML頁面,包含一個輸入框和三個按鈕用于查詢單詞:

<!DOCTYPE html>
<html lang="en">
<head><meta charset="UTF-8"><meta http-equiv="X-UA-Compatible" content="ie=edge"><meta name="viewport" content="width=device-width, initial-scale=1.0"><title>查詢英漢詞典 spx</title><script src="jquery.js"></script>   <style>
/* portrait 判斷為豎屏 */
@media only screen and (orientation: portrait){#lab1 {display:none;}
} 
/* landscape 判斷為橫屏 */ 
@media only screen and (orientation: landscape){#lab1 {display: ;}
}    </style>
</head>
<body><form name="form" id="form" action="search" method="GET" target="iframe"><label id="lab1">請輸入:</label><input type="text" name="word" id="word" size="30" placeholder="請輸入英文單詞"><input type="submit" name="eng_han" value="英譯漢"><input type="button" name="btn1" id="btn1" value="前綴查詢"><input type="button" name="btn2" id="btn2" value="模糊查詢"></form><p></p>
<div style="float:left; width:100%;"><div id="result" style="float:left; width:75%; height:400; border:2px;"><iframe name="iframe" id="iframe" width="100%" height="400"> </iframe></div><div id="alist" style="float:right; width:25%; height:400; border:2px;"></div>
</div><script src="bitstring.min.js"></script> 
<script src="pcmdata.min.js"></script> 
<script src="speex.js"></script> 
<script src="script1.js"></script>
</body>
</html>

?在?public?中添加一些英漢字典的樣式:
speex.js 下載網址:speex.js 是Web前端網頁播放.spx聲音文件所需的解碼器

在?public/script1.js?中編寫前端邏輯:

// decode Speex from mdict-js 
/** * @param bufSpx ArrayBuffer (Uint8Array) holding content of speex file (*.spx or *.ogg) */ function decodeSpx(bufSpx) { var stream, samples, st; var ogg, header, err; ogg = new Ogg(bufSpx, {file: true}); ogg.demux(); stream = ogg.bitstream(); header = Speex.parseHeader(ogg.frames[0]); console.log(header); comment = new SpeexComment(ogg.frames[1]); console.log(comment.data); st = new Speex({ quality: 8, mode: header.mode, rate: header.rate }); samples = st.decode(stream, ogg.segments); var waveData = PCMData.encode({ sampleRate: header.rate, channelCount: header.nb_channels, bytesPerSample: 2, data: samples }); // array buffer holding audio data in wav codec var bufWav = Speex.util.str2ab(waveData); // convert to a blob object var blob = new Blob([bufWav], {type: "audio/wav"}); // return a "blob://" url which can be used as a href anywhere return URL.createObjectURL(blob); }const iframe = $('#iframe')[0]; // 獲取 iframe DOM 元素const iframeDoc = iframe.contentDocument || iframe.contentWindow.document; 
// 頁面加載添加:監聽iframe網頁點擊事件  $(document).ready(function(){var listener = window.addEventListener('blur', function(){if (document.activeElement === document.getElementById('iframe')){$('iframe').contents().find('a').click(function(event){event.preventDefault();var a = $(this);if (a){var addr = a.attr('href');if (addr.indexOf('entry://')==0 && addr.indexOf('entry://#')!=0){             var word = encodeURIComponent(addr.substring(8));$.ajax({url: `/search?word=${word}`,method: 'GET',success: function (html) {// 將 HTML 內容加載到 iframe 中//$('#iframe').attr('srcdoc', html);if (html){// 寫入 HTML 內容iframeDoc.open();iframeDoc.write(html);iframeDoc.close();}},error: function (error) {console.error('entry:請求失敗:', error);}});} else if (addr.indexOf('sound://')==0){var url = "/data/" + addr.substring(8);fetch(url).then(response => response.arrayBuffer()).then(arrayBuffer => {// 將 ArrayBuffer 轉換為 Uint8Arrayconst uint8Array = new Uint8Array(arrayBuffer);   try {// 解碼.spx 數據后變為.wavvar blobUrl = decodeSpx(String.fromCharCode.apply(null, uint8Array));// 創建 Audio 并播放音頻var audio = new Audio(blobUrl);audio.addEventListener("canplaythrough", (event)=> {audio.play();});audio.addEventListener('error', (e) => {console.error('play error:', e);});} catch (error) {console.error('Error decoding spx data', error);}}).catch(error => {console.error('Error loading spx file', error);});}}})};});
});// 前綴查詢
$(function(){$("#btn1").click(function(){$.getJSON("/prefix?word="+$("#word").val(), function(data){var items = [];$.each(data, function(i, item){if (i<=20){items[i] = '<a href="/search?word=' +item+ '" target="iframe">' +item+ "</a><br>";}});var a = items.join('\n');if (a) $('#alist').html(a);})})
});// 模糊查詢
$(function(){$("#btn2").click(function(){$.getJSON("/fuzzy?word="+$("#word").val(), function(data){var items = [];$.each(data, function(i, item){if (i<=20){items[i] = '<a href="/search?word=' +item+ '" target="iframe">' +item+ "</a><br>";}});var a = items.join('\n');if (a) $('#alist').html(a);})})
});

4. 創建后端服務器

在?server/server.js?中編寫Node.js服務器代碼,使用?express?和?js-mdict?來處理查詢請求:

如何直接讀取.MDD文件中的.spx 音頻數據,編寫了升級版?server_spx.js 如下

const express = require('express');
const fs = require('fs');
const path = require('path');
const Mdict = require('js-mdict');
//console.log(Mdict);
const app = express();
const port = 8003;// 加載MDict詞典文件
//const mdict = new Mdict('path/to/your/dictionary.mdx');
const mdx = new Mdict.MDX('/path/to/your.mdx');
const mdd = new Mdict.MDD('/path/to/your.mdd');
//console.log(mdd.locate('\\goods'));
app.use(express.json());
app.use(express.urlencoded({ extended: false }));
// 提供靜態文件
app.use(express.static(path.join(__dirname, '../public')));const isWord = (txt) => {// 只允許字母、下劃線、空格、-return /^[a-zA-Z_ \-]+$/.test(txt);
};
// 處理查詢請求
app.get('/search', (req, res) => {let word = req.query.word;// 檢查word是否合法if (word.length>50 || !isWord(word)) {return res.status(400).send('Invalid input.');}if (word) {let data = mdx.lookup(word);console.log("cha: "+ word);if(data.definition){res.send(data.definition);} else {res.status(400).send('this word not found');}} else {res.status(400).send('error: No word input');}
});// 處理前綴查詢請求
app.get('/prefix', (req, res) => {let word = req.query.word;// 檢查word是否合法if (word.length>50 || !isWord(word)) {return res.status(400).send('Invalid input.');}if (word) {let alist = mdx.prefix(word);console.log("pre: "+ word);if(alist){let wordls = [];alist.forEach(function(value){wordls.push(value.keyText);});  res.json(wordls);} else {res.status(400).send('info: this word not found');}} else {res.status(400).send('error: No word input');}
});// 處理模糊查詢請求
app.get('/fuzzy', (req, res) => {let word = req.query.word;// 檢查word是否合法if (word.length>50 || !isWord(word)) {return res.status(400).send('Invalid input.');}if (word) {let alist = mdx.fuzzy_search(word,3,1);console.log("fuzzy: "+ word);if(alist){let wordls = [];alist.forEach(function(value){wordls.push(value.keyText);});  res.json(wordls);} else {res.status(400).send('info: this word not found');}} else {res.status(400).send('error: No word input');}
});// 指定目錄
const dir1 = "\\";// 實現文件下載,*/是路徑
app.get('/data/*/:fileName', (req, res, next) => {let path1 = req.params[0]; // 捕獲 * 匹配的部分let fileName = req.params.fileName; // 捕獲文件名// 檢查路徑中是否包含非法字符(如 ..)if (path1.includes('..') || fileName.includes('..')) {return res.status(400).send('Invalid path: Path traversal is not allowed.');}if (path.extname(fileName) === '.spx'){let filePath = path.join(dir1,path1, fileName);//console.log(filePath);let data = mdd.locate(filePath);if (data){console.log('key: '+ data.keyText);//console.log(Buffer.isBuffer(data.definition));if (data.definition){let binaryData = Buffer.from(data.definition, 'base64');//res.setHeader('Content-Type', 'application/octet-stream');res.set({'Content-Type': 'audio/ogg','Content-Disposition': 'attachment;','Content-Length': Buffer.byteLength(binaryData)});//console.log('bytes: '+ Buffer.byteLength(binaryData));res.end(binaryData);} else {res.status(400).send('error: data.definition is null');}} else {res.status(400).send('error: data is null');}} else {res.status(400).send('filename.ext is not .spx');}
});app.listen(port, () => {console.log(`Server is running on http://localhost:${port}`);
});

5. 運行項目

在項目根目錄下運行以下命令啟動服務器:node server/server_spx.js
然后打開瀏覽器,訪問?http://localhost:8003/index1.htm?,你應該可以看到一個簡單的詞典查詢頁面。輸入單詞并點擊查詢按鈕,頁面會顯示該單詞的釋義。

6. 部署

你可以將這個應用部署到任何支持 Node.js 的服務器上。

7. 進一步優化

  • 錯誤處理:在前端和后端添加更多的錯誤處理邏輯。

  • UI 改進:可以進一步美化前端頁面,添加加載動畫等。

  • 安全性:在生產環境中,確保對用戶輸入進行驗證和清理,防止 XSS 等攻擊。

8. 總結

通過以上步驟,你可以實現一個簡單的在線英語詞典查詢系統,并且能夠播放?.spx?格式的音頻文件。你可以根據需求進一步擴展功能,比如添加更多的詞典、支持更多格式的音頻文件等。

本文來自互聯網用戶投稿,該文觀點僅代表作者本人,不代表本站立場。本站僅提供信息存儲空間服務,不擁有所有權,不承擔相關法律責任。
如若轉載,請注明出處:http://www.pswp.cn/web/68210.shtml
繁體地址,請注明出處:http://hk.pswp.cn/web/68210.shtml
英文地址,請注明出處:http://en.pswp.cn/web/68210.shtml

如若內容造成侵權/違法違規/事實不符,請聯系多彩編程網進行投訴反饋email:809451989@qq.com,一經查實,立即刪除!

相關文章

Linux ftrace 內核跟蹤入門

文章目錄 ftrace介紹開啟ftraceftrace使用ftrace跟蹤指定內核函數ftrace跟蹤指定pid ftrace原理ftrace與stracetrace-cmd 工具KernelShark參考 ftrace介紹 Ftrace is an internal tracer designed to help out developers and designers of systems to find what is going on i…

【抽象代數】1.1. 運算及關系

集合與映射 定義1. 設 為 的子集&#xff0c;定義 到 的映射 &#xff1a; 使得 &#xff0c;稱 為 到 的嵌入映射。 定義2. 設 為 的子集&#xff0c; 為 到 的映射&#xff0c; 為 到 的映射&#xff0c;如果 &#xff0c;稱為的開拓&#xff0c; 為 的限制&…

pytest+request+yaml+allure 接口自動化測試全解析[手動寫的跟AI的對比]

我手動寫的:Python3:pytest+request+yaml+allure接口自動化測試_request+pytest+yaml-CSDN博客 AI寫的:pytest+request+yaml+allure 接口自動化測試全解析 在當今的軟件開發流程中,接口自動化測試扮演著至關重要的角色。它不僅能夠提高測試效率,確保接口的穩定性和正確性…

數據庫高安全—審計追蹤:傳統審計統一審計

書接上文數據庫高安全—角色權限&#xff1a;權限管理&權限檢查&#xff0c;從權限管理和權限檢查方面解讀了高斯數據庫的角色權限&#xff0c;本篇將從傳統審計和統一審計兩方面對高斯數據庫的審計追蹤技術進行解讀。 4 審計追蹤 4.1 傳統審計 審計內容的記錄方式通…

第三個Qt開發實例:利用之前已經開發好的LED驅動在Qt生成的界面中控制LED2的亮和滅

前言 上一篇博文 https://blog.csdn.net/wenhao_ir/article/details/145459006 中&#xff0c;我們是直接利用GPIO子系統控制了LED2的亮和滅&#xff0c;這篇博文中我們利用之前寫好的LED驅動程序在Qt的生成的界面中控制LED2的亮和滅。 之前已經在下面兩篇博文中實現了LED驅動…

deepseek來講lua

Lua 是一種輕量級、高效、可嵌入的腳本語言&#xff0c;廣泛應用于游戲開發、嵌入式系統、Web 服務器等領域。以下是 Lua 的主要特點和一些基本概念&#xff1a; 1. 特點 輕量級&#xff1a;Lua 的核心非常小&#xff0c;適合嵌入到其他應用程序中。高效&#xff1a;Lua 的執…

(動態規劃 leetcode377)組合求和IV

確立狀態轉移方程需要深入理解問題&#xff0c;合理定義子問題&#xff0c;找到邊界條件(比如dp[0])&#xff0c;分析狀態之間的轉移關系&#xff08;dp和dp之間的關系&#xff09;&#xff0c;并進行驗證。 遞歸是自頂向下&#xff0c;而dp是自下而上 這里是i作為目標值&…

解決aspose將Excel轉成PDF中文變成方框的亂碼問題

原文網址&#xff1a;解決aspose將Excel轉成PDF中文變成方框的亂碼問題_IT利刃出鞘的博客-CSDN博客 簡介 本文介紹如何解決aspose將Excel轉成PDF中文變成方框的亂碼問題。 問題描述 用aspose將word、excel等轉成PDF后&#xff0c;英文展示正常&#xff0c;但中文全部變成了…

Netty 核心原理與高并發場景實踐

在當今的網絡編程領域&#xff0c;隨著互聯網應用的不斷發展&#xff0c;對高并發、高性能網絡通信的需求日益增長。Netty 作為一款基于 Java 的異步事件驅動的網絡應用框架&#xff0c;憑借其卓越的性能和豐富的功能&#xff0c;成為了實現高并發網絡應用的首選工具。無論是在…

問題大集04-瀏覽器阻止從 本地 發起的跨域請求,因為服務器的響應頭 Access-Control-Allow-Origin 設置為通配符 *

1、問題 localhost/:1 Access to XMLHttpRequest at xxx&#xff08;請求&#xff09; from origin http://localhost:xxx&#xff08;本地&#xff09; has been blocked by CORS policy: The value of the Access-Control-Allow-Origin header in the response must not be t…

判斷192.168.1.0/24網絡中,當前在線的ip有哪些

需求&#xff1a;判斷192.168.1.0/24網絡中&#xff0c;當前在線的ip有哪些&#xff0c;并編寫腳本打印出來。 [rootopenEuler ~]# cat 1.sh #!/bin/bash for ip in $(seq 1 254); do ping -c 1 -W 1 "192.168.1.$ip" > /dev/null 2>&1 if [ $? …

vue-vite axios bug

axios-bug http proxy error Error: write ECONNABORTED 代碼寫法 一般baseURL不是單寫前綴就可以了嗎&#xff0c;為何要寫死就不會出現以上錯誤&#xff0c;求解。

【Spring】_SpringBoot配置文件

目錄 1.Spring Boot配置文件 1.1 Spring Boot 的配置文件類型及命名 1.2 properties和yml的優先級 2. properties配置文件 1.1 properties語法格式 1.2 自定義配置及配置文件的讀取 1.3 properties的缺點 3. yml配置文件 3.1 yml語法格式 3.2 自定義配置及配置文件的…

實操給觸摸一體機接入大模型語音交互

本文以CSK6 大模型開發板串口觸摸屏為例&#xff0c;實操講解觸摸一體機怎樣快速增加大模型語音交互功能&#xff0c;使用戶能夠通過語音在一體機上查詢信息、獲取智能回答及實現更多互動功能等。 在本文方案中通過CSK6大模型語音開發板采集用戶語音&#xff0c;將語音數據傳輸…

深入解析 FFmpeg 的 AAC 編解碼過程

深入解析 FFmpeg 的 AAC 編解碼過程 —— 技術詳解與代碼實現 AAC(Advanced Audio Coding) 是一種高效的有損音頻壓縮格式,因其高壓縮效率和良好的音質而被廣泛應用于流媒體、廣播和音頻存儲等領域。FFmpeg 是一個強大的多媒體處理工具,支持 AAC 的編碼和解碼。本文將詳細…

RabbitMQ 從入門到精通:從工作模式到集群部署實戰(一)

#作者&#xff1a;閆乾苓 文章目錄 RabbitMQ簡介RabbitMQ與VMware的關系架構工作流程RabbitMQ 隊列工作模式及適用場景簡單隊列模式&#xff08;Simple Queue&#xff09;工作隊列模式&#xff08;Work Queue&#xff09;發布/訂閱模式&#xff08;Publish/Subscribe&#xff…

探索 Spring Cloud Alibaba:開啟微服務架構新時代

一、引言 在當今數字化浪潮中&#xff0c;軟件系統的規模和復雜度不斷攀升&#xff0c;傳統的單體架構逐漸難以滿足快速迭代、高并發處理以及靈活擴展的需求。微服務架構應運而生&#xff0c;它將一個大型的應用拆分成多個小型、自治的服務&#xff0c;每個服務專注于特定的業務…

Linux基礎命令之Nginx中的rewrite功能(重新)

一、什么是Rewrite Rewrite也稱URL Rewrite&#xff0c;即URL重寫&#xff0c;就是把傳入Web的請求重定向到其他URL的過程。 1. URL Rewrite最常見的應用是URL偽靜態化&#xff0c;是將動態頁面顯示為靜態頁面方式的一種技術。比如http://www.123.com/news/index.php?id123 使…

anaconda使用

anaconda配置鏡像源&#xff1a; 引用&#xff1a;https://zhuanlan.zhihu.com/p/17776864328 # 顯示所有的鏡像源 conda config --show channels # 設置鏡像源 conda config --add channels https://mirrors.tuna.tsinghua.edu.cn/anaconda/pkgs/free/ conda config --add c…

DeepSeek 闡述 2025年前端發展趨勢

預測2025年前端的發展趨勢。首先&#xff0c;我需要考慮當前的前端 技術發展情況&#xff0c;以及近幾年的變化趨勢。比如&#xff0c;框架方面&#xff0c;React、Vue、Angular這些主流框架的更新方向和社區活躍度。可能用戶想知道未來哪些技術會更流行&#xff0c;或者需要學…