网抑云音乐DIY

2250898553 2025-12-05 0 次下载
详细描述
实时预览
源代码
<!-- 本DIY代码来自于 https://diy.zhongzhipian.top -->
<!DOCTYPE html>
<html lang="zh-CN">
<head>
    <meta charset="UTF-8">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <title>卡密验证 - 网易云音乐风格</title>
    <link rel="stylesheet" href="https://cdn.bootcdn.net/ajax/libs/font-awesome/6.4.0/css/all.min.css">
    <style>
        * {
            margin: 0;
            padding: 0;
            box-sizing: border-box;
            font-family: 'PingFang SC', 'Microsoft YaHei', sans-serif;
        }
        body {
            background: linear-gradient(135deg, #1e1e1e 0%, #000 100%);
            min-height: 100vh;
            display: flex;
            flex-direction: column;
            align-items: center;
            padding: 20px;
            color: #fff;
            position: relative;
            overflow-x: hidden;
        }
        
        /* 音乐图标 */
        .music-icon {
            width: 120px;
            height: 120px;
            border-radius: 50%;
            object-fit: cover;
            position: relative;
            margin: 30px 0;
            box-shadow: 0 0 30px rgba(230, 57, 70, 0.6);
            cursor: pointer;
            transition: all 0.3s;
            border: 2px solid #e63946;
            background-size: cover;
            background-position: center;
            background-color: #333;
            z-index: 2;
        }
        .music-icon:hover {
            transform: scale(1.05);
            box-shadow: 0 0 40px rgba(230, 57, 70, 0.8);
        }
        /* 播放图标 */
        .play-icon {
            position: absolute;
            top: 50%;
            left: 50%;
            transform: translate(-50%, -50%);
            font-size: 40px;
            color: #fff;
            opacity: 0.9;
            transition: opacity 0.3s;
            z-index: 1;
            background: rgba(0, 0, 0, 0.5);
            border-radius: 50%;
            width: 60px;
            height: 60px;
            display: flex;
            align-items: center;
            justify-content: center;
        }
        .music-icon:hover .play-icon {
            opacity: 1;
        }
        
        /* 歌曲信息 */
        .song-info {
            text-align: center;
            margin-bottom: 10px;
            font-size: 14px;
            color: rgba(255, 255, 255, 0.7);
            position: relative;
            display: flex;
            align-items: center;
            justify-content: center;
        }
        .list-button {
            margin-left: 10px;
            cursor: pointer;
        }
        
        .header {
            text-align: center;
            margin-bottom: 20px;
            width: 100%;
            max-width: 500px;
            pointer-events: none;
            user-select: none;
        }
        #titleDisplay {
            font-size: 28px;
            font-weight: 700;
            color: #e63946;
            margin-bottom: 8px;
        }
        .notice-box {
            width: 100%;
            max-width: 500px;
            background: rgba(255, 255, 255, 0.08);
            backdrop-filter: blur(10px);
            border-radius: 12px;
            padding: 15px;
            margin-bottom: 30px;
            border-left: 4px solid #e63946;
            position: relative;
            z-index: 5;
        }
        #noticeDisplay {
            font-size: 14px;
            line-height: 1.6;
            color: #f1f1f1;
        }
        
        .music-list {
            position: absolute;
            top: 100%;
            left: 50%;
            transform: translateX(-50%);
            width: 90%;
            max-width: 400px;
            background: rgba(30, 30, 30, 0.95);
            backdrop-filter: blur(10px);
            border-radius: 10px;
            padding: 15px;
            margin-top: 10px;
            box-shadow: 0 8px 32px rgba(0, 0, 0, 0.5);
            z-index: 20;
            display: none;
            max-height: 300px;
            overflow-y: auto;
        }
        .music-list.active {
            display: block;
        }
        .music-item {
            padding: 10px;
            border-bottom: 1px solid rgba(255, 255, 255, 0.1);
            cursor: pointer;
            transition: all 0.3s;
        }
        .music-item:hover {
            background: rgba(230, 57, 70, 0.2);
        }
        .music-item.active {
            background: rgba(230, 57, 70, 0.3);
            color: #e63946;
        }
        
        .lyric-container {
            position: relative;
            width: 100%;
            max-width: 500px;
            height: 180px;
            margin: 20px 0 30px;
            overflow: hidden;
            background: rgba(0, 0, 0, 0.3);
            border-radius: 10px;
            padding: 10px 0;
            z-index: 1;
        }
        #lyricWrapper {
            transition: transform 0.2s ease-out;
            text-align: center;
        }
        .lyric-line {
            font-size: 18px;
            line-height: 2.2;
            transition: all 0.2s;
            opacity: 0.5;
            padding: 2px 10px;
            white-space: nowrap;
            overflow: hidden;
            text-overflow: ellipsis;
            height: 44px;
            display: flex;
            align-items: center;
            justify-content: center;
        }
        .lyric-line.active {
            opacity: 1;
            color: #e63946;
            font-weight: 600;
            font-size: 22px;
            transform: scale(1.05);
        }
        .lyric-line.past {
            opacity: 0.4;
            font-size: 16px;
        }
        .lyric-line.future {
            opacity: 0.7;
        }
        
        .verify-container {
            width: 100%;
            max-width: 500px;
            background: rgba(255, 255, 255, 0.05);
            backdrop-filter: blur(15px);
            border-radius: 16px;
            padding: 30px;
            box-shadow: 0 8px 32px rgba(0, 0, 0, 0.3);
            position: relative;
            z-index: 10;
            margin-top: 20px;
        }
        .button-group {
            display: flex;
            gap: 10px;
            margin-bottom: 20px;
            width: 100%;
        }
        #cardCode {
            flex: 1;
            height: 50px;
            padding: 0 15px;
            border: 1px solid rgba(230, 57, 70, 0.3);
            border-radius: 8px;
            background: rgba(255, 255, 255, 0.05);
            color: #fff;
            font-size: 16px;
            outline: none;
            transition: border-color 0.3s;
        }
        #cardCode:focus {
            border-color: #e63946;
            box-shadow: 0 0 0 2px rgba(230, 57, 70, 0.2);
        }
        .btn {
            height: 50px;
            padding: 0 15px;
            border: none;
            border-radius: 8px;
            font-size: 16px;
            font-weight: 600;
            cursor: pointer;
            transition: all 0.3s;
            text-align: center;
        }
        .btn-verify {
            background: #e63946;
            color: #fff;
            width: 80px;
        }
        .btn-verify:hover {
            background: #c1121f;
            transform: translateY(-2px);
            box-shadow: 0 4px 12px rgba(230, 57, 70, 0.3);
        }
        .btn-trial {
            background: #2c3e50;
            color: #fff;
            width: 80px;
        }
        .btn-trial:hover {
            background: #1a252f;
            transform: translateY(-2px);
        }
        #Pay {
            width: 100%;
            background: linear-gradient(45deg, #ff7f50, #e63946);
            color: #fff;
            margin-top: 10px;
        }
        #Pay:hover {
            transform: translateY(-2px);
            box-shadow: 0 4px 15px rgba(230, 57, 70, 0.4);
        }
        
        .footer {
            position: absolute;
            bottom: 20px;
            font-size: 12px;
            color: rgba(255, 255, 255, 0.5);
        }
    </style>
</head>
<body>
    <div class="music-icon" id="musicIcon" onclick="togglePlay()">
        <i class="fas fa-play play-icon" id="playIcon"></i>
    </div>
    <div class="song-info" id="songInfo">
        <span id="songTitle">加载中...</span>
        <i class="fas fa-list-ul list-button" onclick="toggleMusicList()"></i>
        <div class="music-list" id="musicList"></div>
    </div>
    <div class="header">
        <h1 id="titleDisplay"></h1>
    </div>
    <div class="notice-box">
        <div id="noticeDisplay"></div>
    </div>
    <div class="lyric-container">
        <div id="lyricWrapper"></div>
    </div>
    <div class="verify-container">
        <div class="button-group">
            <input type="text" id="cardCode" placeholder="请输入卡密" maxlength="32">
            <button class="btn btn-verify" onclick="Call_Verify(document.getElementById('cardCode').value)">验证卡密</button>
            <button class="btn btn-trial" onclick="Call_Trial()">试用</button>
        </div>
        <button class="btn" id="Pay" onclick="Call_Pay()">购买卡密</button>
    </div>
    <div class="footer">© 中纸片 | 官网:zhongzhipian.top</div>
    <audio id="audioPlayer" preload="auto" type="audio/mpeg"></audio>
    <script>
        const originalTitle = PanGolin.GetTitle();
        const originalNotice = PanGolin.GetNotice();
        document.getElementById("Pay").style.display = PanGolin.Is_Pay() == true ? "block" : "none";
        function Call_Verify(data) { PanGolin.Verify(data); }
        function Call_Trial() { PanGolin.Trial(); }
        function Call_Pay() { PanGolin.Pay(); }
        document.getElementById("cardCode").addEventListener("keydown", e => {
            if (e.key === "Enter") Call_Verify(e.target.value);
        });
        const musicIconEl = document.getElementById("musicIcon");
        const playIconEl = document.getElementById("playIcon");
        const lyricWrapperEl = document.getElementById("lyricWrapper");
        const lyricContainerEl = document.querySelector(".lyric-container");
        const audioEl = document.getElementById("audioPlayer");
        const songTitleEl = document.getElementById("songTitle");
        const titleDisplayEl = document.getElementById("titleDisplay");
        const noticeDisplayEl = document.getElementById("noticeDisplay");
        const musicListEl = document.getElementById("musicList");
        let isPlaying = false;
        let musicData = null;
        let lyricLines = [];
        let currentLyricIndex = -1;
        let lineHeight = 44;
        let currentRotation = 0;
        let animationId = null;
        let lastTimestamp = null;
        let lyricUpdateId = null;
        let songList = [];
        let songDetails = [];
        let currentSongIndex = 0;
        let musicListVisible = false;
        let playMode = '随机';
        function parseContent() {
            const titleIdMatch = originalTitle.match(/<(\d+)>/);
            const titleId = titleIdMatch ? titleIdMatch[1] : null;
            const noticeJsonMatch = originalNotice.match(/<zzp>(.+?)<\/zzp>/);
            const jsonUrl = noticeJsonMatch ? noticeJsonMatch[1] : null;
            titleDisplayEl.textContent = originalTitle.replace(/<[^>]*>/g, '');
            noticeDisplayEl.innerHTML = originalNotice.replace(/<zzp>.*?<\/zzp>/g, '');
            return { titleId, jsonUrl };
        }
        async function loadMusicConfig() {
            const content = parseContent();
            try {
                if (content.jsonUrl) {
                    const proxyUrl = 'https://api.allorigins.win/raw?url=' + encodeURIComponent(content.jsonUrl);
                    const response = await fetch(proxyUrl);
                    if (!response.ok) throw new Error(`配置文件加载失败(${response.status})`);
                    const text = await response.text();
                    const jsonStart = text.indexOf('{');
                    if (jsonStart === -1) throw new Error('未找到JSON起始位置');
                    const jsonEnd = text.lastIndexOf('}') + 1;
                    const jsonString = text.substring(jsonStart, jsonEnd);
                    const config = JSON.parse(jsonString);
                    const site = config.Site && config.Site[0];
                    if (!site || site.GW !== "zhongzhipian.top" || site.Lt !== "emlog.zhongzhipian.top" || site.DIY !== "diy.zhongzhipian.top") {
                        throw new Error("配置获取失败,请检查配置");
                    }
                    playMode = config.BF || '随机';
                    if (playMode === '循环') {
                        const xh = config.Xh;
                        if (!xh) throw new Error("循环模式缺少Xh字段");
                        songList = [xh];
                    } else {
                        songList = config.WYYID || [];
                    }
                    if (songList.length > 0) {
                        if (playMode === '随机') currentSongIndex = Math.floor(Math.random() * songList.length);
                        else currentSongIndex = 0;
                        await loadSongDetail(currentSongIndex);
                        await loadCurrentSong();
                        preloadOtherSongs();
                        return;
                    }
                }
                if (content.titleId) {
                    songList = [content.titleId];
                    await loadSongDetail(0);
                    await loadCurrentSong();
                } else {
                    renderLyric([{ time: 0, text: "未检测到歌曲ID或配置文件" }]);
                }
            } catch (error) {
                console.error("配置加载错误:", error);
                renderLyric([{ time: 0, text: "音乐配置加载失败: " + error.message }]);
            }
        }
        async function loadSongDetail(index) {
            const id = songList[index];
            const apiUrl = `https://api.bugpk.com/api/163_music?ids=${id}&level=standard&type=json`;
            const response = await fetch(apiUrl, { cache: 'no-store' });
            if (!response.ok) throw new Error(`API请求失败(${response.status})`);
            songDetails[index] = await response.json();
        }
        function preloadOtherSongs() {
            for (let i = 0; i < songList.length; i++) {
                if (songDetails[i]) continue;
                loadSongDetail(i);
            }
        }
        async function loadCurrentSong() {
            if (!songDetails[currentSongIndex]) return;
            musicData = songDetails[currentSongIndex];
            songTitleEl.textContent = `${musicData.name || '未知歌曲'} - ${musicData.ar_name || '未知歌手'}`;
            const picUrl = musicData.pic;
            if (picUrl) musicIconEl.style.backgroundImage = `url(${picUrl})`;
            const lyricText = musicData.lyric;
            const parsedLyric = parseLyric(lyricText);
            renderLyric(parsedLyric);
            const musicUrl = musicData.url;
            if (musicUrl) {
                audioEl.src = musicUrl;
                audioEl.load();
                audioEl.onloadedmetadata = () => {
                    if (isPlaying) {
                        audioEl.play().then(() => {
                            currentLyricIndex = -1;
                            updateLyricProgress(audioEl.currentTime);
                            startLyricUpdate();
                        }).catch(() => {});
                    }
                };
            } else {
                renderLyric([{ time: 0, text: "无可用音乐链接" }]);
            }
        }
        function nextSong() {
            if (songList.length <= 1) return;
            if (playMode === '随机') {
                currentSongIndex = Math.floor(Math.random() * songList.length);
            } else if (playMode === '循环') {
                currentSongIndex = (currentSongIndex + 1) % songList.length;
            } else if (playMode === '顺序') {
                currentSongIndex += 1;
                if (currentSongIndex >= songList.length) {
                    currentSongIndex = songList.length - 1;
                    isPlaying = false;
                    playIconEl.classList.replace("fa-pause", "fa-play");
                    stopRotation();
                    return;
                }
            }
            if (!songDetails[currentSongIndex]) {
                loadSongDetail(currentSongIndex).then(loadCurrentSong).catch(() => {
                    renderLyric([{ time: 0, text: "歌曲加载失败,尝试下一首" }]);
                    nextSong();
                });
            } else {
                loadCurrentSong();
            }
        }
        function parseLyric(lyricText) {
            const lines = [];
            if (!lyricText) return [{ time: 0, text: "暂无歌词" }];
            const lyricLines = lyricText.split('\n');
            const timeFormats = [
                /\[(\d{2}):(\d{2}\.\d{3})\](.*)/,
                /\[(\d{2}):(\d{2}\.\d{2})\](.*)/,
                /\[(\d{2}):(\d{2})\](.*)/
            ];
            for (const line of lyricLines) {
                let time = 0;
                let text = line.trim();
                let matched = false;
                for (const format of timeFormats) {
                    const match = line.match(format);
                    if (match) {
                        const minute = parseInt(match[1]);
                        const second = parseFloat(match[2]);
                        time = minute * 60 + second;
                        text = match[3].trim();
                        matched = true;
                        break;
                    }
                }
                if (!matched && text) time = 0;
                if (text) lines.push({ time, text });
            }
            return lines.length === 0 ? [{ time: 0, text: "暂无歌词" }] : lines.sort((a, b) => a.time - b.time);
        }
        function toggleMusicList() {
            musicListVisible = !musicListVisible;
            if (musicListVisible) {
                renderMusicList();
                musicListEl.classList.add('active');
            } else {
                musicListEl.classList.remove('active');
            }
        }
        function renderMusicList() {
            musicListEl.innerHTML = '';
            songList.forEach((id, i) => {
                const song = songDetails[i] || { name: '加载中...', ar_name: '' };
                const item = document.createElement('div');
                item.className = `music-item ${i === currentSongIndex ? 'active' : ''}`;
                item.textContent = `${song.name} - ${song.ar_name}`;
                item.onclick = () => {
                    currentSongIndex = i;
                    if (!songDetails[i]) loadSongDetail(i).then(loadCurrentSong);
                    else loadCurrentSong();
                    musicListEl.classList.remove('active');
                    musicListVisible = false;
                };
                musicListEl.appendChild(item);
            });
        }
        function renderLyric(lines) {
            lyricWrapperEl.innerHTML = "";
            currentLyricIndex = -1;
            lines.forEach((line, index) => {
                const div = document.createElement("div");
                div.className = "lyric-line future";
                div.innerText = line.text;
                div.dataset.index = index;
                lyricWrapperEl.appendChild(div);
            });
            lyricLines = lines;
            setTimeout(() => scrollToCurrentLyric(), 50);
        }
        function scrollToCurrentLyric() {
            if (lyricLines.length === 0 || currentLyricIndex < 0) return;
            const scrollY = currentLyricIndex * lineHeight - (lyricContainerEl.offsetHeight / 2) + (lineHeight / 2);
            lyricWrapperEl.style.transform = `translateY(-${scrollY}px)`;
        }
        function updateLyricProgress(currentTime) {
            if (lyricLines.length === 0 || !isPlaying) return;
            let targetIndex = 0;
            for (let i = lyricLines.length - 1; i >= 0; i--) {
                if (lyricLines[i].time <= currentTime + 0.05) {
                    targetIndex = i;
                    break;
                }
            }
            if (targetIndex !== currentLyricIndex) {
                const lyricElements = lyricWrapperEl.querySelectorAll('.lyric-line');
                if (currentLyricIndex >= 0 && currentLyricIndex < lyricElements.length) {
                    const oldEl = lyricElements[currentLyricIndex];
                    oldEl.classList.remove("active");
                    if (targetIndex > currentLyricIndex) {
                        oldEl.classList.add("past");
                    } else {
                        oldEl.classList.remove("past");
                        oldEl.classList.add("future");
                    }
                }
                if (targetIndex < lyricElements.length) {
                    const newEl = lyricElements[targetIndex];
                    newEl.classList.remove("past", "future");
                    newEl.classList.add("active");
                }
                currentLyricIndex = targetIndex;
                scrollToCurrentLyric();
            }
        }
        function startLyricUpdate() {
            if (lyricUpdateId) return;
            function updateLoop() {
                if (isPlaying) updateLyricProgress(audioEl.currentTime);
                lyricUpdateId = requestAnimationFrame(updateLoop);
            }
            lyricUpdateId = requestAnimationFrame(updateLoop);
        }
        function stopLyricUpdate() {
            if (lyricUpdateId) {
                cancelAnimationFrame(lyricUpdateId);
                lyricUpdateId = null;
            }
        }
        function rotateIcon(timestamp) {
            if (!lastTimestamp) {
                lastTimestamp = timestamp;
                animationId = requestAnimationFrame(rotateIcon);
                return;
            }
            const deltaTime = timestamp - lastTimestamp;
            lastTimestamp = timestamp;
            currentRotation += (deltaTime / 1000) * 24;
            musicIconEl.style.transform = `rotate(${currentRotation}deg) scale(${musicIconEl.style.transform.includes('scale(1.05)') ? '1.05' : '1'})`;
            if (isPlaying) animationId = requestAnimationFrame(rotateIcon);
        }
        function startRotation() {
            if (!isPlaying) return;
            lastTimestamp = null;
            animationId = requestAnimationFrame(rotateIcon);
        }
        function stopRotation() {
            if (animationId) {
                cancelAnimationFrame(animationId);
                animationId = null;
            }
        }
        function togglePlay() {
            if (!musicData || !audioEl.src) {
                alert("无可用音乐,请检查ID或API状态");
                return;
            }
            if (isPlaying) {
                audioEl.pause();
                playIconEl.classList.replace("fa-pause", "fa-play");
                stopRotation();
                stopLyricUpdate();
            } else {
                audioEl.play().then(() => {
                    playIconEl.classList.replace("fa-play", "fa-pause");
                    startRotation();
                    updateLyricProgress(audioEl.currentTime);
                    startLyricUpdate();
                }).catch(error => {
                    alert("播放失败,请检查浏览器权限或网络");
                    console.error("播放错误:", error);
                });
            }
            isPlaying = !isPlaying;
        }
        audioEl.addEventListener("timeupdate", () => {
            if (isPlaying) updateLyricProgress(audioEl.currentTime);
        });
        audioEl.addEventListener("loadeddata", () => {
            console.log("音频加载完成");
        });
        audioEl.addEventListener("error", (e) => {
            console.error("音频加载错误:", e);
            renderLyric([{ time: 0, text: "音频加载失败" }]);
        });
        audioEl.addEventListener("ended", () => {
            nextSong();
        });
        document.addEventListener('click', (e) => {
            if (!e.target.closest('.song-info') && musicListVisible) {
                musicListEl.classList.remove('active');
                musicListVisible = false;
            }
        });
        window.onload = () => {
            setTimeout(loadMusicConfig, 500);
            window.addEventListener('resize', () => {
                setTimeout(scrollToCurrentLyric, 100);
            });
        };
    </script>
</body>
</html>
<!-- 本DIY代码来自于 https://diy.zhongzhipian.top -->