312 lines
16 KiB
HTML
312 lines
16 KiB
HTML
<!DOCTYPE html>
|
|
<html lang="zh-CN">
|
|
<head>
|
|
<meta charset="UTF-8">
|
|
<meta name="viewport" content="width=device-width, initial-scale=1.0, viewport-fit=cover">
|
|
<meta name="apple-mobile-web-app-capable" content="yes">
|
|
<meta name="apple-mobile-web-app-status-bar-style" content="black-translucent">
|
|
<meta name="apple-mobile-web-app-title" content="八音盒">
|
|
<meta name="theme-color" content="#060612">
|
|
<link rel="manifest" href="manifest.json">
|
|
<link rel="apple-touch-icon" href="apple-touch-icon.svg">
|
|
<title>八音盒</title>
|
|
<link rel="stylesheet" href="zen_box.css">
|
|
</head>
|
|
<body>
|
|
|
|
<!-- Starfield Background -->
|
|
<div class="starfield">
|
|
<div class="stars-sm"></div>
|
|
<div class="stars-md"></div>
|
|
<div class="stars-lg"></div>
|
|
</div>
|
|
|
|
<div class="app">
|
|
|
|
<!-- Header -->
|
|
<div class="header">
|
|
<div class="header-title">
|
|
<svg class="header-icon" viewBox="0 0 100 100" fill="none" xmlns="http://www.w3.org/2000/svg">
|
|
<circle cx="50" cy="44" r="32" stroke="#e8b86d" stroke-width="1.2" opacity="0.25"/>
|
|
<ellipse cx="50" cy="84" rx="22" ry="4" fill="rgba(232,184,109,0.12)"/>
|
|
<path d="M33 66 C24 65 16 70 14 78 C12 84 16 88 24 87 C32 86 42 79 44 72 L44 67 Z" fill="#e8e6f0"/>
|
|
<path d="M67 66 C76 65 84 70 86 78 C88 84 84 88 76 87 C68 86 58 79 56 72 L56 67 Z" fill="#e8e6f0"/>
|
|
<path d="M44 67 C44 67 40 58 40 50 C40 40 44 34 48 30 L50 29 L52 30 C56 34 60 40 60 50 C60 58 56 67 56 67 C53 74 47 74 44 67 Z" fill="#e8e6f0"/>
|
|
<ellipse cx="50" cy="72" rx="10" ry="4" fill="#e8e6f0"/>
|
|
<rect x="46" y="25" width="8" height="7" rx="2" fill="#e8e6f0"/>
|
|
<ellipse cx="50" cy="17" rx="11" ry="12" fill="#e8e6f0"/>
|
|
<ellipse cx="50" cy="6" rx="5" ry="4" fill="#e8e6f0"/>
|
|
<path d="M34 36 Q28 33 28 29 Q28 25 34 22" stroke="#e8b86d" stroke-width="1.2" stroke-linecap="round" fill="none" opacity="0.7"/>
|
|
<path d="M66 36 Q72 33 72 29 Q72 25 66 22" stroke="#e8b86d" stroke-width="1.2" stroke-linecap="round" fill="none" opacity="0.7"/>
|
|
<circle cx="50" cy="7" r="1.5" fill="#e8b86d" opacity="0.8"/>
|
|
</svg>
|
|
八<span>音</span>盒
|
|
</div>
|
|
<div class="header-count" id="trackCount">0 首</div>
|
|
</div>
|
|
|
|
<!-- Zen Center -->
|
|
<div class="zen-center">
|
|
<div class="orbit-wrap">
|
|
<div class="orbit-ring"></div>
|
|
<div class="orbit-ring-2"></div>
|
|
<div class="orbit-dot-1"></div>
|
|
<div class="orbit-dot-2"></div>
|
|
<div class="zen-glow" id="zenGlow"></div>
|
|
<div class="zen-waves">
|
|
<div class="zen-wave" id="zenWave0"></div>
|
|
<div class="zen-wave" id="zenWave1"></div>
|
|
<div class="zen-wave" id="zenWave2"></div>
|
|
</div>
|
|
<div class="zen-figure" id="zenFigure">
|
|
<!-- Zen meditation figure — natural lotus posture, warm gold silhouette -->
|
|
<svg viewBox="0 0 200 210" fill="none" xmlns="http://www.w3.org/2000/svg">
|
|
|
|
<!-- Ground shadow -->
|
|
<ellipse cx="100" cy="178" rx="44" ry="5.5" fill="rgba(232,184,109,0.08)"/>
|
|
|
|
<!-- === LOWER BODY: Full lotus base === -->
|
|
<!-- Lap platform — wide, grounded oval -->
|
|
<ellipse cx="100" cy="158" rx="46" ry="14" fill="#c8973e" opacity="0.70"/>
|
|
|
|
<!-- Left knee extending out and down -->
|
|
<path d="M 54 150 C 44 152, 36 158, 36 165 C 36 171, 42 175, 52 174 C 60 173, 68 167, 72 160 C 74 155, 70 149, 64 148 Z" fill="#d4a045" opacity="0.78"/>
|
|
|
|
<!-- Right knee extending out and down -->
|
|
<path d="M 146 150 C 156 152, 164 158, 164 165 C 164 171, 158 175, 148 174 C 140 173, 132 167, 128 160 C 126 155, 130 149, 136 148 Z" fill="#d4a045" opacity="0.78"/>
|
|
|
|
<!-- Left foot resting on right thigh — visible instep -->
|
|
<path d="M 124 148 C 132 144, 142 145, 146 150 C 148 153, 145 157, 138 157 C 131 157, 124 153, 122 150 Z" fill="#c8973e" opacity="0.72"/>
|
|
|
|
<!-- Right foot resting on left thigh — visible instep -->
|
|
<path d="M 76 148 C 68 144, 58 145, 54 150 C 52 153, 55 157, 62 157 C 69 157, 76 153, 78 150 Z" fill="#c8973e" opacity="0.72"/>
|
|
|
|
<!-- === TORSO: Upright, slightly tapered === -->
|
|
<path d="
|
|
M 72 152
|
|
C 70 140, 69 126, 70 114
|
|
C 71 102, 75 92, 82 85
|
|
C 88 79, 94 77, 100 76
|
|
C 106 77, 112 79, 118 85
|
|
C 125 92, 129 102, 130 114
|
|
C 131 126, 130 140, 128 152
|
|
C 120 157, 110 160, 100 160
|
|
C 90 160, 80 157, 72 152
|
|
Z
|
|
" fill="#e0a84e" opacity="0.88"/>
|
|
|
|
<!-- Chest line — subtle center crease -->
|
|
<path d="M 100 88 C 99 108, 99 130, 100 152" stroke="#c8882a" stroke-width="0.8" opacity="0.18" stroke-linecap="round"/>
|
|
|
|
<!-- === ARMS: Draped down naturally to lap === -->
|
|
<!-- Left upper arm — hangs from shoulder, angles inward -->
|
|
<path d="M 70 114 C 64 116, 58 122, 56 130 C 54 136, 56 142, 62 146 C 68 148, 75 146, 78 140 C 74 136, 70 128, 70 118 Z" fill="#d4a045" opacity="0.82"/>
|
|
|
|
<!-- Right upper arm -->
|
|
<path d="M 130 114 C 136 116, 142 122, 144 130 C 146 136, 144 142, 138 146 C 132 148, 125 146, 122 140 C 126 136, 130 128, 130 118 Z" fill="#d4a045" opacity="0.82"/>
|
|
|
|
<!-- === HANDS in dhyana mudra: left palm up, right resting on top === -->
|
|
<!-- Left hand — palm up, fingers slightly curved -->
|
|
<path d="M 84 154 C 80 152, 76 152, 75 155 C 74 158, 76 162, 82 163 C 88 164, 96 162, 98 158 C 98 155, 92 154, 84 154 Z" fill="#d4a045" opacity="0.80"/>
|
|
<!-- Right hand resting on left, fingers forward -->
|
|
<path d="M 102 152 C 98 150, 94 150, 92 153 C 90 156, 91 160, 96 162 C 102 163, 110 161, 114 157 C 116 154, 112 151, 106 151 Z" fill="#c8973e" opacity="0.78"/>
|
|
<!-- Thumb tips touching — small oval -->
|
|
<ellipse cx="99" cy="153" rx="4" ry="2.5" fill="#e8b86d" opacity="0.55"/>
|
|
|
|
<!-- === NECK: slim, natural === -->
|
|
<path d="M 93 78 C 93 74, 96 70, 100 69 C 104 70, 107 74, 107 78 L 107 86 L 93 86 Z" fill="#e0a84e" opacity="0.88"/>
|
|
|
|
<!-- === HEAD: slightly bowed forward, serene === -->
|
|
<!-- Head shape — slightly elongated, chin tucked -->
|
|
<path d="
|
|
M 82 54
|
|
C 82 36, 90 26, 100 25
|
|
C 110 26, 118 36, 118 54
|
|
C 118 66, 112 74, 106 77
|
|
L 100 79
|
|
L 94 77
|
|
C 88 74, 82 66, 82 54
|
|
Z
|
|
" fill="#e0a84e" opacity="0.88"/>
|
|
|
|
<!-- === HAIR: simple smooth cap === -->
|
|
<path d="M 82 50 C 82 36, 90 26, 100 25 C 110 26, 118 36, 118 50 C 112 43, 106 39, 100 38 C 94 39, 88 43, 82 50 Z" fill="#b8812a" opacity="0.80"/>
|
|
|
|
<!-- === FACE: eyes closed, barely-there features === -->
|
|
<!-- Brow ridge — very subtle -->
|
|
<path d="M 89 53 Q 93 51, 97 53" stroke="#8a6020" stroke-width="0.8" stroke-linecap="round" fill="none" opacity="0.35"/>
|
|
<path d="M 103 53 Q 107 51, 111 53" stroke="#8a6020" stroke-width="0.8" stroke-linecap="round" fill="none" opacity="0.35"/>
|
|
<!-- Eyes closed — downward arc, peaceful -->
|
|
<path d="M 89 57 Q 93 61, 97 57" stroke="#7a5010" stroke-width="1.4" stroke-linecap="round" fill="none" opacity="0.65"/>
|
|
<path d="M 103 57 Q 107 61, 111 57" stroke="#7a5010" stroke-width="1.4" stroke-linecap="round" fill="none" opacity="0.65"/>
|
|
<!-- Nose — single gentle hint -->
|
|
<path d="M 100 62 C 99 65, 97 67, 97 68" stroke="#8a6020" stroke-width="1" stroke-linecap="round" fill="none" opacity="0.25"/>
|
|
<!-- Lips — serene half-smile -->
|
|
<path d="M 95 72 Q 100 75, 105 72" stroke="#8a6020" stroke-width="1.2" stroke-linecap="round" fill="none" opacity="0.30"/>
|
|
|
|
<!-- === CROWN CHAKRA: sahasrara point === -->
|
|
<circle cx="100" cy="24" r="3.5" fill="rgba(232,184,109,0.20)"/>
|
|
<circle cx="100" cy="24" r="1.8" fill="#e8b86d" opacity="0.75"/>
|
|
<circle cx="100" cy="24" r="0.8" fill="#fff" opacity="0.60"/>
|
|
|
|
<!-- === SUBTLE INNER LIGHT: warm glow at heart center === -->
|
|
<circle cx="100" cy="110" r="12" fill="rgba(232,184,109,0.04)"/>
|
|
|
|
</svg>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
|
|
<!-- Track Info -->
|
|
<div class="track-info">
|
|
<div class="track-title marquee-host" id="trackTitleHost">
|
|
<div class="marquee-track" id="trackTitleTrack">
|
|
<span class="marquee-copy marquee-copy-primary" id="trackTitle">尚未选择曲目</span>
|
|
<span class="marquee-gap" aria-hidden="true"></span>
|
|
<span class="marquee-copy marquee-copy-duplicate" id="trackTitleDuplicate" aria-hidden="true">尚未选择曲目</span>
|
|
</div>
|
|
</div>
|
|
<div class="track-artist" id="trackArtist">—</div>
|
|
</div>
|
|
|
|
<!-- Bottom Control Bar -->
|
|
<div class="bottom-bar">
|
|
<div class="glass-bar">
|
|
<!-- Progress -->
|
|
<div class="progress-wrap">
|
|
<input type="range" class="progress-bar" id="progressBar" min="0" max="100" value="0"
|
|
oninput="onProgressInput(this.value)" onchange="onProgressChange(this.value)">
|
|
<div class="time-row">
|
|
<span id="timeCurrent">0:00</span>
|
|
<span id="timeTotal">0:00</span>
|
|
</div>
|
|
</div>
|
|
|
|
<!-- Main Controls -->
|
|
<div class="controls">
|
|
<button class="ctrl-btn" id="btnShuffle" onclick="toggleShuffle()" title="随机">
|
|
<svg width="18" height="18" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round">
|
|
<polyline points="16 1 21 3 21 8"></polyline>
|
|
<path d="M4 4 C8 4 10 8 12 12 C14 16 16 20 20 20"></path>
|
|
<polyline points="16 23 21 23 21 18"></polyline>
|
|
<path d="M4 20 C8 20 10 16 12 12 C14 8 16 4 20 4"></path>
|
|
</svg>
|
|
</button>
|
|
<button class="ctrl-btn" onclick="prevTrack()" title="上一首">
|
|
<svg width="22" height="22" viewBox="0 0 24 24" fill="currentColor">
|
|
<path d="M6 6h2v12H6V6zm3.5 6 8.5 6V6l-8.5 6z"></path>
|
|
</svg>
|
|
</button>
|
|
<button class="play-btn" id="playBtn" onclick="togglePlay()" title="播放/暂停">
|
|
<svg id="iconPlay" width="24" height="24" viewBox="0 0 24 24" fill="currentColor">
|
|
<path d="M8 5v14l11-7z"></path>
|
|
</svg>
|
|
<svg id="iconPause" width="24" height="24" viewBox="0 0 24 24" fill="currentColor" style="display:none">
|
|
<path d="M6 19h4V5H6v14zm8-14v14h4V5h-4z"></path>
|
|
</svg>
|
|
</button>
|
|
<button class="ctrl-btn" onclick="nextTrack()" title="下一首">
|
|
<svg width="22" height="22" viewBox="0 0 24 24" fill="currentColor">
|
|
<path d="M16 6h2v12h-2V6zm-10 0v12l8.5-6L6 6z"></path>
|
|
</svg>
|
|
</button>
|
|
<button class="ctrl-btn" id="btnRepeat" onclick="cycleRepeat()" title="循环">
|
|
<svg width="18" height="18" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round">
|
|
<polyline points="17 1 21 5 17 9"></polyline><path d="M3 11V9a4 4 0 0 1 4-4h14"></path>
|
|
<polyline points="7 23 3 19 7 15"></polyline><path d="M21 13v2a4 4 0 0 1-4 4H3"></path>
|
|
</svg>
|
|
</button>
|
|
</div>
|
|
|
|
<!-- Secondary row: playlist toggle + volume -->
|
|
<div class="secondary-controls">
|
|
<button class="sec-btn" onclick="openSheet()" title="播放列表">
|
|
<svg width="18" height="18" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round">
|
|
<line x1="8" y1="6" x2="21" y2="6"></line>
|
|
<line x1="8" y1="12" x2="21" y2="12"></line>
|
|
<line x1="8" y1="18" x2="21" y2="18"></line>
|
|
<line x1="3" y1="6" x2="3.01" y2="6"></line>
|
|
<line x1="3" y1="12" x2="3.01" y2="12"></line>
|
|
<line x1="3" y1="18" x2="3.01" y2="18"></line>
|
|
</svg>
|
|
</button>
|
|
<button class="sec-btn" id="btnVolToggle" onclick="toggleVolume()" title="音量">
|
|
<svg width="18" height="18" viewBox="0 0 24 24" fill="currentColor" id="volIcon">
|
|
<path d="M3 9v6h4l5 5V4L7 9H3zm13.5 3A4.5 4.5 0 0 0 14 7.97v8.05c1.48-.73 2.5-2.25 2.5-4.02z"></path>
|
|
</svg>
|
|
</button>
|
|
<button class="sec-btn" onclick="openSettings()" title="设置">
|
|
<svg width="18" height="18" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round">
|
|
<circle cx="12" cy="12" r="3"></circle>
|
|
<path d="M19.4 15a1.65 1.65 0 0 0 .33 1.82l.06.06a2 2 0 1 1-2.83 2.83l-.06-.06A1.65 1.65 0 0 0 15 19.4a1.65 1.65 0 0 0-1 .6 1.65 1.65 0 0 1-2 0 1.65 1.65 0 0 0-1-.6 1.65 1.65 0 0 0-1.82.33l-.06.06a2 2 0 1 1-2.83-2.83l.06-.06A1.65 1.65 0 0 0 4.6 15a1.65 1.65 0 0 0-.6-1 1.65 1.65 0 0 1 0-2 1.65 1.65 0 0 0 .6-1 1.65 1.65 0 0 0-.33-1.82l-.06-.06a2 2 0 1 1 2.83-2.83l.06.06A1.65 1.65 0 0 0 9 4.6a1.65 1.65 0 0 0 1-.6 1.65 1.65 0 0 1 2 0 1.65 1.65 0 0 0 1 .6 1.65 1.65 0 0 0 1.82-.33l.06-.06a2 2 0 1 1 2.83 2.83l-.06.06A1.65 1.65 0 0 0 19.4 9c0 .38.14.74.4 1a1.65 1.65 0 0 1 0 2c-.26.26-.4.62-.4 1z"></path>
|
|
</svg>
|
|
</button>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
|
|
</div>
|
|
|
|
<!-- Settings Modal -->
|
|
<div class="settings-overlay" id="settingsOverlay" onclick="closeSettings()"></div>
|
|
<div class="settings-panel" id="settingsPanel">
|
|
<div class="settings-header">
|
|
<div class="settings-title">设置</div>
|
|
<button class="sheet-close" onclick="closeSettings()" title="关闭设置">
|
|
<svg width="20" height="20" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round">
|
|
<line x1="18" y1="6" x2="6" y2="18"></line><line x1="6" y1="6" x2="18" y2="18"></line>
|
|
</svg>
|
|
</button>
|
|
</div>
|
|
<div class="settings-body">
|
|
<div class="setting-group">
|
|
<div class="setting-label">当前歌单</div>
|
|
<select id="playlistSelect" class="setting-select"></select>
|
|
<div class="setting-note">自动读取当前目录下所有以 playlist.json 结尾的歌单文件,并记住你上次选择。</div>
|
|
</div>
|
|
<div class="setting-group">
|
|
<div class="setting-label">缓存对照</div>
|
|
<div class="setting-summary" id="cacheSummary">正在检查缓存...</div>
|
|
<div class="setting-note">按歌曲地址对照当前歌单与浏览器缓存,标记哪些已缓存、哪些未缓存。</div>
|
|
</div>
|
|
<div class="setting-group">
|
|
<div class="setting-label">播放记忆</div>
|
|
<label class="setting-switch">
|
|
<input type="checkbox" id="resumePlaybackToggle">
|
|
<span>记住上次位置继续听</span>
|
|
</label>
|
|
<div class="setting-note">默认开启。下次打开时,会从上次暂停的位置继续播放当前音频。</div>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
|
|
<!-- Playlist Sheet Overlay -->
|
|
<div class="sheet-overlay" id="sheetOverlay" onclick="closeSheet()"></div>
|
|
<div class="sheet" id="sheet">
|
|
<div class="sheet-handle"></div>
|
|
<div class="sheet-header">
|
|
<div class="sheet-title">播放列表</div>
|
|
<button class="sheet-close" onclick="closeSheet()">
|
|
<svg width="20" height="20" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round">
|
|
<line x1="18" y1="6" x2="6" y2="18"></line><line x1="6" y1="6" x2="18" y2="18"></line>
|
|
</svg>
|
|
</button>
|
|
</div>
|
|
<div class="sheet-list" id="sheetList">
|
|
<div class="empty-state" id="emptyState">
|
|
暂无曲目<br>
|
|
<span style="font-size:12px;opacity:0.6">请将音乐文件添加至播放列表</span>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
|
|
<!-- Toast -->
|
|
<div class="toast" id="toast"></div>
|
|
|
|
<!-- Hidden Audio -->
|
|
<audio id="audio" preload="metadata"></audio>
|
|
|
|
<script src="zen_box.js"></script>
|
|
</body>
|
|
</html>
|