Files
2025-09-24 16:43:10 +08:00

751 lines
23 KiB
JavaScript
Raw Permalink Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

/**
* 音乐播放器 - 外置应用案例
* 展示了如何创建一个功能完整的外置应用
*/
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;