【网页播放器】播放自己喜欢的音乐

news2024/11/15 7:32:36

在这里插入图片描述

// 错误处理
window.onerror = function(message, source, lineno, colno, error) {
    console.error("An error occurred:", message, "at", source, ":", lineno);
    return true;
};

// 检查 particlesJS 是否已定义
if (typeof particlesJS !== 'undefined') {
    // 初始化粒子效果
    document.addEventListener('DOMContentLoaded', function() {
        particlesJS('particles-js', {
            particles: {
                number: { value: 80, density: { enable: true, value_area: 800 } },
                color: { value: '#ffffff' },
                shape: { type: 'circle', stroke: { width: 0, color: '#000000' } },
                opacity: { value: 0.5, random: true, anim: { enable: true, speed: 1, opacity_min: 0.1, sync: false } },
                size: { value: 3, random: true, anim: { enable: true, speed: 4, size_min: 0.3, sync: false } },
                line_linked: { enable: true, distance: 150, color: '#ffffff', opacity: 0.4, width: 1 },
                move: { enable: true, speed: 1, direction: 'none', random: true, straight: false, out_mode: 'out', bounce: false }
            },
            interactivity: {
                detect_on: 'canvas',
                events: { onhover: { enable: true, mode: 'repulse' }, onclick: { enable: true, mode: 'push' }, resize: true },
                modes: { repulse: { distance: 100, duration: 0.4 }, push: { particles_nb: 4 } }
            },
            retina_detect: true
        });
        console.log('Particles initialized');
    });
} else {
    console.error("particlesJS is not defined. The library may not have loaded correctly.");
}

// 初始化音频波形
let wavesurfer;

function initWaveSurfer() {
    wavesurfer = WaveSurfer.create({
        container: '#visualizer',
        waveColor: 'rgba(255, 255, 255, 0.5)',
        progressColor: 'rgba(29, 185, 84, 0.7)',
        cursorColor: 'transparent',
        barWidth: 2,
        barRadius: 3,
        cursorWidth: 0,
        height: 40,
        barGap: 2,
        responsive: true
    });

    // 绑定事件监听器
    wavesurfer.on('ready', onWavesurferReady);
    wavesurfer.on('audioprocess', updateProgress);
    wavesurfer.on('audioprocess', updateLyrics);

    console.log('WaveSurfer initialized');

    // 初始化后立即绑定播放/暂停按钮事件
    bindPlayPauseButton();
}

function bindPlayPauseButton() {
    playPauseButton.addEventListener('click', togglePlayPause);
}

function togglePlayPause() {
    if (wavesurfer) {
        wavesurfer.playPause();
        updatePlayPauseIcon();
    } else {
        console.error('WaveSurfer is not initialized');
    }
}

function updatePlayPauseIcon() {
    const icon = playPauseButton.querySelector('i');
    if (wavesurfer && wavesurfer.isPlaying()) {
        icon.classList.remove('fa-play');
        icon.classList.add('fa-pause');
    } else {
        icon.classList.remove('fa-pause');
        icon.classList.add('fa-play');
    }
}

// 在用户交互后初始化 WaveSurfer
document.addEventListener('click', function initAudioContext() {
    if (!wavesurfer) {
        initWaveSurfer();
    }
    document.removeEventListener('click', initAudioContext);
}, { once: true });

// 获取DOM元素
const playPauseButton = document.getElementById('play-pause');
const prevButton = document.getElementById('prev');
const nextButton = document.getElementById('next');
const shuffleButton = document.getElementById('shuffle');
const repeatButton = document.getElementById('repeat');
const fileInput = document.getElementById('file-input');
const songTitle = document.getElementById('song-title');
const artistName = document.getElementById('artist-name');
const albumCover = document.getElementById('album-cover');
const lyricsContainer = document.getElementById('lyrics');
const progressContainer = document.getElementById('progress-container');
const progressBar = document.getElementById('progress-bar');
const currentTime = document.getElementById('current-time');
const totalTime = document.getElementById('total-time');

// 初始化控制按钮
function initializeControls() {
    playPauseButton.addEventListener('click', togglePlayPause);
    prevButton.addEventListener('click', playPreviousTrack);
    nextButton.addEventListener('click', playNextTrack);
    shuffleButton.addEventListener('click', toggleShuffle);
    repeatButton.addEventListener('click', toggleRepeat);
    progressContainer.addEventListener('click', seekToPosition);
}

// 文件上传功能
fileInput.addEventListener('change', (e) => {
    const file = e.target.files[0];
    if (file) {
        if (!wavesurfer) {
            initWaveSurfer();
        }
        const objectURL = URL.createObjectURL(file);
        wavesurfer.load(objectURL);
        updateSongInfo(file);
        console.log('File loaded:', file.name);
    }
});

function updateSongInfo(file) {
    songTitle.textContent = file.name.replace(/\.[^/.]+$/, "");
    artistName.textContent = "未知艺术家"; // 这里可以添加获取元数据的逻辑
    // 这里可以添加获取专辑封面的逻辑
    console.log('Song info updated'); // 添加日志
}

// 进度条更新
function updateProgress() {
    if (wavesurfer) {
        const progress = wavesurfer.getCurrentTime() / wavesurfer.getDuration();
        progressBar.style.width = `${progress * 100}%`;
        currentTime.textContent = formatTime(wavesurfer.getCurrentTime());
    }
}

progressContainer.addEventListener('click', function(e) {
    if (wavesurfer) {
        const clickPosition = (e.clientX - this.getBoundingClientRect().left) / this.offsetWidth;
        wavesurfer.seekTo(clickPosition);
    }
});

// 时间格式化
function formatTime(time) {
    const minutes = Math.floor(time / 60);
    const seconds = Math.floor(time % 60);
    return `${minutes}:${seconds.toString().padStart(2, '0')}`;
}

// 音频加载完成后的操作
function onWavesurferReady() {
    playPauseButton.disabled = false;
    totalTime.textContent = formatTime(wavesurfer.getDuration());
    updatePlayPauseIcon();
    console.log('Wavesurfer ready');
    wavesurfer.play();
}

// 模拟歌词显示
function updateLyrics(time) {
    if (!showingLyrics) return;
    
    // 如果有解析的歌词,使用它们
    if (window.parsedLyrics && window.parsedLyrics.length > 0) {
        const currentLyric = window.parsedLyrics.find(lyric => lyric.time <= time);
        if (currentLyric) {
            lyricsContainer.textContent = currentLyric.text;
        }
    } else {
        // 否则显示默认的播放时间
        lyricsContainer.textContent = `正在播放: ${Math.floor(time)}`;
    }
    console.log('Lyrics updated:', lyricsContainer.textContent); // 添加日志
}

// 添加其他按钮的功能(这里只是占位,实际功能需要根据您的需求来实现)
prevButton.addEventListener('click', () => console.log('上一首'));
nextButton.addEventListener('click', () => console.log('下一首'));
shuffleButton.addEventListener('click', () => console.log('随机播放'));
repeatButton.addEventListener('click', () => console.log('重复播放'));

// 确保在 DOM 加载完成后初始化 WaveSurfer
document.addEventListener('DOMContentLoaded', () => {
    initializeControls();
    initWaveSurfer();
});

const coverLyricsContainer = document.getElementById('cover-lyrics-container');
const lyricsInput = document.getElementById('lyrics-input');
let showingLyrics = false;

coverLyricsContainer.addEventListener('click', toggleLyrics);

function toggleLyrics() {
    showingLyrics = !showingLyrics;
    albumCover.style.display = showingLyrics ? 'none' : 'block';
    lyricsContainer.style.display = showingLyrics ? 'flex' : 'none';
    console.log('Lyrics toggled:', showingLyrics); // 添加日志
}

lyricsInput.addEventListener('change', (e) => {
    const file = e.target.files[0];
    if (file) {
        const reader = new FileReader();
        reader.onload = function(e) {
            const cueContent = e.target.result;
            const lyrics = parseCueFile(cueContent);
            updateLyricsDisplay(lyrics);
        };
        reader.readAsText(file);
    }
});

function parseCueFile(cueContent) {
    const lines = cueContent.split('\n');
    const lyrics = [];
    let currentTime = 0;

    for (let line of lines) {
        if (line.startsWith('  TRACK')) {
            currentTime = 0;
        } else if (line.startsWith('    INDEX 01')) {
            const timeStr = line.split('INDEX 01')[1].trim();
            const [min, sec, frame] = timeStr.split(':').map(Number);
            currentTime = min * 60 + sec + frame / 75;
        } else if (line.startsWith('    TITLE')) {
            const lyric = line.split('TITLE')[1].trim().replace(/"/g, '');
            lyrics.push({ time: currentTime, text: lyric });
        }
    }

    return lyrics;
}

function updateLyricsDisplay(lyrics) {
    lyricsContainer.innerHTML = '';
    for (let lyric of lyrics) {
        const p = document.createElement('p');
        p.textContent = lyric.text;
        lyricsContainer.appendChild(p);
    }
}

// 拖动功能
const fileInputContainer = document.getElementById('file-input-container');
let isDragging = false;
let startX, startY, initialLeft, initialTop;

fileInputContainer.addEventListener('mousedown', startDragging);
document.addEventListener('mousemove', drag);
document.addEventListener('mouseup', stopDragging);

function startDragging(e) {
    isDragging = true;
    startX = e.clientX;
    startY = e.clientY;
    initialLeft = fileInputContainer.offsetLeft;
    initialTop = fileInputContainer.offsetTop;
}

function drag(e) {
    if (!isDragging) return;
    e.preventDefault();
    const dx = e.clientX - startX;
    const dy = e.clientY - startY;
    fileInputContainer.style.left = `${initialLeft + dx}px`;
    fileInputContainer.style.top = `${initialTop + dy}px`;
}

function stopDragging() {
    isDragging = false;
}
body {
    margin: 0;
    display: flex;
    justify-content: center;
    align-items: center;
    height: 100vh;
    background: linear-gradient(45deg, #1a1a1a, #2a2a2a);
    font-family: 'Poppins', sans-serif;
    color: white;
}

#player {
    position: relative;
    width: 340px;
    height: 600px;
    background-color: rgba(255, 255, 255, 0.1);
    border-radius: 30px;
    overflow: hidden;
    box-shadow: 0 10px 30px rgba(0,0,0,0.3);
    transition: all 0.3s ease;
    padding: 20px;
    display: flex;
    flex-direction: column;
    justify-content: space-between;
    z-index: 1;
}

#album-cover {
    width: 220px;
    height: 220px;
    border-radius: 50%;
    margin: 20px auto;
    display: block;
    box-shadow: 0 10px 30px rgba(0,0,0,0.3);
    animation: rotate 20s linear infinite;
    transition: all 0.3s ease;
}

#info-container {
    text-align: center;
    margin-bottom: 15px;
}

#song-title {
    font-size: 22px;
    margin: 0;
    font-weight: 600;
    text-shadow: 0 2px 4px rgba(0,0,0,0.3);
}

#artist-name {
    font-size: 16px;
    margin: 5px 0 0;
    opacity: 0.8;
}

#lyrics {
    height: 40px;
    overflow-y: auto;
    margin: 10px 0;
    text-align: center;
    font-size: 14px;
    opacity: 0.9;
}

#progress-container {
    position: relative;
    width: 100%;
    height: 40px;
    background-color: rgba(255,255,255,0.1);
    margin: 10px 0;
    border-radius: 20px;
    overflow: hidden;
    cursor: pointer;
}

#time-info {
    display: flex;
    justify-content: space-between;
    width: 100%;
    margin: 5px 0;
    font-size: 12px;
    opacity: 0.8;
}

#controls {
    display: flex;
    justify-content: space-between;
    align-items: center;
    margin-top: 15px;
}

.control-btn {
    background: none;
    border: none;
    color: white;
    font-size: 20px;
    cursor: pointer;
    transition: all 0.2s;
    opacity: 0.8;
}

.main-btn {
    font-size: 40px;
    opacity: 1;
}

#file-input-container {
    position: absolute;
    bottom: 20px;
    right: 20px;
    z-index: 10;
    cursor: move;
    display: flex;
    flex-direction: column;
    align-items: center;
}

#file-input {
    display: none;
}

.file-input-label, .lyrics-input-label {
    width: 40px;
    height: 40px;
    font-size: 18px;
    display: flex;
    justify-content: center;
    align-items: center;
    background-color: rgba(128, 128, 128, 0.8); /* 灰色 */
    color: white;
    border-radius: 50%;
    cursor: pointer;
    transition: all 0.2s;
    box-shadow: 0 2px 5px rgba(0,0,0,0.2);
    margin-bottom: 10px;
}

.file-input-label:hover, .lyrics-input-label:hover {
    background-color: rgba(160, 160, 160, 0.9); /* 稍微亮一点的灰色 */
    transform: scale(1.1);
    box-shadow: 0 4px 8px rgba(0,0,0,0.3);
}

/* 如果需要,可以添加一个提示文本 */
.file-input-label::after, .lyrics-input-label::after {
    content: none;
}

.file-input-label:hover::after, .lyrics-input-label:hover::after {
    opacity: 1;
}

#particle-container, #blur-overlay, #visualizer {
    position: absolute;
    top: 0;
    left: 0;
    width: 100%;
    height: 100%;
}

#blur-overlay {
    backdrop-filter: blur(5px);
    z-index: 1;
}

#visualizer {
    z-index: 2;
}

#album-cover:hover {
    transform: scale(1.05);
    box-shadow: 0 15px 35px rgba(0,0,0,0.4);
}

@keyframes rotate {
    from { transform: rotate(0deg); }
    to { transform: rotate(360deg); }
}

#progress-bar {
    position: absolute;
    top: 0;
    left: 0;
    height: 100%;
    background-color: rgba(29, 185, 84, 0.5);
    z-index: 3;
    transition: width 0.1s linear;
}

#time-info {
    display: flex;
    justify-content: space-between;
    width: 100%;
    margin: 5px 0;
    font-size: 12px;
    opacity: 0.8;
}

#controls {
    display: flex;
    justify-content: space-between;
    align-items: center;
    margin-top: 15px;
}

.control-btn:hover {
    transform: scale(1.2);
    opacity: 1;
}

.main-btn {
    font-size: 40px;
    opacity: 1;
}

#file-input-container {
    position: absolute;
    bottom: 20px;
    right: 20px;
    z-index: 10;
}

#file-input {
    display: none;
}

.file-input-label {
    width: 40px;
    height: 40px;
    font-size: 18px;
}

/* 其他样式保持不变 */

#cover-lyrics-container {
    position: relative;
    width: 220px;
    height: 220px;
    margin: 20px auto;
    cursor: pointer;
}

#album-cover, #lyrics {
    position: absolute;
    top: 0;
    left: 0;
    width: 100%;
    height: 100%;
    border-radius: 50%;
    transition: all 0.3s ease;
}

#lyrics {
    background-color: rgba(0, 0, 0, 0.7);
    color: white;
    display: flex;
    align-items: center;
    justify-content: center;
    text-align: center;
    padding: 10px;
    overflow-y: auto;
    font-size: 14px;
}

.lyrics-input-label {
    width: 40px;
    height: 40px;
    font-size: 18px;
    display: flex;
    justify-content: center;
    align-items: center;
    background-color: rgba(29, 185, 84, 0.8);
    color: white;
    border-radius: 50%;
    cursor: pointer;
    transition: all 0.2s;
    box-shadow: 0 2px 5px rgba(0,0,0,0.2);
    margin-top: 10px;
}

.lyrics-input-label:hover {
    background-color: rgba(30, 215, 96, 0.9);
    transform: scale(1.1);
    box-shadow: 0 4px 8px rgba(0,0,0,0.3);
}

/* ... 其他样式保持不变 ... */

#particles-js {
    position: fixed;
    top: 0;
    left: 0;
    width: 100%;
    height: 100%;
    z-index: -1;
}

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/2117735.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

【Day10-配置文件日志多线程】

配置文件 介绍 配置文件 在企业开发过程中&#xff0c;我们习惯把一些需要灵活配置的数据放在一些文本文件中&#xff0c;而不是在Java代码写死我们把这种存放程序配置信息的文件&#xff0c;统称为配置文件 Properties 是一个Map集合&#xff08;键值对集合&#xff09;&am…

推荐系统的基础_协同过滤(CF)

协同过滤&#xff08;Collaborative Filtering&#xff09;是一种推荐系统算法&#xff0c;它通过分析用户之间的相似性或者物品之间的相似性来预测用户可能感兴趣的物品。协同过滤算法主要有两种类型&#xff1a; 1. 用户基协同过滤&#xff08;User-based Collaborative Filt…

OceanMind海睿思“一种业务驱动数据治理的方法和系统”获国家发明专利!

近日&#xff0c;中新赛克海睿思最新技术&#xff1a;一种业务驱动数据治理的方法和系统&#xff08;专利号ZL 202410567107.8&#xff09;&#xff0c;获得国家知识产权局的正式授权&#xff0c;并取得专利证书。 当前&#xff0c;现有的数据治理方法论和平台工具主要聚焦于数…

IDEA 常用插件推荐,美观又实用!

1、 TONGYl Lingma - Your Al Coding Assistant. Type less, Code more. 通义灵码&#xff0c;是一款基于通义大模型的智能编码辅助工具&#xff0c;提供行级/函数级实时续写、自然语言生成代码、单元测试生成、代码注释生成、代码解释、研发智能问答、异常报错排查等能力&…

JVM 调优篇2 jvm的内存结构以及堆栈参数设置与查看

一 jvm的内存模型 2.1 jvm内存模型概览 二 实操案例 2.1 设置和查看栈大小 1.代码 /*** 演示栈中的异常:StackOverflowError** author shkstart* create 2020 下午 9:08** 设置栈的大小&#xff1a; -Xss (-XX:ThreadStackSize)** -XX:PrintFlagsFinal*/ public class S…

【C++】C++ STL 探索:List使用与背后底层逻辑

C语法相关知识点可以通过点击以下链接进行学习一起加油&#xff01;命名空间缺省参数与函数重载C相关特性类和对象-上篇类和对象-中篇类和对象-下篇日期类C/C内存管理模板初阶String使用String模拟实现Vector使用及其模拟实现 本文将通过模拟实现List&#xff0c;从多个角度深入…

第J3周:DenseNet算法实战与解析(pytorch版)

>- **&#x1f368; 本文为[&#x1f517;365天深度学习训练营]中的学习记录博客** >- **&#x1f356; 原作者&#xff1a;[K同学啊]** &#x1f4cc; 本周任务&#xff1a; ●1.请根据本文 Pytorch 代码&#xff0c;编写出相应的 TensorFlow 代码&#xff08;建议使用…

《黑神话·悟空》背后的佛学义理探析

《黑神话悟空》不仅是一款备受期待的动作冒险游戏&#xff0c;其背后的深厚文化内涵&#xff0c;尤其是佛教义理的体现&#xff0c;更是吸引了不少玩家和佛学爱好者的关注。本文将通过对游戏剧情的解析&#xff0c;结合佛教思想&#xff0c;探讨《黑神话悟空》中所蕴含的哲学智…

冯·诺依曼体系结构

纯硬件的计算机结构应该就是输入设备——CPU——输出设备 冯诺依曼体系结构加入了存储器&#xff08;内存&#xff09; 因为数据是要在计算机体系结构中流动的&#xff0c;流动过程中对数据进行加工处理&#xff0c;数据从一个设备到另流动到另一个设备本质是一种数据拷贝。C…

HDFS常用命令及Python连接HDFS操作

目录 一、HDFS常用命令 二、Python连接HDFS操作 一、HDFS常用命令 HDFS&#xff08;Hadoop Distributed File System&#xff0c;Hadoop分布式文件系统&#xff09;是Hadoop集群中的一部分&#xff0c;用于存储大量数据&#xff0c;并运行在商用硬件集群上。以下是HDFS中常用…

6款好用到离谱的宝藏软件,每一款都超出你的认知

你的电脑里有没有那种&#xff0c;无论重装多少次系统&#xff0c;都要第一时间安装的软件&#xff1f; 请把它的名字打在评论区&#xff01;本期分享6款&#xff0c;免费也能吊打付费的Windows电脑必装软件。 最大程度的增强Windows系统的功能&#xff0c;良心分享&#xff…

一文讲解多种GIS分析功能

GIS行业有很多分析功能&#xff0c;对于刚入行的新手有着足够的吸引力&#xff0c;其实有许多分析功能实现原理大差不差&#xff0c;比如模型压平&#xff0c;基于模型的淹没分析以及模型裁切。本文将以模型裁切为切入口进行介绍其中原理。 首先 &#xff08;立方体剖切示意图…

只需一个类文件,Erupt 可以能完成整个后台管理?这个低代码值得一试

只需一个类文件&#xff0c;Erupt 竟然能搞定整个后台管理&#xff1f;这个低代码值得一试 在纷繁复杂的后端开发世界里&#xff0c;Erupt 就像是一剂强心针&#xff0c;用一个 .class 文件就能实现后台管理功能&#xff0c;简直让人感叹“开发也可以这么简单&#xff01;”本文…

linux进程的概念和pid

进程的概念 进程是参与分配资源&#xff08;cpu&#xff0c;内存&#xff09;得实体&#xff0c;比如打开qq&#xff0c;浏览器就是打开了进程。 进程这么多&#xff0c;如何管理进程呢&#xff1f; 在linux下进程通过PCB&#xff08;task_struct&#xff09;来管理进程 ta…

足浴行业在线预约小程序源码系统+支持拼团功能 带完整的安装代码包以及搭建部署教程

系统概述 在快节奏的现代生活中&#xff0c;人们对健康养生的需求日益增长&#xff0c;足浴行业作为传统养生方式之一&#xff0c;其市场需求也随之不断扩大。为了满足消费者日益增长的便捷性需求&#xff0c;一款集在线预约、拼团优惠于一体的足浴行业小程序源码系统应运而生…

Vue/cli不同环境下打包后js文件没有添加hash值-会导致缓存问题-解决

环境变量 包文件判断是根据NODE_ENV=production,这时会对应打包加上hash值,所以在配置不同环境对应命令的时候,把NODE_ENV=production加上 全局的环境变量需要以VUE_APP_ 开头 process.env.VUE_APP_ENV 会读取不到值 .env 文件配置 NODE_ENV=production 才会按照hash模式去…

利用数据分析提升SEO排名的7种方法

我们都听过“大数据分析”这个词。科技让我们能够清晰地了解我们的活动和内容的表现——向我们提供了关于受众的宝贵信息&#xff0c;甚至可以精确到他们在Google和其他搜索引擎上使用的具体搜索词。 你已经在你的业务中使用数据分析了吗&#xff1f;如果是&#xff0c;你有利…

漏水监测报警摄像机

漏水监测报警摄像机 是一种智能设备&#xff0c;专门用于监测管道或设备的漏水情况&#xff0c;并能在检测到漏水时发出警报&#xff0c;帮助用户及时发现并处理水患。这种摄像机通常配备高清摄像头和敏感的水滴传感器&#xff0c;能够全天候地监测管道周围的情况。 当漏水摄像…

【ARM compiler】生成ELF文件中包含了那些内容

【更多软件使用问题请点击亿道电子官方网站】 文档目标&#xff1a;用于了解ARM compiler生成的ELF文件中存储的内容进行了解 问题场景&#xff1a;ELF文件主要用于通过调试软件对于代码的运行顺序和数据链接等内容进行分析。了解一下ARM compiler生成ELF文件包含那些内容。 软…

蓝牙--关于bta_av_main.cc文件的讲解

简单概要下: BTIF:提供bluedroid对外的接口 BTA:提供各种profile的实现 stack:协议实现与连接管理 上层在建立A2dp connect连接的时候,先调用到btif层的btif_av.cc中函数src_connect_sink,接着调用bta层bta_av_api.cc中函数BTA_AvOpen,经过内部state machine处理,最…