搜索结果

×

搜索结果将在这里显示。

🤍 酷咔智能媒体播放器

使用方法总结
输入链接:粘贴音频或视频文件链接
加载媒体:点击"加载媒体"按钮
控制播放:使用播放控制按钮
调节设置:调整音量和播放速度
全屏播放:视频模式下可全屏观看

音频播放
支持MP3、WAV、OGG、M4A等格式
音量控制

视频播放
支持MP4、WebM、OGG等格式
视频画面正确显示
全屏播放功能
播放进度控制

代码分享

<!DOCTYPE html>
<html lang="zh-CN">
<head>
    <meta charset="UTF-8">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <title>酷咔智能媒体播放器</title>
    <style>
        * {
            margin: 0;
            padding: 0;
            box-sizing: border-box;
        }

        body {
            font-family: -apple-system, BlinkMacSystemFont, 'Segoe UI', Roboto, sans-serif;
            background: linear-gradient(135deg, #1a237e 0%, #4a148c 100%);
            min-height: 100vh;
            display: flex;
            justify-content: center;
            align-items: center;
            padding: 20px;
        }

        .player-container {
            width: 100%;
            max-width: 800px;
            background: white;
            border-radius: 20px;
            box-shadow: 0 20px 60px rgba(0,0,0,0.3);
            overflow: hidden;
        }

        .player-header {
            background: linear-gradient(135deg, #667eea 0%, #764ba2 100%);
            color: white;
            padding: 30px;
            text-align: center;
        }

        .player-title {
            font-size: 2rem;
            font-weight: 600;
            margin-bottom: 10px;
        }

        .player-subtitle {
            font-size: 1.1rem;
            opacity: 0.9;
        }

        .player-body {
            padding: 30px;
        }

        .input-section {
            margin-bottom: 30px;
        }

        .input-label {
            display: block;
            margin-bottom: 10px;
            font-weight: 500;
            color: #333;
        }

        .url-input {
            width: 100%;
            padding: 12px 15px;
            border: 2px solid #e0e0e0;
            border-radius: 8px;
            font-size: 1rem;
            margin-bottom: 15px;
        }

        .url-input:focus {
            outline: none;
            border-color: #667eea;
        }

        .action-buttons {
            display: flex;
            gap: 10px;
            margin-bottom: 20px;
        }

        .btn {
            padding: 12px 20px;
            border: none;
            border-radius: 8px;
            font-size: 1rem;
            font-weight: 600;
            cursor: pointer;
            flex: 1;
        }

        .load-btn {
            background: #4CAF50;
            color: white;
        }

        .load-btn:hover {
            background: #388e3c;
        }

        .load-btn:disabled {
            opacity: 0.6;
            cursor: not-allowed;
        }

        .fullscreen-btn {
            background: #2196F3;
            color: white;
        }

        .fullscreen-btn:hover:not(:disabled) {
            background: #0b7dda;
        }

        .fullscreen-btn:disabled {
            opacity: 0.6;
            cursor: not-allowed;
        }

        /* 媒体容器 - 关键修复 */
        .media-container {
            width: 100%;
            background: #000;
            border-radius: 10px;
            overflow: hidden;
            margin-bottom: 20px;
            position: relative;
            display: none; /* 默认隐藏,加载后显示 */
        }

        .media-container.active {
            display: block;
        }

        /* 视频元素样式 - 确保正确显示 */
        #videoElement {
            width: 100%;
            height: auto;
            max-height: 400px;
            display: block; /* 确保block显示 */
            background: black; /* 黑色背景避免空白 */
        }

        /* 音频容器样式 */
        .audio-container {
            width: 100%;
            height: 100px;
            background: linear-gradient(135deg, #667eea 0%, #764ba2 100%);
            border-radius: 10px;
            display: flex;
            align-items: center;
            justify-content: center;
            color: white;
            font-size: 1.2rem;
        }

        .audio-container.hidden {
            display: none;
        }

        .video-placeholder {
            width: 100%;
            height: 200px;
            display: flex;
            align-items: center;
            justify-content: center;
            background: #111;
            color: white;
            font-size: 1.2rem;
        }

        .video-placeholder.hidden {
            display: none;
        }

        .controls {
            display: flex;
            gap: 10px;
            margin: 20px 0;
        }

        .control-btn {
            padding: 12px;
            border: none;
            border-radius: 8px;
            background: #f5f5f5;
            color: #333;
            cursor: pointer;
            flex: 1;
            font-size: 1.1rem;
        }

        .control-btn:hover:not(:disabled) {
            background: #e0e0e0;
        }

        .control-btn:disabled {
            opacity: 0.5;
            cursor: not-allowed;
        }

        .progress-container {
            margin: 20px 0;
        }

        .progress-bar {
            height: 6px;
            background: #e0e0e0;
            border-radius: 3px;
            cursor: pointer;
            position: relative;
        }

        .progress-fill {
            height: 100%;
            background: #667eea;
            width: 0%;
            border-radius: 3px;
            position: absolute;
            top: 0;
            left: 0;
        }

        .time-display {
            display: flex;
            justify-content: space-between;
            color: #666;
            font-size: 0.9rem;
            margin-top: 5px;
        }

        .volume-control {
            display: flex;
            align-items: center;
            gap: 10px;
            margin: 15px 0;
        }

        .volume-slider {
            flex: 1;
            height: 6px;
            -webkit-appearance: none;
            background: #e0e0e0;
            border-radius: 3px;
        }

        .volume-slider::-webkit-slider-thumb {
            -webkit-appearance: none;
            width: 20px;
            height: 20px;
            border-radius: 50%;
            background: #667eea;
            cursor: pointer;
        }

        .status {
            padding: 15px;
            background: #f8f9ff;
            border-radius: 8px;
            text-align: center;
            margin-top: 20px;
            min-height: 50px;
            display: flex;
            align-items: center;
            justify-content: center;
        }

        .status.success {
            color: #4CAF50;
        }

        .status.error {
            color: #f44336;
        }

        .status.info {
            color: #666;
        }

        .status.warning {
            color: #FF9800;
        }

        .debug-info {
            margin-top: 20px;
            padding: 10px;
            background: #f5f5f5;
            border-radius: 5px;
            font-family: monospace;
            font-size: 0.9rem;
            color: #666;
        }

        .example-links {
            margin: 10px 0;
            font-size: 0.9rem;
            color: #666;
        }

        .example-link {
            color: #667eea;
            text-decoration: none;
            margin: 0 5px;
            cursor: pointer;
        }

        .example-link:hover {
            text-decoration: underline;
        }

        .media-type-badge {
            display: inline-block;
            padding: 4px 12px;
            background: #4CAF50;
            color: white;
            border-radius: 20px;
            font-size: 0.9rem;
            margin-left: 10px;
        }

        .media-type-badge.video {
            background: #2196F3;
        }

        .media-type-badge.audio {
            background: #FF9800;
        }
    </style>
</head>
<body>
    <div class="player-container">
        <div class="player-header">
            <h1 class="player-title">酷咔智能媒体播放器</h1>
            <p class="player-subtitle">https://5blog.cn/tx/media-player.html</p>
        </div>

        <div class="player-body">
            <div class="input-section">
                <label class="input-label">媒体链接:</label>
                <input type="text" class="url-input" id="urlInput" 
                    placeholder="粘贴MP3、MP4、WebM等链接"
                    value="https://5blog.cn/content/uploadfile/202602/31641771082987.mp4">

                <div class="action-buttons">
                    <button class="btn load-btn" id="loadBtn">加载媒体</button>
                    <button class="btn fullscreen-btn" id="fullscreenBtn" disabled>全屏</button>
                </div>

                <div class="example-links">
                    测试链接: 
                    <a class="example-link" onclick="setExample('video')">视频测试</a>
                    <a class="example-link" onclick="setExample('audio')">音频测试</a>
                </div>
            </div>

            <!-- 媒体显示容器 -->
            <div class="media-container" id="mediaContainer">
                <!-- 视频元素 - 直接内嵌 -->
                <video id="videoElement" controls style="display: none;"></video>

                <!-- 音频占位符 -->
                <div id="audioContainer" class="audio-container hidden">
                    🎵 音频播放中
                </div>

                <!-- 视频占位符(视频未显示时显示) -->
                <div id="videoPlaceholder" class="video-placeholder">
                    视频加载中...
                </div>
            </div>

            <!-- 媒体类型指示器 -->
            <div style="text-align: center; margin: 10px 0;">
                当前模式: <span id="mediaTypeIndicator" class="media-type-badge">未加载</span>
            </div>

            <div class="progress-container">
                <div class="progress-bar" id="progressBar">
                    <div class="progress-fill" id="progressFill"></div>
                </div>
                <div class="time-display">
                    <span id="currentTime">0:00</span>
                    <span id="duration">0:00</span>
                </div>
            </div>

            <div class="controls">
                <button class="control-btn" id="playBtn" disabled>▶ 播放</button>
                <button class="control-btn" id="pauseBtn" disabled>⏸ 暂停</button>
                <button class="control-btn" id="stopBtn" disabled>⏹ 停止</button>
                <button class="control-btn" id="rewindBtn" disabled>⏪ 10秒</button>
                <button class="control-btn" id="forwardBtn" disabled>⏩ 10秒</button>
            </div>

            <div class="volume-control">
                <span>🔊</span>
                <input type="range" class="volume-slider" id="volumeSlider" min="0" max="100" value="70">
                <span id="volumeValue">70%</span>
            </div>

            <div class="status info" id="statusText">等待加载媒体...</div>

            <div class="debug-info" id="debugInfo" style="display: none;">
                调试信息: <span id="debugText">暂无</span>
            </div>
        </div>
    </div>

    <script>
        class FixedMediaPlayer {
            constructor() {
                this.mediaElement = null;
                this.isVideo = false;
                this.isLoaded = false;
                this.isPlaying = false;

                // DOM元素
                this.elements = {
                    // 输入相关
                    urlInput: document.getElementById('urlInput'),
                    loadBtn: document.getElementById('loadBtn'),
                    fullscreenBtn: document.getElementById('fullscreenBtn'),

                    // 媒体容器相关
                    mediaContainer: document.getElementById('mediaContainer'),
                    videoElement: document.getElementById('videoElement'),
                    audioContainer: document.getElementById('audioContainer'),
                    videoPlaceholder: document.getElementById('videoPlaceholder'),

                    // 控制相关
                    playBtn: document.getElementById('playBtn'),
                    pauseBtn: document.getElementById('pauseBtn'),
                    stopBtn: document.getElementById('stopBtn'),
                    rewindBtn: document.getElementById('rewindBtn'),
                    forwardBtn: document.getElementById('forwardBtn'),

                    // 进度和音量相关
                    progressBar: document.getElementById('progressBar'),
                    progressFill: document.getElementById('progressFill'),
                    currentTime: document.getElementById('currentTime'),
                    duration: document.getElementById('duration'),
                    volumeSlider: document.getElementById('volumeSlider'),
                    volumeValue: document.getElementById('volumeValue'),

                    // 状态和信息相关
                    statusText: document.getElementById('statusText'),
                    mediaTypeIndicator: document.getElementById('mediaTypeIndicator'),
                    debugInfo: document.getElementById('debugInfo'),
                    debugText: document.getElementById('debugText')
                };

                this.init();
            }

            init() {
                console.log('播放器初始化...');
                this.logDebug('播放器初始化开始');

                // 绑定事件
                this.elements.loadBtn.addEventListener('click', () => this.loadMedia());
                this.elements.urlInput.addEventListener('keypress', (e) => {
                    if (e.key === 'Enter') this.loadMedia();
                });

                this.elements.playBtn.addEventListener('click', () => this.play());
                this.elements.pauseBtn.addEventListener('click', () => this.pause());
                this.elements.stopBtn.addEventListener('click', () => this.stop());
                this.elements.rewindBtn.addEventListener('click', () => this.seek(-10));
                this.elements.forwardBtn.addEventListener('click', () => this.seek(10));
                this.elements.fullscreenBtn.addEventListener('click', () => this.toggleFullscreen());
                this.elements.progressBar.addEventListener('click', (e) => this.seekToPosition(e));
                this.elements.volumeSlider.addEventListener('input', (e) => this.setVolume(e.target.value));

                this.logDebug('事件监听器设置完成');

                // 设置初始音量
                this.setVolume(80);
            }

            logDebug(message) {
                console.log('[Debug]', message);
                this.elements.debugText.textContent = message;
                this.elements.debugInfo.style.display = 'block';
            }

            setStatus(message, type = 'info') {
                this.elements.statusText.textContent = message;
                this.elements.statusText.className = 'status ' + type;
                this.logDebug(`状态: ${message}`);
            }

            detectMediaType(url) {
                const extension = url.split('.').pop().toLowerCase().split('?')[0];
                const videoExtensions = ['mp4', 'webm', 'ogg', 'mov', 'avi', 'wmv', 'flv', 'mkv'];
                const audioExtensions = ['mp3', 'wav', 'ogg', 'm4a', 'aac', 'flac'];

                if (videoExtensions.includes(extension)) {
                    return 'video';
                } else if (audioExtensions.includes(extension)) {
                    return 'audio';
                } else {
                    // 从URL推测
                    if (url.includes('/video/') || url.includes('.mp4')) {
                        return 'video';
                    }
                    return 'audio';
                }
            }

            loadMedia() {
                const url = this.elements.urlInput.value.trim();

                if (!url) {
                    this.setStatus('请输入媒体链接', 'error');
                    return;
                }

                this.logDebug(`开始加载: ${url}`);
                this.setStatus('正在检测媒体类型...', 'info');

                // 重置播放器
                this.resetPlayer();

                // 检测媒体类型
                this.isVideo = this.detectMediaType(url) === 'video';
                this.logDebug(`检测为: ${this.isVideo ? '视频' : '音频'}`);

                // 设置媒体元素
                this.setupMediaElement();

                // 更新界面指示器
                this.updateMediaTypeIndicator();

                // 显示媒体容器
                this.elements.mediaContainer.classList.add('active');

                // 设置媒体源
                this.mediaElement.src = url;
                this.mediaElement.load();

                this.elements.loadBtn.disabled = true;
                this.setStatus('正在加载媒体...', 'info');
            }

            setupMediaElement() {
                // 使用已有的video元素
                this.mediaElement = this.elements.videoElement;

                // 清理之前的事件监听器
                const newVideo = this.mediaElement.cloneNode();
                this.mediaElement.parentNode.replaceChild(newVideo, this.mediaElement);
                this.mediaElement = newVideo;
                this.mediaElement.id = 'videoElement';

                // 设置样式
                this.mediaElement.style.width = '100%';
                this.mediaElement.style.height = 'auto';
                this.mediaElement.style.display = 'block'; // 关键修复:确保显示
                this.mediaElement.style.background = '#000';

                // 如果是音频,隐藏视频控件
                if (!this.isVideo) {
                    this.mediaElement.style.display = 'none';
                    this.elements.audioContainer.classList.remove('hidden');
                    this.elements.videoPlaceholder.classList.add('hidden');
                } else {
                    this.mediaElement.style.display = 'block'; // 关键修复
                    this.elements.audioContainer.classList.add('hidden');
                    this.elements.videoPlaceholder.classList.add('hidden'); // 隐藏占位符
                }

                // 设置事件监听
                this.setupMediaEventListeners();

                this.logDebug(`媒体元素设置完成 (${this.isVideo ? '视频' : '音频'})`);
            }

            setupMediaEventListeners() {
                this.mediaElement.addEventListener('loadedmetadata', () => this.onLoadedMetadata());
                this.mediaElement.addEventListener('loadeddata', () => this.onLoadedData());
                this.mediaElement.addEventListener('canplay', () => this.onCanPlay());
                this.mediaElement.addEventListener('error', (e) => this.onError(e));
                this.mediaElement.addEventListener('timeupdate', () => this.updateProgress());
                this.mediaElement.addEventListener('ended', () => this.onEnded());
                this.mediaElement.addEventListener('play', () => this.onPlay());
                this.mediaElement.addEventListener('pause', () => this.onPause());

                this.logDebug('媒体事件监听器已设置');
            }

            onLoadedMetadata() {
                this.logDebug(`元数据加载完成,时长: ${this.formatTime(this.mediaElement.duration)}`);
                this.updateDuration();

                if (this.isVideo) {
                    this.logDebug(`视频尺寸: ${this.mediaElement.videoWidth}x${this.mediaElement.videoHeight}`);
                }
            }

            onLoadedData() {
                this.isLoaded = true;
                this.elements.playBtn.disabled = false;
                this.elements.pauseBtn.disabled = false;
                this.elements.stopBtn.disabled = false;
                this.elements.rewindBtn.disabled = false;
                this.elements.forwardBtn.disabled = false;
                this.elements.fullscreenBtn.disabled = !this.isVideo;

                this.setStatus('媒体加载完成,可以播放', 'success');
                this.logDebug('媒体数据加载完成');
            }

            onCanPlay() {
                this.logDebug('媒体可以开始播放');

                // 如果是视频,确保视频元素可见
                if (this.isVideo) {
                    this.mediaElement.style.display = 'block';
                    this.elements.videoPlaceholder.classList.add('hidden');
                }
            }

            onError(event) {
                console.error('媒体错误:', this.mediaElement.error);

                let errorMessage = '未知错误';
                if (this.mediaElement.error) {
                    switch(this.mediaElement.error.code) {
                        case this.mediaElement.error.MEDIA_ERR_ABORTED:
                            errorMessage = '加载被中止';
                            break;
                        case this.mediaElement.error.MEDIA_ERR_NETWORK:
                            errorMessage = '网络错误';
                            break;
                        case this.mediaElement.error.MEDIA_ERR_DECODE:
                            errorMessage = '解码错误';
                            break;
                        case this.mediaElement.error.MEDIA_ERR_SRC_NOT_SUPPORTED:
                            errorMessage = '格式不支持';
                            break;
                        default:
                            errorMessage = `错误代码: ${this.mediaElement.error.code}`;
                    }
                }

                this.setStatus(`加载失败: ${errorMessage}`, 'error');
                this.logDebug(`媒体错误: ${errorMessage}`);

                // 如果是视频,显示占位符
                if (this.isVideo) {
                    this.elements.videoPlaceholder.classList.remove('hidden');
                    this.elements.videoPlaceholder.textContent = '加载失败: ' + errorMessage;
                }
            }

            onEnded() {
                this.isPlaying = false;
                this.setStatus('播放完成', 'success');
                this.logDebug('播放结束');
            }

            onPlay() {
                this.isPlaying = true;
                this.logDebug('播放开始');
            }

            onPause() {
                this.isPlaying = false;
                this.logDebug('播放暂停');
            }

            play() {
                if (!this.isLoaded) {
                    this.setStatus('媒体未加载', 'error');
                    return;
                }

                this.mediaElement.play().then(() => {
                    this.logDebug('播放成功');
                    this.setStatus('播放中...', 'success');
                }).catch(error => {
                    console.error('播放失败:', error);
                    this.setStatus(`播放失败: ${error.message}`, 'error');
                    this.logDebug(`播放失败: ${error.message}`);
                });
            }

            pause() {
                this.mediaElement.pause();
                this.setStatus('已暂停', 'info');
            }

            stop() {
                this.mediaElement.pause();
                this.mediaElement.currentTime = 0;
                this.updateProgress();
                this.setStatus('已停止', 'info');
            }

            seek(seconds) {
                if (!this.isLoaded) return;

                const newTime = this.mediaElement.currentTime + seconds;
                this.mediaElement.currentTime = Math.max(0, Math.min(newTime, this.mediaElement.duration));
                this.logDebug(`跳转 ${seconds} 秒`);
            }

            seekToPosition(event) {
                if (!this.isLoaded) return;

                const rect = this.elements.progressBar.getBoundingClientRect();
                const clickX = event.clientX - rect.left;
                const width = rect.width;
                const percentage = clickX / width;

                this.mediaElement.currentTime = this.mediaElement.duration * percentage;
                this.logDebug(`点击跳转到 ${Math.round(percentage * 100)}%`);
            }

            setVolume(value) {
                const volume = value / 100;
                this.mediaElement.volume = volume;
                this.elements.volumeValue.textContent = value + '%';
                this.logDebug(`音量设置为 ${value}%`);
            }

            toggleFullscreen() {
                if (!this.isVideo || !this.isLoaded) return;

                if (!document.fullscreenElement) {
                    this.mediaElement.requestFullscreen().catch(err => {
                        console.error('全屏失败:', err);
                        this.logDebug('全屏失败');
                    });
                } else {
                    document.exitFullscreen();
                }
            }

            updateProgress() {
                if (!this.isLoaded || isNaN(this.mediaElement.duration)) return;

                const progress = (this.mediaElement.currentTime / this.mediaElement.duration) * 100;
                this.elements.progressFill.style.width = progress + '%';
                this.elements.currentTime.textContent = this.formatTime(this.mediaElement.currentTime);
            }

            updateDuration() {
                if (!this.isLoaded || isNaN(this.mediaElement.duration)) return;
                this.elements.duration.textContent = this.formatTime(this.mediaElement.duration);
            }

            updateMediaTypeIndicator() {
                if (this.isVideo) {
                    this.elements.mediaTypeIndicator.textContent = '视频模式';
                    this.elements.mediaTypeIndicator.className = 'media-type-badge video';
                } else {
                    this.elements.mediaTypeIndicator.textContent = '音频模式';
                    this.elements.mediaTypeIndicator.className = 'media-type-badge audio';
                }
            }

            resetPlayer() {
                this.isLoaded = false;
                this.isPlaying = false;

                if (this.mediaElement) {
                    this.mediaElement.pause();
                    this.mediaElement.src = '';
                }

                this.elements.progressFill.style.width = '0%';
                this.elements.currentTime.textContent = '0:00';
                this.elements.duration.textContent = '0:00';
                this.elements.mediaContainer.classList.remove('active');

                this.elements.loadBtn.disabled = false;
                this.elements.playBtn.disabled = true;
                this.elements.pauseBtn.disabled = true;
                this.elements.stopBtn.disabled = true;
                this.elements.rewindBtn.disabled = true;
                this.elements.forwardBtn.disabled = true;
                this.elements.fullscreenBtn.disabled = true;

                this.elements.audioContainer.classList.add('hidden');
                this.elements.videoPlaceholder.classList.remove('hidden');
                this.elements.videoPlaceholder.textContent = '视频加载中...';

                this.elements.mediaTypeIndicator.textContent = '未加载';
                this.elements.mediaTypeIndicator.className = 'media-type-badge';

                this.logDebug('播放器已重置');
            }

            formatTime(seconds) {
                if (isNaN(seconds)) return '0:00';
                const mins = Math.floor(seconds / 60);
                const secs = Math.floor(seconds % 60);
                return mins + ':' + secs.toString().padStart(2, '0');
            }
        }

        // 辅助函数
        function setExample(type) {
            const examples = {
                video: 'https://5blog.cn/content/uploadfile/202602/31641771082987.mp4',
                audio: 'https://5blog.cn/content/uploadfile/202602/e7311769955470.mp3'
            };

            document.getElementById('urlInput').value = examples[type] || '';

            // 自动加载
            setTimeout(() => {
                if (player) {
                    player.loadMedia();
                }
            }, 100);
        }

        // 初始化播放器
        const player = new FixedMediaPlayer();

        // 页面加载完成后设置视频示例
        window.addEventListener('DOMContentLoaded', () => {
            console.log('页面加载完成,准备自动加载视频示例');
            setTimeout(() => {
                setExample('video');
            }, 1000);
        });
    </script>
</body>
</html>

演示效果

点击查看演示效果

阅读:29
发布时间:
请先 登录 再评论