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