第一句子网 - 唯美句子、句子迷、好句子大全
第一句子网 > electron实现本地音乐播放器

electron实现本地音乐播放器

时间:2024-01-19 02:17:24

相关推荐

electron实现本地音乐播放器

本项目构建环境:

node => v12.15.0electron => 10.1.3

搭建环境:

# 克隆示例项目的仓库$ git clone /electron/electron-quick-start# 进入这个仓库$ cd electron-quick-start# 安装依赖并运行$ npm install && npm start

本项目所需依赖:

"devDependencies": {"electron": "^10.1.3","electron-builder": "^22.8.1"},"dependencies": {"bootstrap": "^4.5.2","electron-store": "^6.0.1","nodemon": "^2.0.4","uuid": "^8.3.1"}

本项目无使用任何前端框架,纯原生。(体验一把原生开发带来的快落吧)

修改 main.js

const {app, BrowserWindow, ipcMain, dialog } = require('electron')const DataStore = require('./renderer/MusicDataStore')const myStore = new DataStore({name: 'Music Data' })// 封装一个 BrowserWindow,避免每一次重复的编写class AppWindow extends BrowserWindow {constructor(config, fileLocation) {const baseConfig = {width: 960,height: 660,webPreferences: {nodeIntegration: true}}// 两个对象合并const finalConfig = {...baseConfig, ...config }super(finalConfig)this.loadFile(fileLocation)this.once('ready-to-show', () => {this.show()})}}app.on('ready', () => {// 加载主页面const mainWindow = new AppWindow({}, './renderer/index.html')mainWindow.webContents.on('did-finish-load', () => {mainWindow.send('getTracks', myStore.getTracks())})ipcMain.on('add-music-window', () => {const addWindow = new AppWindow({width: 800,height: 600,// 指定主进程parent: mainWindow}, './renderer/add.html')})// 添加数据ipcMain.on('add-tracks', (event, tracks) => {const updatedTracks = myStore.addTracks(tracks).getTracks()mainWindow.send('getTracks', updatedTracks)})// 删除数据ipcMain.on('delete-track', (event, id) => {const updatedTracks = myStore.deleteTrack(id).getTracks()mainWindow.send('getTracks', updatedTracks)})ipcMain.on('open-music-file', (event) => {dialog.showOpenDialog({properties: ['openFile', 'multiSelections'],filters: [{name: 'Music', extensions: ['mp3'] }]}).then((files) => {if (files) {event.sender.send('selected-file', files)}})})})

index.html

(这是我们的主页面)

<!DOCTYPE html><html><head><meta charset="UTF-8"><title>本地播放器</title><link rel="stylesheet" href="../node_modules/bootstrap/dist/css/bootstrap.min.css"><link rel="stylesheet" href="./index.css"><link rel="stylesheet" href="../font/iconfont.css"></head><body><div class="music-content"><div class="container"><h1>我的播放器</h1><button type="button" class="btn btn-primary btn-lg btn-block mt-4"id="add-music-button">添加歌曲到曲库</button><div id="tracksList" class="mt-4"></div><div class="container fixed-bottom pb-4 "><hr/><div class="row my-2" id="player-status"></div><div class="progress"><div class="progress-bar" id="player-progress" role="progressbar" style="width: 0%;">0%</div></div></div></div></div><script>require('./index.js');</script></body></html>

index.js

const {ipcRenderer } = require('electron')const {$, convertDuration, str } = require('./helper')let musicAudio = new Audio()let allTrackslet currentTrack$('add-music-button').addEventListener('click', () => {ipcRenderer.send('add-music-window')})const renderListHTML = (tracks) => {const tracksList = $('tracksList')const tracksListHTML = tracks.reduce((html, track) => {html += `<li class="row music-track list-group-item d-flex justify-content-between align-items-center"><div class="col-10"><i class="mr-2 text-secondary iconfont icon-yinle"></i><b>${str(track.fileName)}</b></div><div class="col-2"><i class="fas fa-play mr-3 icon-ziyuan iconfont" data-id="${track.id}"></i><i class="fas fa-trash-alt icon-del iconfont" data-id="${track.id}"></i></div></li>`return html}, '')const emptyTrackHTML = '<div class="alert alert-primary">还没有添加任何音乐</div>'tracksList.innerHTML = tracks.length ? `<ul class="list-group">${tracksListHTML}</ul>` : emptyTrackHTML}const renderPlayerHTML = (name, duration) => {const player = $('player-status')const html = `<div class="col font-weight-bold"">正在播放:${str(name)}</div><div class="col"><span id="current-seeker">00:00</span> / ${convertDuration(duration)}</div>`player.innerHTML = html}const updateProgressHTML = (currentTime, duration) => {// 计算 progress 的数值const progress = Math.floor(currentTime / duration * 100)const bar = $('player-progress')bar.innerHTML = progress + '%'bar.style.width = progress + '%'const seeker = $('current-seeker')seeker.innerHTML = convertDuration(currentTime)}ipcRenderer.on('getTracks', (event, tracks) => {allTracks = tracksrenderListHTML(tracks)})musicAudio.addEventListener('loadedmetadata', () => {// 开始渲染播放器状态renderPlayerHTML(currentTrack.fileName, musicAudio.duration)})musicAudio.addEventListener('timeupdate', () => {// 更新播放器状态updateProgressHTML(musicAudio.currentTime, musicAudio.duration)})$('tracksList').addEventListener('click', (event) => {event.preventDefault()const {dataset, classList } = event.targetconst id = dataset && dataset.idif (id && classList.contains('icon-ziyuan')) {// 播放音乐if (currentTrack && currentTrack.id === id) {// 继续播放音乐musicAudio.play()} else {// 播放新的歌曲currentTrack = allTracks.find(track => track.id === id)musicAudio.src = currentTrack.pathmusicAudio.play()const resetIconEle = document.querySelector('.icon-zanting')if (resetIconEle) {// 更改播放图标resetIconEle.classList.replace('icon-zanting', 'icon-ziyuan')}}classList.replace('icon-ziyuan', 'icon-zanting')} else if (id && classList.contains('icon-zanting')) {// 暂停musicAudio.pause()classList.replace('icon-zanting', 'icon-ziyuan')} else if (id && classList.contains('icon-del')) {// 删除ipcRenderer.send('delete-track', id)}})

MusicDataStore.js

(这是存储音乐数据的地方)

const Store = require('electron-store')const {path} = require('path')// 保证唯一的IDconst {v4: uuidv4 } = require('uuid');class DataStore extends Store {constructor(settings) {super(settings);this.tracks = this.get('tracks') || []}// 保存数据saveTracks() {this.set('tracks', this.tracks)return this}// 获取数据getTracks() {return this.get('tracks') || []}// 添加数据addTracks(tracks) {const tracksWithProps = tracks.map(track => {return {id: uuidv4(),path: track,fileName: track}}).filter(track => {const currentTrackPath = this.getTracks().map(track => track.path)return currentTrackPath.indexOf(track.path) < 0})this.tracks = [...this.tracks, ...tracksWithProps]return this.saveTracks()}// 删除数据deleteTrack(deleteId) {this.tracks = this.tracks.filter(item => item.id !== deleteId)return this.saveTracks()}}module.exports = DataStore

大概的主代码就差不多了。剩下的一些辅助代码我就不写出来了。

(这个 demo 其实是存在 bug,就是显示音乐的名字有一点问题)

我在 electron 引入 path 模块是 undefined,这个我不知道是为什么,所以代码的名字我只是做了很简单的处理。就很丑了。

代码地址奉上

/suiboyu/electron-music

下载之后的代码中electron-music/outName/appName-win32-x64,中有一个appName.exe就是打包出来的 exe(这个打包好像也行有点问题的,不过 demo 嘛,刚刚开始学习,凑合凑合用吧)

本内容不代表本网观点和政治立场,如有侵犯你的权益请联系我们处理。
网友评论
网友评论仅供其表达个人看法,并不表明网站立场。