-
不添加文件目录,加载任意的本地文件系统内的音频文件,直接调用播放器播放
-
前一首后一首功能
-
声音音量控制
-
自定义软件窗口
如何关联播放
如何实现关联播放?因为对electron
不是很熟,查了很久 electron
的资料,终于找到了配置项,需要配置 fileAssociations
fileAssociations: [
{
ext: [“mp3”, “wav”, “flac”, “ogg”, “m4a”],
name: “music”,
role: “Editor”
}
],
配置好后,通过 electron
的open-file事件,获取打开的音频文件的本地路径。对于 windows
, 需要通过 process.argv
,来获取文件路径。
const filePath = process.argv[1];
如何加载本地音频文件
上一步通过配置拿到文件的本地路径后,下一步就是通过路径读取音频文件的信息。由于音频的插件无法解析绝对路径,所以需要通过node的文件系统,通过fs.readFileSync读取到文件的buffer信息。
let buffer = fs.readFileSync(diskPath); //读取文件,并将缓存区进行转换
读取后需要将buffer转换成node可读流
const stream = this.bufferToStream(buffer);//将buffer数据转换成node 可读流
转换方法 bufferToStream
bufferToStream(binary) {
const readableInstanceStream = new Readable({
read() {
this.push(binary);
this.push(null);
}
});
return readableInstanceStream;
}
转换成流后需要将音频流转换成blob对象来加载,实现方法
module.exports = streamToBlob
function streamToBlob (stream, mimeType) {
if (mimeType != null && typeof mimeType !== ‘string’) {
throw new Error(‘Invalid mimetype, expected string.’)
}
return new Promise((resolve, reject) => {
const chunks = []
stream
.on(‘data’, chunk => chunks.push(chunk))
.once(‘end’, () => {
const blob = mimeType != null
? new Blob(chunks, { type: mimeType })
: new Blob(chunks)
resolve(blob)
})
.once(‘error’, reject)
})
}
转blob
let fileUrl; // blob对象
streamToBlob(stream)
.then(res => {
fileUrl = res;
// console.log(fileUrl);
//将blob对象转成blob链接
let filePath = window.URL.createObjectURL(fileUrl);
// console.log(filePath);
this.wavesurfer.load(filePath);
// 自动播放
this.wavesurfer.play();
this.playing = true;
})
.catch(err => {
console.log(err);
});
这样就实现了加载本地文件播放了
上一首下一首功能
这里的上一首下一首的功能是基于上面获取到的文件的绝对路径,通过node的path模块,path.dirname获取到文件的父级目录。
const dirPath = path.dirname(diskPath);
然后通过fs.readdir读取目录下所有文件,会返回一个文件名数组,找到该目录下正在播放的文件的下标,通过数组下标判断前一首和后一首歌曲的名称,然后再组装成绝对路径,读取资源播放
playFileList(diskPath, pos) {
let isInFiles;
let fileIndex;
let preIndex;
let nextIndex;
let fullPath;
let dirPath = path.dirname(diskPath);
let basename = path.basename(diskPath);
fs.readdir(dirPath, (err, files) => {
isInFiles = files.includes(basename);
if (isInFiles && pos === “pre”) {
fileIndex = files.indexOf(basename);
preIndex = fileIndex - 1;
fullPath = path.resolve(dirPath, files[preIndex]);
this.loadMusic(fullPath);
}
if (isInFiles && pos === “next”) {
fileIndex = files.indexOf(basename);
nextIndex = fileIndex + 1;
fullPath = path.resolve(dirPath, files[nextIndex]);
this.loadMusic(fullPath);
}
});
},
声音音量控制
音量控制需要通过监听input的键入事件,获取到range的值,然后通过设置样式background-image,动态计算百分比,然后调用wavesurfer的setVolume方法调节音量
:style=“background-image:linear-gradient( to right, ${fillColor}, ${fillColor} ${percent}, ${emptyColor} ${percent})
”
改变音量changeVol事件
changeVol(e) {
let val = e.target.value;
let min = e.target.min;
let max = e.target.max;
let rate = (val - min) / (max - min);
this.percent = 100 * rate + “%”;
console.log(this.percent, rate);
this.wavesurfer.setVolume(Number(rate));
},
自定义标题栏
个人觉得系统自带的菜单栏太丑了,就给设置了无边框再自己加上最小化,关闭的功能。最小化,关闭是通过ipc通信,渲染进程监听到有点击操作后,通知主进程进行相应的操作。
渲染进程
close() {
ipcRenderer.send(“close”);
},
minimize() {
ipcRenderer.send(“minimize”);
}
主进程
ipcMain.on(“close”, () => {
win.close();
app.quit();
});
ipcMain.on(“minimize”, () => {
win.minimize();
});
打开多个实例的问题
在实际测试的过程中发现会出现,打开一首新的音乐播放,就会出现重新开一个实例的现象,不能实现覆盖播放,后面查阅资料发现electron有一个second-instance事件,可以监听是否打开了第二个实例。当第二个实例被执行并且调用 app.requestSingleInstanceLock()") 时,这个事件将在应用程序的首个实例中触发,并且会返回第二个实例的相关信息,然后通过主进程通知渲染进程,告知渲染进程第二个实例的本地绝对路径,渲染进程接收到信息后,立马加载第二个实例的资源。app.requestSingleInstanceLock(),表示应用程序实例是否成功取得了锁。如果它取得锁失败,可以假设另一个应用实例已经取得了锁并且仍旧在运行,所以可以直接关闭掉,这样就避免了打开多个实例的问题
主进程
const gotTheLock = app.requestSingleInstanceLock();
if (gotTheLock) {
app.on(“second-instance”, (event, commandLine, workingDirectory) => {
// 监听是否有第二个实例,向渲染进程发送第二个实例的本地路径
win.webContents.send(“path”, ${commandLine[commandLine.length - 1]}
);
if (win) {
if (win.isMinimized()) win.restore();
win.focus();
}
});
app.on(“ready”, async () => {
createWindow();
});
} else {
app.quit();
}
渲染进程
ipcRenderer.on(“path”, (event, arg) => {
const newOriginPath = arg;
// console.log(newOriginPath);
this.loadMusic(newOriginPath);
});
自动更新
需求的起因是,在很兴奋的给女朋友成品的时候,尴尬的被女朋友试出很多bug(捂脸ing),然后频繁的修改打包,然后通过私发传给她。特别麻烦,所以这个需求很急迫。最后查了资料,通过electron-updater实现了这个需求.
安装electron-updater
自我介绍一下,小编13年上海交大毕业,曾经在小公司待过,也去过华为、OPPO等大厂,18年进入阿里一直到现在。
深知大多数前端工程师,想要提升技能,往往是自己摸索成长或者是报班学习,但对于培训机构动则几千的学费,着实压力不小。自己不成体系的自学效果低效又漫长,而且极易碰到天花板技术停滞不前!
因此收集整理了一份《2024年Web前端开发全套学习资料》,初衷也很简单,就是希望能够帮助到想自学提升又不知道该从何学起的朋友,同时减轻大家的负担。
既有适合小白学习的零基础资料,也有适合3年以上经验的小伙伴深入学习提升的进阶课程,基本涵盖了95%以上前端开发知识点,真正体系化!
由于文件比较大,这里只是将部分目录截图出来,每个节点里面都包含大厂面经、学习笔记、源码讲义、实战项目、讲解视频,并且会持续更新!
如果你觉得这些内容对你有帮助,可以扫码获取!!(备注:前端)
核心竞争力,怎么才能提高呢?
成年人想要改变生活,逆转状态?那就开始学习吧~
万事开头难,但是程序员这一条路坚持几年后发展空间还是非常大的,一切重在坚持。
为了帮助大家更好更高效的准备面试,特别整理了《前端工程师面试手册》电子稿文件。
前端面试题汇总
JavaScript
性能
linux
前端资料汇总
完整版PDF资料免费分享,只需你点赞支持,动动手指点击此处就可免费领取了。
前端工程师岗位缺口一直很大,符合岗位要求的人越来越少,所以学习前端的小伙伴要注意了,一定要把技能学到扎实,做有含金量的项目,这样在找工作的时候无论遇到什么情况,问题都不会大。
ript**
性能
linux
前端资料汇总
完整版PDF资料免费分享,只需你点赞支持,动动手指点击此处就可免费领取了。
前端工程师岗位缺口一直很大,符合岗位要求的人越来越少,所以学习前端的小伙伴要注意了,一定要把技能学到扎实,做有含金量的项目,这样在找工作的时候无论遇到什么情况,问题都不会大。