网页 MetingAPI 音乐播放卡片

程 涛 发布于 19 小时前 9 次阅读


<script>
// 音乐播放器模块 - 纯JS版本(移除歌词功能)
class MusicPlayer {
    constructor(options = {}) {
        // 默认配置
        this.config = {
            container: options.container || document.body,
            position: options.position || 'bottom-left', // bottom-left, bottom-right
            themeColor: options.themeColor || '#6366f1',
            musicApi: options.musicApi || 'https://MetingAPI:网易云音乐ID'
        };
        
        // 状态变量
        this.aplayerInstance = null;
        this.isPlaying = false;
        
        // 初始化
        this.init();
    }

    // 初始化播放器
    async init() {
        try {
            // 1. 加载必要的外部资源
            await this.loadExternalResources();
            
            // 2. 创建DOM结构(移除歌词容器相关)
            this.createDOM();
            
            // 3. 初始化APlayer
            await this.initAPlayer();
            
        } catch (error) {
            console.error('播放器初始化失败:', error);
            this.playerContainer.innerHTML = `<div style="color:${this.config.themeColor}; font-size:0.8rem; padding:10px; text-align:center;">音乐加载失败,请刷新重试</div>`;
        }
    }

    // 加载外部资源
    loadExternalResources() {
        return new Promise((resolve) => {
            let loadedCount = 0;
            const totalResources = 3; // 移除了APlayer资源的加载计数
            
            const checkComplete = () => {
                loadedCount++;
                if (loadedCount >= totalResources) resolve();
            };
            
            // 加载Tailwind CSS
            const tailwindJS = document.createElement('script');
            tailwindJS.src = 'https://cdn.tailwindcss.com';
            tailwindJS.onload = () => {
                tailwind.config = {
                    theme: {
                        extend: {
                            colors: {
                                primary: this.config.themeColor,
                            },
                        }
                    }
                };
                checkComplete();
            };
            tailwindJS.onerror = checkComplete;
            document.head.appendChild(tailwindJS);
            
            // 加载Font Awesome
            const fontAwesomeCSS = document.createElement('link');
            fontAwesomeCSS.rel = 'stylesheet';
            fontAwesomeCSS.href = 'https://cdn.jsdelivr.net/npm/font-awesome@4.7.0/css/font-awesome.min.css';
            fontAwesomeCSS.onload = checkComplete;
            fontAwesomeCSS.onerror = checkComplete;
            document.head.appendChild(fontAwesomeCSS);

            // 检查APlayer是否已加载
            if (typeof APlayer !== 'undefined') {
                checkComplete();
            } else {
                // 如果未加载,监听加载完成
                const checkAPlayerLoaded = setInterval(() => {
                    if (typeof APlayer !== 'undefined') {
                        clearInterval(checkAPlayerLoaded);
                        checkComplete();
                    }
                }, 100);
            }
        });
    }

    // 创建DOM结构和样式(移除歌词相关DOM)
    createDOM() {
        // 创建样式(移除歌词相关样式)
        this.createStyles();
        
        // 创建播放器容器
        this.playerContainer = document.createElement('div');
        this.playerContainer.className = `max-w-xs w-64 bg-white dark:bg-gray-800 rounded-2xl shadow-lg overflow-hidden transition-all duration-300 fixed ${this.config.position === 'bottom-right' ? 'bottom-4 right-4' : 'bottom-4 left-4'} z-50`;
        
        // 创建APlayer容器
        this.aplayerContainer = document.createElement('div');
        this.aplayerContainer.id = `music-player-${Date.now()}`;
        this.aplayerContainer.className = 'w-full';
        this.playerContainer.appendChild(this.aplayerContainer);
        
        // 添加到页面
        this.config.container.appendChild(this.playerContainer);
    }

    // 创建自定义样式(移除歌词相关样式)
    createStyles() {
        const style = document.createElement('style');
        style.textContent = `
            .progress-thumb {
                appearance: none;
                width: 0.75rem;
                height: 0.75rem;
                border-radius: 9999px;
                background-color: ${this.config.themeColor};
                cursor: pointer;
                box-shadow: 0 4px 6px -1px rgb(0 0 0 / 0.1), 0 2px 4px -2px rgb(0 0 0 / 0.1);
            }
            .progress-track {
                appearance: none;
                height: 0.25rem;
                border-radius: 9999px;
                background-color: #e5e7eb;
            }
            .dark .progress-track {
                background-color: #e5e7eb;
            }
            .progress-track::-webkit-slider-thumb {
                ${this.config.themeColor ? `background-color: ${this.config.themeColor};` : ''}
                appearance: none;
                width: 0.75rem;
                height: 0.75rem;
                border-radius: 9999px;
                cursor: pointer;
                box-shadow: 0 4px 6px -1px rgb(0 0 0 / 0.1), 0 2px 4px -2px rgb(0 0 0 / 0.1);
            }
            .progress-track::-moz-range-thumb {
                ${this.config.themeColor ? `background-color: ${this.config.themeColor};` : ''}
                appearance: none;
                width: 0.75rem;
                height: 0.75rem;
                border-radius: 9999px;
                cursor: pointer;
                box-shadow: 0 4px 6px -1px rgb(0 0 0 / 0.1), 0 2px 4px -2px rgb(0 0 0 / 0.1);
            }
            .cover-loading {
                background: linear-gradient(90deg, #f0f0f0 25%, #e0e0e0 50%, #f0f0f0 75%);
                background-size: 200% 100%;
                animation: loading 1.5s infinite;
            }
            @keyframes loading {
                0% { background-position: 200% 0; }
                100% { background-position: -200% 0; }
            }
        `;
        document.head.appendChild(style);
    }

    // 初始化APlayer(移除歌词相关处理)
    async initAPlayer() {
        // 等待APlayer加载完成
        if (typeof APlayer === 'undefined') {
            await new Promise(resolve => {
                const checkAPlayer = setInterval(() => {
                    if (typeof APlayer !== 'undefined') {
                        clearInterval(checkAPlayer);
                        resolve();
                    }
                }, 100);
            });
        }

        // 请求API数据
        try {
            const response = await fetch(this.config.musicApi);
            let dataText = await response.text();
            
            // 过滤PHP警告,只保留JSON部分
            const jsonStartIndex = dataText.indexOf('[');
            const jsonEndIndex = dataText.lastIndexOf(']') + 1;
            const jsonData = JSON.parse(dataText.slice(jsonStartIndex, jsonEndIndex));

            // 格式化歌曲数据(移除歌词字段)
            const musicList = jsonData.map(song => ({
                name: song.name,
                artist: song.artist,
                url: song.url,
                cover: song.pic
            }));

            // 创建APlayer实例
            this.aplayerInstance = new APlayer({
                container: this.aplayerContainer,
                autoplay: false,
                theme: this.config.themeColor,
                loop: 'all',
                order: 'list',
                preload: 'auto',
                volume: 0.6,
                listFolded: true,
                listMaxHeight: 180,
                music: musicList
            });

            // 处理浏览器自动播放限制
            document.addEventListener('click', () => {
                if (this.aplayerInstance && !this.isPlaying) {
                    this.aplayerInstance.play().catch(err => {
                        console.log('播放需手动触发,点击播放器播放按钮即可');
                    });
                }
            }, { once: true });

            // 监听播放/暂停事件,更新状态
            this.aplayerInstance.on('play', () => {
                this.isPlaying = true;
            });
            this.aplayerInstance.on('pause', () => {
                this.isPlaying = false;
            });

        } catch (apiError) {
            console.error('API请求失败,使用本地示例数据:', apiError);
            
            // 备用方案:使用本地示例数据
            const fallbackMusic = [{
                name: '示例音乐',
                artist: '未知艺术家',
                url: 'https://demo.music.com/example.mp3',
                cover: 'https://via.placeholder.com/150'
            }];
            
            this.aplayerInstance = new APlayer({
                container: this.aplayerContainer,
                autoplay: false,
                theme: this.config.themeColor,
                loop: 'all',
                order: 'list',
                preload: 'none',
                volume: 0.6,
                listFolded: true,
                listMaxHeight: 180,
                music: fallbackMusic
            });
        }
    }

    // 销毁播放器(移除歌词容器销毁)
    destroy() {
        if (this.aplayerInstance) {
            this.aplayerInstance.destroy();
        }
        if (this.playerContainer && this.playerContainer.parentNode) {
            this.playerContainer.parentNode.removeChild(this.playerContainer);
        }
        this.isPlaying = false;
    }
}

// 确保DOM加载完成后再初始化
function initPlayerWhenReady() {
    if (document.readyState === 'complete' || document.readyState === 'interactive') {
        window.musicPlayer = new MusicPlayer({
            position: 'bottom-left',
            themeColor: '#6366f1'
        });
    } else {
        document.addEventListener('DOMContentLoaded', () => {
            window.musicPlayer = new MusicPlayer({
                position: 'bottom-left',
                themeColor: '#6366f1'
            });
        });
    }
}

// 立即调用初始化函数
initPlayerWhenReady();

// 导出模块(如果在模块化环境中使用)
if (typeof module !== 'undefined' && module.exports) {
    module.exports = MusicPlayer;
}
</script>

<!-- 引入APlayer资源 -->
<link rel="stylesheet" href="https://cdn.bootcdn.net/ajax/libs/aplayer/1.10.1/APlayer.min.css">
<script src="https://cdn.bootcdn.net/ajax/libs/aplayer/1.10.1/APlayer.min.js"></script>
此作者没有提供个人介绍。
最后更新于 2026-02-21