Files
vue-desktop/public/apps/music-player/app.js

751 lines
23 KiB
JavaScript
Raw Normal View History

2025-09-24 16:43:10 +08:00
/**
* 音乐播放器 - 外置应用案例
* 展示了如何创建一个功能完整的外置应用
*/
class MusicPlayer {
constructor() {
// 应用状态
this.isPlaying = false;
this.currentTrackIndex = 0;
this.playlist = [];
this.isShuffleMode = false;
this.repeatMode = 'none'; // none, one, all
this.volume = 0.7;
// DOM 元素
this.audioPlayer = null;
this.playPauseBtn = null;
this.progressBar = null;
this.volumeBar = null;
this.playlist_element = null;
// 系统SDK
this.systemSDK = null;
this.init();
}
/**
* 初始化应用
*/
async init() {
console.log('[音乐播放器] 初始化开始');
// 等待DOM加载完成
if (document.readyState === 'loading') {
document.addEventListener('DOMContentLoaded', () => this.setupApp());
} else {
this.setupApp();
}
// 初始化系统SDK
await this.initSystemSDK();
}
/**
* 初始化系统SDK
*/
async initSystemSDK() {
try {
console.log('[音乐播放器] 开始初始化系统SDK');
// 等待系统SDK可用
let attempts = 0;
const maxAttempts = 100; // 增加尝试次数
while (!window.SystemSDK && attempts < maxAttempts) {
console.log(`[音乐播放器] 等待SystemSDK可用... (尝试 ${attempts + 1}/${maxAttempts})`);
await new Promise(resolve => setTimeout(resolve, 100));
attempts++;
}
if (window.SystemSDK) {
console.log('[音乐播放器] SystemSDK对象已找到开始初始化');
// 初始化SDK
const initResult = await window.SystemSDK.init({
appId: 'music-player',
appName: '音乐播放器',
version: '1.0.0',
permissions: ['storage.read', 'storage.write']
});
if (initResult.success) {
this.systemSDK = window.SystemSDK;
console.log('[音乐播放器] 系统SDK初始化成功');
// 显示系统通知
if (this.systemSDK.ui) {
try {
await this.systemSDK.ui.showNotification({
title: '音乐播放器',
message: '应用已启动,准备播放音乐!',
type: 'info'
});
} catch (error) {
console.warn('[音乐播放器] 显示通知失败:', error);
}
}
// 从本地存储恢复播放列表
await this.loadPlaylistFromStorage();
} else {
console.error('[音乐播放器] 系统SDK初始化失败:', initResult.error);
}
} else {
console.error('[音乐播放器] 系统SDK不可用已达到最大尝试次数');
}
} catch (error) {
console.error('[音乐播放器] 系统SDK初始化失败:', error);
}
}
/**
* 设置应用界面和事件
*/
setupApp() {
console.log('[音乐播放器] 设置界面');
// 获取DOM元素
this.audioPlayer = document.getElementById('audioPlayer');
this.playPauseBtn = document.getElementById('playPauseBtn');
this.progressBar = document.getElementById('progressBar');
this.volumeBar = document.getElementById('volumeBar');
this.playlist_element = document.getElementById('playlist');
// 设置音频事件
this.setupAudioEvents();
// 设置控制按钮事件
this.setupControlEvents();
// 设置窗口控制事件
this.setupWindowControls();
// 设置键盘快捷键
this.setupKeyboardShortcuts();
// 初始化音量
this.setVolume(this.volume * 100);
console.log('[音乐播放器] 应用设置完成');
}
/**
* 设置音频播放器事件
*/
setupAudioEvents() {
if (!this.audioPlayer) return;
// 播放开始
this.audioPlayer.addEventListener('play', () => {
this.isPlaying = true;
this.updatePlayButton();
this.updateStatus('正在播放');
});
// 播放暂停
this.audioPlayer.addEventListener('pause', () => {
this.isPlaying = false;
this.updatePlayButton();
this.updateStatus('已暂停');
});
// 播放结束
this.audioPlayer.addEventListener('ended', () => {
this.handleTrackEnded();
});
// 时间更新
this.audioPlayer.addEventListener('timeupdate', () => {
this.updateProgress();
});
// 加载完成
this.audioPlayer.addEventListener('loadedmetadata', () => {
this.updateTotalTime();
});
// 加载错误
this.audioPlayer.addEventListener('error', (e) => {
console.error('[音乐播放器] 播放错误:', e);
this.updateStatus('播放出错');
this.nextTrack();
});
}
/**
* 设置控制按钮事件
*/
setupControlEvents() {
// 播放/暂停
document.getElementById('playPauseBtn')?.addEventListener('click', () => {
this.togglePlayPause();
});
// 上一曲
document.getElementById('prevBtn')?.addEventListener('click', () => {
this.prevTrack();
});
// 下一曲
document.getElementById('nextBtn')?.addEventListener('click', () => {
this.nextTrack();
});
// 随机播放
document.getElementById('shuffleBtn')?.addEventListener('click', () => {
this.toggleShuffle();
});
// 重复播放
document.getElementById('repeatBtn')?.addEventListener('click', () => {
this.toggleRepeat();
});
// 进度条
this.progressBar?.addEventListener('input', () => {
this.seekTo(this.progressBar.value);
});
// 音量控制
this.volumeBar?.addEventListener('input', () => {
this.setVolume(this.volumeBar.value);
});
// 文件选择
document.getElementById('addFilesBtn')?.addEventListener('click', () => {
document.getElementById('fileInput').click();
});
document.getElementById('fileInput')?.addEventListener('change', (e) => {
this.handleFileSelection(e.target.files);
});
// 清空播放列表
document.getElementById('clearPlaylistBtn')?.addEventListener('click', () => {
this.clearPlaylist();
});
}
/**
* 设置窗口控制事件
*/
setupWindowControls() {
// 最小化
document.getElementById('minimizeBtn')?.addEventListener('click', () => {
if (this.systemSDK) {
this.systemSDK.window.minimize();
}
});
// 最大化/还原
document.getElementById('maximizeBtn')?.addEventListener('click', () => {
if (this.systemSDK) {
this.systemSDK.window.toggleMaximize();
}
});
// 关闭
document.getElementById('closeBtn')?.addEventListener('click', () => {
if (this.systemSDK) {
this.systemSDK.window.close();
} else {
window.close();
}
});
}
/**
* 设置键盘快捷键
*/
setupKeyboardShortcuts() {
document.addEventListener('keydown', (e) => {
if (e.target.tagName === 'INPUT') return;
switch (e.code) {
case 'Space':
e.preventDefault();
this.togglePlayPause();
break;
case 'ArrowLeft':
e.preventDefault();
this.prevTrack();
break;
case 'ArrowRight':
e.preventDefault();
this.nextTrack();
break;
case 'ArrowUp':
e.preventDefault();
this.setVolume(Math.min(100, this.volume * 100 + 5));
break;
case 'ArrowDown':
e.preventDefault();
this.setVolume(Math.max(0, this.volume * 100 - 5));
break;
}
});
}
/**
* 处理文件选择
*/
handleFileSelection(files) {
const audioFiles = Array.from(files).filter(file =>
file.type.startsWith('audio/')
);
if (audioFiles.length === 0) {
this.updateStatus('未选择音频文件');
return;
}
audioFiles.forEach(file => {
const track = {
id: Date.now() + Math.random(),
name: file.name.replace(/\.[^/.]+$/, ""),
file: file,
url: URL.createObjectURL(file),
duration: 0
};
this.playlist.push(track);
});
this.updatePlaylist();
this.savePlaylistToStorage();
this.updateStatus(`添加了 ${audioFiles.length} 首歌曲`);
// 如果是第一次添加歌曲,自动播放
if (this.playlist.length === audioFiles.length) {
this.loadTrack(0);
}
}
/**
* 播放/暂停切换
*/
togglePlayPause() {
if (!this.audioPlayer || this.playlist.length === 0) {
this.updateStatus('播放列表为空');
return;
}
if (this.isPlaying) {
this.audioPlayer.pause();
} else {
this.audioPlayer.play().catch(error => {
console.error('[音乐播放器] 播放失败:', error);
this.updateStatus('播放失败');
});
}
}
/**
* 上一曲
*/
prevTrack() {
if (this.playlist.length === 0) return;
let newIndex;
if (this.isShuffleMode) {
newIndex = Math.floor(Math.random() * this.playlist.length);
} else {
newIndex = this.currentTrackIndex - 1;
if (newIndex < 0) {
newIndex = this.playlist.length - 1;
}
}
this.loadTrack(newIndex);
}
/**
* 下一曲
*/
nextTrack() {
if (this.playlist.length === 0) return;
let newIndex;
if (this.isShuffleMode) {
newIndex = Math.floor(Math.random() * this.playlist.length);
} else {
newIndex = this.currentTrackIndex + 1;
if (newIndex >= this.playlist.length) {
newIndex = 0;
}
}
this.loadTrack(newIndex);
}
/**
* 加载指定曲目
*/
loadTrack(index) {
if (index < 0 || index >= this.playlist.length) return;
this.currentTrackIndex = index;
const track = this.playlist[index];
this.audioPlayer.src = track.url;
this.updateCurrentTrackInfo(track);
this.updatePlaylistHighlight();
if (this.isPlaying) {
this.audioPlayer.play().catch(error => {
console.error('[音乐播放器] 播放失败:', error);
});
}
}
/**
* 处理曲目播放结束
*/
handleTrackEnded() {
switch (this.repeatMode) {
case 'one':
this.audioPlayer.currentTime = 0;
this.audioPlayer.play();
break;
case 'all':
this.nextTrack();
break;
default:
if (this.currentTrackIndex < this.playlist.length - 1) {
this.nextTrack();
} else {
this.isPlaying = false;
this.updatePlayButton();
this.updateStatus('播放完成');
}
break;
}
}
/**
* 切换随机播放
*/
toggleShuffle() {
this.isShuffleMode = !this.isShuffleMode;
const btn = document.getElementById('shuffleBtn');
if (btn) {
btn.classList.toggle('active', this.isShuffleMode);
}
this.updateStatus(this.isShuffleMode ? '随机播放已开启' : '随机播放已关闭');
}
/**
* 切换重复播放模式
*/
toggleRepeat() {
const modes = ['none', 'one', 'all'];
const currentIndex = modes.indexOf(this.repeatMode);
this.repeatMode = modes[(currentIndex + 1) % modes.length];
const btn = document.getElementById('repeatBtn');
if (btn) {
btn.classList.toggle('active', this.repeatMode !== 'none');
switch (this.repeatMode) {
case 'one':
btn.textContent = '🔂';
break;
case 'all':
btn.textContent = '🔁';
break;
default:
btn.textContent = '🔁';
break;
}
}
const modeNames = { none: '关闭', one: '单曲循环', all: '列表循环' };
this.updateStatus(`重复播放: ${modeNames[this.repeatMode]}`);
}
/**
* 设置音量
*/
setVolume(value) {
this.volume = value / 100;
if (this.audioPlayer) {
this.audioPlayer.volume = this.volume;
}
const volumeValue = document.getElementById('volumeValue');
if (volumeValue) {
volumeValue.textContent = `${Math.round(value)}%`;
}
if (this.volumeBar) {
this.volumeBar.value = value;
}
}
/**
* 跳转到指定时间
*/
seekTo(percentage) {
if (this.audioPlayer && this.audioPlayer.duration) {
const time = (percentage / 100) * this.audioPlayer.duration;
this.audioPlayer.currentTime = time;
}
}
/**
* 更新播放按钮状态
*/
updatePlayButton() {
if (this.playPauseBtn) {
this.playPauseBtn.textContent = this.isPlaying ? '⏸️' : '▶️';
this.playPauseBtn.classList.toggle('playing', this.isPlaying);
}
}
/**
* 更新进度条
*/
updateProgress() {
if (this.audioPlayer && this.progressBar && this.audioPlayer.duration) {
const progress = (this.audioPlayer.currentTime / this.audioPlayer.duration) * 100;
this.progressBar.value = progress;
const currentTime = document.getElementById('currentTime');
if (currentTime) {
currentTime.textContent = this.formatTime(this.audioPlayer.currentTime);
}
}
}
/**
* 更新总时长显示
*/
updateTotalTime() {
if (this.audioPlayer) {
const totalTime = document.getElementById('totalTime');
if (totalTime) {
totalTime.textContent = this.formatTime(this.audioPlayer.duration || 0);
}
}
}
/**
* 更新当前曲目信息
*/
updateCurrentTrackInfo(track) {
const titleElement = document.getElementById('trackTitle');
const artistElement = document.getElementById('trackArtist');
const albumElement = document.getElementById('trackAlbum');
if (titleElement) titleElement.textContent = track.name;
if (artistElement) artistElement.textContent = '未知艺术家';
if (albumElement) albumElement.textContent = '未知专辑';
}
/**
* 更新播放列表显示
*/
updatePlaylist() {
if (!this.playlist_element) return;
if (this.playlist.length === 0) {
this.playlist_element.innerHTML = '<li class="playlist-empty">暂无音乐文件</li>';
this.updateTrackCount();
return;
}
this.playlist_element.innerHTML = this.playlist.map((track, index) => `
<li class="playlist-item ${index === this.currentTrackIndex ? 'playing' : ''}"
data-index="${index}">
<span class="track-number">${index + 1}</span>
<div class="track-details">
<div class="track-name">${track.name}</div>
<div class="track-duration">${this.formatTime(track.duration)}</div>
</div>
</li>
`).join('');
// 添加点击事件
this.playlist_element.querySelectorAll('.playlist-item').forEach(item => {
item.addEventListener('click', () => {
const index = parseInt(item.dataset.index);
this.loadTrack(index);
if (!this.isPlaying) {
this.togglePlayPause();
}
});
});
this.updateTrackCount();
}
/**
* 更新播放列表高亮
*/
updatePlaylistHighlight() {
if (!this.playlist_element) return;
this.playlist_element.querySelectorAll('.playlist-item').forEach((item, index) => {
item.classList.toggle('playing', index === this.currentTrackIndex);
});
}
/**
* 清空播放列表
*/
clearPlaylist() {
this.playlist.forEach(track => {
if (track.url) {
URL.revokeObjectURL(track.url);
}
});
this.playlist = [];
this.currentTrackIndex = 0;
this.isPlaying = false;
if (this.audioPlayer) {
this.audioPlayer.pause();
this.audioPlayer.src = '';
}
this.updatePlaylist();
this.updatePlayButton();
this.updateCurrentTrackInfo({ name: '选择音乐文件开始播放' });
this.updateStatus('播放列表已清空');
this.savePlaylistToStorage();
}
/**
* 更新状态栏
*/
updateStatus(message) {
const statusText = document.getElementById('statusText');
if (statusText) {
statusText.textContent = message;
}
}
/**
* 更新歌曲数量
*/
updateTrackCount() {
const trackCount = document.getElementById('trackCount');
if (trackCount) {
trackCount.textContent = `${this.playlist.length} 首歌曲`;
}
}
/**
* 格式化时间显示
*/
formatTime(seconds) {
if (!seconds || isNaN(seconds)) return '00:00';
const mins = Math.floor(seconds / 60);
const secs = Math.floor(seconds % 60);
return `${mins.toString().padStart(2, '0')}:${secs.toString().padStart(2, '0')}`;
}
/**
* 保存播放列表到本地存储
*/
savePlaylistToStorage() {
try {
const playlistData = this.playlist.map(track => ({
id: track.id,
name: track.name,
duration: track.duration
}));
// 使用系统SDK进行存储操作
if (this.systemSDK && this.systemSDK.storage) {
console.log('[音乐播放器] 保存播放列表到系统存储');
this.systemSDK.storage.set('music-player-playlist', JSON.stringify(playlistData))
.then(result => {
if (result.success) {
console.log('[音乐播放器] 播放列表保存成功');
} else {
console.warn('[音乐播放器] 保存播放列表到系统存储失败:', result.error);
}
})
.catch(error => {
console.error('[音乐播放器] 保存播放列表失败:', error);
});
} else {
console.warn('[音乐播放器] 系统SDK未初始化无法保存播放列表');
}
} catch (error) {
console.error('[音乐播放器] 保存播放列表失败:', error);
}
}
/**
* 从本地存储加载播放列表
*/
async loadPlaylistFromStorage() {
try {
// 使用系统SDK进行存储操作
if (this.systemSDK && this.systemSDK.storage) {
console.log('[音乐播放器] 从系统存储加载播放列表');
const result = await this.systemSDK.storage.get('music-player-playlist');
if (result.success && result.data) {
try {
const playlistData = JSON.parse(result.data);
console.log(`[音乐播放器] 从系统存储加载了 ${playlistData.length} 首歌曲`);
// 这里可以恢复播放列表
} catch (parseError) {
console.warn('[音乐播放器] 解析播放列表数据失败:', parseError);
}
} else if (!result.success) {
console.warn('[音乐播放器] 从系统存储加载播放列表失败:', result.error);
}
} else {
console.warn('[音乐播放器] 系统SDK未初始化无法加载播放列表');
}
} catch (error) {
console.error('[音乐播放器] 加载播放列表失败:', error);
}
}
/**
* 清理资源
*/
cleanup() {
console.log('[音乐播放器] 清理资源');
// 暂停播放
if (this.audioPlayer) {
this.audioPlayer.pause();
}
// 释放对象URL
this.playlist.forEach(track => {
if (track.url) {
URL.revokeObjectURL(track.url);
}
});
// 保存状态
this.savePlaylistToStorage();
}
}
// 应用启动
let musicPlayerApp;
// 确保在DOM加载完成后启动应用
if (document.readyState === 'loading') {
document.addEventListener('DOMContentLoaded', () => {
musicPlayerApp = new MusicPlayer();
});
} else {
musicPlayerApp = new MusicPlayer();
}
// 导出供外部使用
window.MusicPlayerApp = musicPlayerApp;