From e807d65f18e004f20ea1714b042e573fb477598c Mon Sep 17 00:00:00 2001 From: birdstudy-nj Date: Fri, 27 Mar 2026 12:09:45 +0800 Subject: [PATCH] =?UTF-8?q?feat:=20=E6=96=B0=E5=A2=9EMusicFree=E6=8F=92?= =?UTF-8?q?=E4=BB=B6=20(#809)?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- xiaomusic/static/iwebplayer/iwebplayer.html | 3859 ++++++++++++++----- 1 file changed, 2949 insertions(+), 910 deletions(-) diff --git a/xiaomusic/static/iwebplayer/iwebplayer.html b/xiaomusic/static/iwebplayer/iwebplayer.html index 239e4ff..dd2767c 100644 --- a/xiaomusic/static/iwebplayer/iwebplayer.html +++ b/xiaomusic/static/iwebplayer/iwebplayer.html @@ -28,7 +28,11 @@ --border: #374151; } } - * { box-sizing: border-box; margin: 0; padding: 0; } + * { + box-sizing: border-box; + margin: 0; + padding: 0; + } body { font-family: -apple-system, BlinkMacSystemFont, "Segoe UI", Roboto, Helvetica, Arial, sans-serif; background-color: var(--bg-color); @@ -43,84 +47,191 @@ 2. 顶栏、Logo 与 设备选项 ========================================== */ .header { - position: sticky; top: 0; + position: sticky; + top: 0; background-color: var(--bg-color); - padding: 0 16px; height: 56px; + padding: 0 16px; + height: 56px; z-index: 150; - display: flex; justify-content: space-between; align-items: center; - transform: translate3d(0,0,0); -webkit-transform: translate3d(0,0,0); + display: flex; + justify-content: space-between; + align-items: center; + transform: translate3d(0,0,0); + -webkit-transform: translate3d(0,0,0); } - @media (prefers-color-scheme: dark) { .header { } } .header-logo-group { - display: flex; align-items: center; gap: 8px; + display: flex; + align-items: center; + gap: 8px; flex: 0 1 auto; - overflow: hidden; margin-right: 15px; + overflow: hidden; + margin-right: 15px; + } + .header-icon { + width: 28px; + height: 28px; + flex-shrink: 0; + } + .header-title-stack { + display: flex; + flex-direction: column; + justify-content: center; + overflow: hidden; + } + .title-main { + font-size: 15px; + font-weight: bold; + line-height: 1.2; + white-space: nowrap; + text-overflow: ellipsis; + overflow: hidden; + } + .title-sub { + font-size: 11px; + color: var(--text-sub); + line-height: 1.2; + white-space: nowrap; + text-overflow: ellipsis; + overflow: hidden; } - .header-icon { width: 28px; height: 28px; flex-shrink: 0; } - .header-title-stack { display: flex; flex-direction: column; justify-content: center; overflow: hidden; } - .title-main { font-size: 15px; font-weight: bold; line-height: 1.2; white-space: nowrap; text-overflow: ellipsis; overflow: hidden; } - .title-sub { font-size: 11px; color: var(--text-sub); line-height: 1.2; white-space: nowrap; text-overflow: ellipsis; overflow: hidden; } .header-controls { - display: flex; gap: 8px; flex: 1; align-items: center; justify-content: flex-end; + display: flex; + gap: 8px; + flex: 1; + align-items: center; + justify-content: flex-end; min-width: 0; } - /* 下拉菜单基类 */ - .custom-select { position: relative; display: flex; align-items: center; height: 36px; min-width: 0; } + .custom-select { + position: relative; + display: flex; + align-items: center; + height: 36px; + min-width: 0; + } .select-value { - height: 36px; box-sizing: border-box; line-height: 20px; - padding: 7px 24px 7px 12px; border-radius: 8px; border: 1px solid var(--border); + height: 36px; + box-sizing: border-box; + line-height: 20px; + padding: 7px 24px 7px 12px; + border-radius: 8px; + border: 1px solid var(--border); background: var(--card-bg) url("data:image/svg+xml;charset=UTF-8,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 24 24' fill='none' stroke='%236b7280' stroke-width='2' stroke-linecap='round' stroke-linejoin='round'%3E%3Cpolyline points='6 9 12 15 18 9'%3E%3C/polyline%3E%3C/svg%3E") no-repeat right 6px center / 12px; - color: var(--text-main); font-size: 15px; cursor: pointer; max-width: 100%; - white-space: nowrap; overflow: hidden; text-overflow: ellipsis; user-select: none; + color: var(--text-main); + font-size: 15px; + cursor: pointer; + max-width: 100%; + white-space: nowrap; + overflow: hidden; + text-overflow: ellipsis; + user-select: none; } .settings-btn { - display: flex; justify-content: center; align-items: center; width: 28px; height: 28px; - border-radius: 50%; color: var(--text-sub); cursor: pointer; transition: background 0.2s, color 0.2s; + display: flex; + justify-content: center; + align-items: center; + width: 28px; + height: 28px; + border-radius: 50%; + color: var(--text-sub); + cursor: pointer; + transition: background 0.2s, color 0.2s; margin-right: -4px; } - .settings-btn:active { background: var(--border); color: var(--text-main); } + .settings-btn:active { + background: var(--border); + color: var(--text-main); + } .select-options { - display: none; position: absolute; top: 100%; right: 0; margin-top: 6px; - background: var(--card-bg); border: 1px solid var(--border); border-radius: 8px; - box-shadow: 0 4px 15px rgba(0,0,0,0.1); list-style: none; max-height: 50vh; overflow-y: auto; - z-index: 200; min-width: 80px; -webkit-overflow-scrolling: touch; + display: none; + position: absolute; + top: 100%; + right: 0; + margin-top: 6px; + background: var(--card-bg); + border: 1px solid var(--border); + border-radius: 8px; + box-shadow: 0 4px 15px rgba(0,0,0,0.1); + list-style: none; + max-height: 50vh; + overflow-y: auto; + z-index: 200; + min-width: 80px; + -webkit-overflow-scrolling: touch; overscroll-behavior: contain; } - .select-options.show { display: block; animation: fadeIn 0.2s ease-out; } - @keyframes fadeIn { from { opacity: 0; transform: translateY(-5px); } to { opacity: 1; transform: translateY(0); } } - .select-option { - padding: 10px 15px; font-size: 15px; border-bottom: 1px solid var(--bg-color); - cursor: pointer; white-space: nowrap; display: flex; align-items: center; + .select-options.show { + display: block; + animation: fadeIn 0.2s ease-out; + } + @keyframes fadeIn { + from { opacity: 0; transform: translateY(-5px); } + to { opacity: 1; transform: translateY(0); } + } + .select-option { + padding: 10px 15px; + font-size: 15px; + border-bottom: 1px solid var(--bg-color); + cursor: pointer; + white-space: nowrap; + display: flex; + align-items: center; + } + .select-option:last-child { + border-bottom: none; + } + .select-option.active { + color: var(--primary); + font-weight: bold; + background: var(--bg-color); } - .select-option:last-child { border-bottom: none; } - .select-option.active { color: var(--primary); font-weight: bold; background: var(--bg-color); } - /* 设备与音轨状态指示 */ - .playing-eq { display: inline-flex; align-items: flex-end; height: 12px; gap: 2px; margin-right: 6px; vertical-align: middle; } - .eq-bar { width: 3px; background-color: var(--primary); animation: eq-bounce 0.8s infinite ease-in-out alternate; border-radius: 1px; } + .playing-eq { + display: inline-flex; + align-items: flex-end; + height: 12px; + gap: 2px; + margin-right: 6px; + vertical-align: middle; + } + .eq-bar { + width: 3px; + background-color: var(--primary); + animation: eq-bounce 0.8s infinite ease-in-out alternate; + border-radius: 1px; + } .eq-bar:nth-child(1) { height: 40%; animation-delay: 0.1s; } .eq-bar:nth-child(2) { height: 100%; animation-delay: 0.3s; } .eq-bar:nth-child(3) { height: 70%; animation-delay: 0.5s; } - @keyframes eq-bounce { 0% { height: 30%; } 100% { height: 100%; } } - .device-offline { color: #9ca3af !important; } + @keyframes eq-bounce { + 0% { height: 30%; } + 100% { height: 100%; } + } + .device-offline { + color: #9ca3af !important; + } /* ========================================== 3. 歌单独立行与搜索栏 ========================================== */ .playlist-row { - position: sticky; top: 56px; z-index: 85; + position: sticky; + top: 56px; + z-index: 85; background: rgba(243, 244, 246, 0.7); - backdrop-filter: blur(20px); -webkit-backdrop-filter: blur(20px); + backdrop-filter: blur(20px); + -webkit-backdrop-filter: blur(20px); box-shadow: 0 12px 28px rgba(0, 0, 0, 0.1), 0 4px 12px rgba(0, 0, 0, 0.05); border-bottom: 1px solid rgba(0, 0, 0, 0.05); - display: flex; align-items: center; - padding: 1px 16px 10px 16px; gap: 10px; - transform: translate3d(0,0,0); -webkit-transform: translate3d(0,0,0); + display: flex; + align-items: center; + padding: 1px 16px 10px 16px; + gap: 10px; + transform: translate3d(0,0,0); + -webkit-transform: translate3d(0,0,0); } - - /* 深色模式的高级毛玻璃与悬浮阴影 */ @media (prefers-color-scheme: dark) { .playlist-row { background: rgba(17, 24, 39, 0.65); @@ -129,46 +240,90 @@ } } - /* 行内:精巧的回收站删除图标 */ .inline-delete-btn { - background: #fee2e2; color: #ef4444; border: none; border-radius: 8px; flex-shrink: 0; - width: 30px; height: 30px; display: none; align-items: center; justify-content: center; - cursor: pointer; transition: background 0.2s; + background: #fee2e2; + color: #ef4444; + border: none; + border-radius: 8px; + flex-shrink: 0; + width: 30px; + height: 30px; + display: none; + align-items: center; + justify-content: center; + cursor: pointer; + transition: background 0.2s; + } + @media (prefers-color-scheme: dark) { + .inline-delete-btn { background: rgba(239, 68, 68, 0.2); } + } + .inline-delete-btn:active { + opacity: 0.8; + } + .inline-delete-btn.show { + display: flex; + animation: fadeIn 0.2s; } - @media (prefers-color-scheme: dark) { .inline-delete-btn { background: rgba(239, 68, 68, 0.2); } } - .inline-delete-btn:active { opacity: 0.8; } - .inline-delete-btn.show { display: flex; animation: fadeIn 0.2s; } - /* 搜索栏:行内紧凑布局 (统一高度、透明背景、加大间距) */ - .playlist-container-search { flex: 0 0 auto !important; max-width: 110px; } + .playlist-container-search { flex: 0 0 auto !important; max-width: 160px; } .search-inline-wrap { - display: none; flex: 1; align-items: center; background: var(--card-bg); - border: 1px solid var(--border); border-radius: 8px; - padding: 0 8px; gap: 6px; - height: 36px; box-sizing: border-box; - min-width: 0; animation: fadeIn 0.2s; + display: none; + flex: 1; + align-items: center; + background: var(--card-bg); + border: 1px solid var(--border); + border-radius: 8px; + padding: 0 8px; + gap: 6px; + height: 36px; + box-sizing: border-box; + min-width: 0; + animation: fadeIn 0.2s; } .search-inline-wrap.show { display: flex; } .search-inline-wrap input { - flex: 1; border: none; background: transparent; padding: 0; font-size: 14px; - color: var(--text-main); outline: none; min-width: 0; height: 100%; + flex: 1; + border: none; + background: transparent; + padding: 0; + font-size: 14px; + color: var(--text-main); + outline: none; + min-width: 0; + height: 100%; } - .search-actions { display: flex; gap: 14px; align-items: center; margin-right: 2px; } - - /* X与保存按钮 */ + .search-actions { + display: flex; + gap: 14px; + align-items: center; + margin-right: 2px; + } .search-icon-btn { background: transparent; - border: none; color: var(--text-sub); - border-radius: 6px; width: 26px; height: 26px; display: none; - align-items: center; justify-content: center; cursor: pointer; flex-shrink: 0; + border: none; + color: var(--text-sub); + border-radius: 6px; + width: 26px; + height: 26px; + display: none; + align-items: center; + justify-content: center; + cursor: pointer; + flex-shrink: 0; transition: background 0.2s, opacity 0.2s; } .search-icon-btn.show { display: flex; } - .search-icon-btn:active { background: var(--border); opacity: 0.8; transform: scale(0.95); } - .search-icon-btn#search-save { color: var(--primary); background: rgba(236, 72, 153, 0.1); } + .search-icon-btn:active { + background: var(--border); + opacity: 0.8; + transform: scale(0.95); + } + .search-icon-btn#search-save { + color: var(--primary); + background: rgba(236, 72, 153, 0.1); + } - /* 弹窗锚点转移 */ #playlist-container { position: static !important; } #playlist-opts { top: 40px !important; @@ -179,159 +334,451 @@ } /* ========================================== - 4. 播放列表 (Playlist) + 4. 播放列表 ========================================== */ - .playlist { list-style: none; padding: 10px; max-width: 800px; margin: 0 auto; background-color: #e5e7eb; min-height: 100vh; } + .playlist { + list-style: none; + padding: 10px; + max-width: 800px; + margin: 0 auto; + background-color: #e5e7eb; + min-height: 100vh; + } .song-item { - background: var(--card-bg); margin-bottom: 10px; padding: 15px; border-radius: 12px; - display: flex; align-items: center; box-shadow: 0 2px 5px rgba(0,0,0,0.05); cursor: pointer; transition: transform 0.1s; - user-select: none; -webkit-user-select: none; -webkit-touch-callout: none; + background: var(--card-bg); + margin-bottom: 10px; + padding: 15px; + border-radius: 12px; + display: flex; + align-items: center; + box-shadow: 0 2px 5px rgba(0,0,0,0.05); + cursor: pointer; + transition: transform 0.1s; + user-select: none; + -webkit-user-select: none; + -webkit-touch-callout: none; } .song-item:active { transform: scale(0.98); } .song-item.playing { border: 2px solid var(--primary); } .song-info { flex: 1; overflow: hidden; } - .song-name { font-size: 16px; font-weight: 500; white-space: nowrap; text-overflow: ellipsis; overflow: hidden; } + .song-name { + font-size: 16px; + font-weight: 500; + white-space: nowrap; + text-overflow: ellipsis; + overflow: hidden; + } .song-fav-icon { margin-left: 10px; display: flex; align-items: center; } .song-delete-icon { - margin-left: 10px; display: flex; align-items: center; color: var(--text-sub); - padding: 4px; border-radius: 50%; transition: background 0.2s, color 0.2s; + margin-left: 10px; + display: flex; + align-items: center; + color: var(--text-sub); + padding: 4px; + border-radius: 50%; + transition: background 0.2s, color 0.2s; } .song-delete-icon:active { background: var(--border); color: var(--primary); } #loading { - text-align: center; padding: 20px; color: var(--text-sub); - background-color: #e5e7eb; min-height: 100vh; + text-align: center; + padding: 20px; + color: var(--text-sub); + background-color: #e5e7eb; + min-height: 100vh; } @media (prefers-color-scheme: dark) { #loading, .playlist { background-color: #000000; } } /* ========================================== - 5. 底部播放栏与进度条 (Player Bar) + 5. 底部播放栏与进度条 ========================================== */ .player-bar { - position: fixed; bottom: 0; left: 0; width: 100%; + position: fixed; + bottom: 0; + left: 0; + width: 100%; height: calc(var(--player-height) + env(safe-area-inset-bottom)); - background: var(--card-bg); border-top: 1px solid var(--border); - display: flex; flex-direction: column; align-items: center; - padding: 0 15px env(safe-area-inset-bottom) 15px; box-shadow: 0 -4px 15px rgba(0,0,0,0.05); z-index: 100; - transform: translateZ(0); -webkit-transform: translateZ(0); + background: var(--card-bg); + border-top: 1px solid var(--border); + display: flex; + flex-direction: column; + align-items: center; + padding: 0 15px env(safe-area-inset-bottom) 15px; + box-shadow: 0 -4px 15px rgba(0,0,0,0.05); + z-index: 100; + transform: translateZ(0); + -webkit-transform: translateZ(0); } .progress-container { - position: absolute; top: -15px; left: 16px; width: calc(100% - 32px); height: 30px; - cursor: pointer; display: flex; align-items: center; justify-content: center; z-index: 101; + position: absolute; + top: -15px; + left: 16px; + width: calc(100% - 32px); + height: 30px; + cursor: pointer; + display: flex; + align-items: center; + justify-content: center; + z-index: 101; + } + .progress-bg { + width: 100%; + height: 4px; + background: var(--border); + position: relative; + border-radius: 4px; + } + .progress-bar { + height: 100%; + background: var(--primary); + width: 0%; + position: absolute; + top: 0; + left: 0; + border-radius: 4px; } - .progress-bg { width: 100%; height: 4px; background: var(--border); position: relative; border-radius: 4px; } - .progress-bar { height: 100%; background: var(--primary); width: 0%; position: absolute; top: 0; left: 0; border-radius: 4px; } .progress-thumb { - position: absolute; right: -7px; top: 50%; transform: translateY(-50%); width: 14px; height: 14px; - border-radius: 50%; background: #ffffff; border: 3px solid var(--primary); box-shadow: 0 1px 4px rgba(0,0,0,0.2); + position: absolute; + right: -7px; + top: 50%; + transform: translateY(-50%); + width: 14px; + height: 14px; + border-radius: 50%; + background: #ffffff; + border: 3px solid var(--primary); + box-shadow: 0 1px 4px rgba(0,0,0,0.2); } .progress-container.remote-mode { cursor: not-allowed; } .progress-container.remote-mode .progress-bg { background: rgba(156, 163, 175, 0.25); } - .progress-container.remote-mode .progress-bar { background: var(--text-sub); opacity: 0.8; transition: width 0.3s linear; } + .progress-container.remote-mode .progress-bar { + background: var(--text-sub); + opacity: 0.8; + transition: width 0.3s linear; + } .progress-container.remote-mode .progress-thumb { display: none; } - .player-container { max-width: 800px; width: 100%; height: 100%; display: flex; flex-direction: column; justify-content: space-evenly; } + .player-container { + max-width: 800px; + width: 100%; + height: 100%; + display: flex; + flex-direction: column; + justify-content: space-evenly; + } .time-row { width: 100%; display: flex; justify-content: space-between; } - .time-current, .time-duration { font-size: 11px; color: var(--text-sub); opacity: 0.8; font-variant-numeric: tabular-nums; } + .time-current, .time-duration { + font-size: 11px; + color: var(--text-sub); + opacity: 0.8; + font-variant-numeric: tabular-nums; + } - .now-playing-info { display: flex; align-items: center; width: 100%; cursor: pointer; padding: 0 10px; position: relative; box-sizing: border-box; justify-content: center; } - .up-arrow { width: 40px; display: flex; justify-content: center; color: var(--text-sub); animation: bounce 2s infinite; } + .now-playing-info { + display: flex; + align-items: center; + width: 100%; + cursor: pointer; + padding: 0 10px; + position: relative; + box-sizing: border-box; + justify-content: center; + } + .up-arrow { + width: 40px; + display: flex; + justify-content: center; + color: var(--text-sub); + animation: bounce 2s infinite; + } .up-arrow svg { transition: transform 0.3s ease; } body.player-open .up-arrow { animation: none; } body.player-open .up-arrow svg { transform: rotate(180deg); } - @keyframes bounce { 0%, 20%, 50%, 80%, 100% {transform: translateY(0);} 40% {transform: translateY(-5px);} 60% {transform: translateY(-3px);} } - .np-text-group { flex: 0 1 auto; display: flex; flex-direction: column; align-items: center; justify-content: center; overflow: hidden; } - .now-playing-title { font-size: 19px; font-weight: bold; white-space: nowrap; text-overflow: ellipsis; overflow: hidden; width: 100%; text-align: center;} - - .controls { display: flex; justify-content: space-between; align-items: center; width: 100%; padding: 0 10px; box-sizing: border-box; } - .btn { background: none; border: none; color: var(--text-main); font-size: 20px; cursor: pointer; width: 40px; height: 40px; display: flex; align-items: center; justify-content: center; border-radius: 50%; transition: opacity 0.2s; } - .btn.play-btn { background: var(--primary); color: white; width: 46px; height: 46px; } - - /* 推送按钮被禁用时的变灰状态样式 */ - .btn.play-btn.disabled-push { background: var(--border) !important; color: var(--text-sub) !important; cursor: not-allowed; } + @keyframes bounce { + 0%, 20%, 50%, 80%, 100% {transform: translateY(0);} + 40% {transform: translateY(-5px);} + 60% {transform: translateY(-3px);} + } + .np-text-group { + flex: 0 1 auto; + display: flex; + flex-direction: column; + align-items: center; + justify-content: center; + overflow: hidden; + } + .now-playing-title { + font-size: 19px; + font-weight: bold; + white-space: nowrap; + text-overflow: ellipsis; + overflow: hidden; + width: 100%; + text-align: center; + } + .controls { + display: flex; + justify-content: space-between; + align-items: center; + width: 100%; + padding: 0 10px; + box-sizing: border-box; + } + .btn { + background: none; + border: none; + color: var(--text-main); + font-size: 20px; + cursor: pointer; + width: 40px; + height: 40px; + display: flex; + align-items: center; + justify-content: center; + border-radius: 50%; + transition: opacity 0.2s; + } + .btn.play-btn { + background: var(--primary); + color: white; + width: 46px; + height: 46px; + } + .btn.play-btn.disabled-push { + background: var(--border) !important; + color: var(--text-sub) !important; + cursor: not-allowed; + } .btn.mode-btn, .btn.vol-btn { opacity: 0.8; } .btn:active { opacity: 0.5; } - /* 音量弹窗 */ .volume-wrapper { position: relative; } .volume-popup { - position: absolute; bottom: 55px; left: 50%; transform: translateX(-50%); background: var(--card-bg); - border: 1px solid var(--border); border-radius: 16px; padding: 12px 0 16px 0; box-shadow: 0 4px 20px rgba(0,0,0,0.15); - display: none; flex-direction: column; justify-content: center; align-items: center; z-index: 110; - width: 54px; height: 160px; touch-action: none; + position: absolute; + bottom: 55px; + left: 50%; + transform: translateX(-50%); + background: var(--card-bg); + border: 1px solid var(--border); + border-radius: 16px; + padding: 12px 0 16px 0; + box-shadow: 0 4px 20px rgba(0,0,0,0.15); + display: none; + flex-direction: column; + justify-content: center; + align-items: center; + z-index: 110; + width: 54px; + height: 160px; + touch-action: none; } .volume-popup.show { display: flex; } - .volume-text { font-size: 12px; font-weight: bold; color: var(--primary); margin-bottom: 8px; font-variant-numeric: tabular-nums; } - .volume-popup input[type=range] { -webkit-appearance: slider-vertical; appearance: slider-vertical; width: 28px; height: 100px; background: transparent; outline: none; margin: 0; cursor: pointer; } + .volume-text { + font-size: 12px; + font-weight: bold; + color: var(--primary); + margin-bottom: 8px; + font-variant-numeric: tabular-nums; + } + .volume-popup input[type=range] { + -webkit-appearance: slider-vertical; + appearance: slider-vertical; + width: 28px; + height: 100px; + background: transparent; + outline: none; + margin: 0; + cursor: pointer; + } /* ========================================== - 6. 抽屉层封面与歌词 (Full Player Drawer) + 6. 全屏抽屉 (Cover & Lyrics) ========================================== */ .full-player { - position: fixed; left: 0; width: 100%; height: 65vh; + position: fixed; + left: 0; + width: 100%; + height: 65vh; bottom: calc(var(--player-height) + env(safe-area-inset-bottom)); - background: var(--card-bg); border-radius: 24px 24px 0 0; - box-shadow: 0 -10px 30px rgba(0, 0, 0, 0.12), 0 -2px 10px rgba(0, 0, 0, 0.05); z-index: 90; - transform: translateY(110%); transition: transform 0.4s cubic-bezier(0.25, 0.8, 0.25, 1); - display: flex; flex-direction: column; align-items: center; + background: var(--card-bg); + border-radius: 24px 24px 0 0; + box-shadow: 0 -10px 30px rgba(0, 0, 0, 0.12), 0 -2px 10px rgba(0, 0, 0, 0.05); + z-index: 90; + transform: translateY(110%); + transition: transform 0.4s cubic-bezier(0.25, 0.8, 0.25, 1); + display: flex; + flex-direction: column; + align-items: center; + } + @media (prefers-color-scheme: dark) { + .full-player { background: #1a2234; border-top: 1px solid var(--border); } } - @media (prefers-color-scheme: dark) { .full-player { background: #1a2234; border-top: 1px solid var(--border); } } .full-player.open { transform: translateY(0); } - .drawer-handle { width: 100%; height: 30px; display: flex; justify-content: center; align-items: center; cursor: pointer; padding-top: 5px; } - .handle-bar { width: 60px; height: 5px; background: var(--text-sub); border-radius: 3px; opacity: 0.4; } + .drawer-handle { + width: 100%; + height: 30px; + display: flex; + justify-content: center; + align-items: center; + cursor: pointer; + padding-top: 5px; + } + .handle-bar { + width: 60px; + height: 5px; + background: var(--text-sub); + border-radius: 3px; + opacity: 0.4; + } - .fp-cover-wrapper { flex: 1; display: flex; justify-content: center; align-items: center; min-height: 200px; padding-top: 10px;} + .fp-cover-wrapper { + flex: 1; + display: flex; + justify-content: center; + align-items: center; + min-height: 200px; + padding-top: 10px; + } .fp-cover { - width: clamp(200px, 60vw, 300px); height: clamp(200px, 60vw, 300px); border-radius: 20px; object-fit: cover; - box-shadow: 0 8px 24px rgba(0,0,0,0.2); border: 1px solid #222; animation: cover-breath 6s ease-in-out infinite; + width: clamp(200px, 60vw, 300px); + height: clamp(200px, 60vw, 300px); + border-radius: 20px; + object-fit: cover; + box-shadow: 0 8px 24px rgba(0,0,0,0.2); + border: 1px solid #222; + animation: cover-breath 6s ease-in-out infinite; } @media (max-height: 700px) { .full-player { height: 60vh; } .fp-cover { width: clamp(120px, 30vh, 180px); height: clamp(120px, 30vh, 180px); } } - @keyframes cover-breath { 0% { transform: scale(1); } 50% { transform: scale(1.05); } 100% { transform: scale(1); } } + @keyframes cover-breath { + 0% { transform: scale(1); } + 50% { transform: scale(1.05); } + 100% { transform: scale(1); } + } - .mini-cover { width:35px; height:35px; border-radius:50%; overflow:hidden; flex:0 0 35px; border:1px solid var(--border); box-shadow:0 1px 3px rgba(0,0,0,0.08); margin-right: 10px; } - .mini-cover img { width:100%; height:100%; object-fit:cover; border-radius:50%; animation: rotate-cover 10s linear infinite; animation-play-state: paused; will-change: transform; } + .mini-cover { + width: 35px; + height: 35px; + border-radius: 50%; + overflow: hidden; + flex: 0 0 35px; + border: 1px solid var(--border); + box-shadow: 0 1px 3px rgba(0,0,0,0.08); + margin-right: 10px; + } + .mini-cover img { + width: 100%; + height: 100%; + object-fit: cover; + border-radius: 50%; + animation: rotate-cover 10s linear infinite; + animation-play-state: paused; + will-change: transform; + } .mini-cover.spinning img { animation-play-state: running; } @keyframes rotate-cover { 100% { transform: rotate(360deg); } } .fp-lyrics-wrapper { - height: 28vh; width: 100%; max-width: 600px; overflow: hidden; position: relative; margin-bottom: 10px; + height: 28vh; + width: 100%; + max-width: 600px; + overflow: hidden; + position: relative; + margin-bottom: 10px; mask-image: linear-gradient(to bottom, transparent 0%, black 20%, black 80%, transparent 100%); - -webkit-mask-image: linear-gradient(to bottom, transparent 0%, black 20%, black 80%, transparent 100%); touch-action: none; + -webkit-mask-image: linear-gradient(to bottom, transparent 0%, black 20%, black 80%, transparent 100%); + touch-action: none; + } + .fp-lyrics-container { + position: absolute; + width: 100%; + text-align: center; + transition: transform 0.3s ease-out; + touch-action: none; + } + .lyric-line { + padding: 6px 20px; + color: var(--text-sub); + font-size: 14px; + transition: color 0.3s, font-size 0.3s, font-weight 0.3s; + min-height: 32px; + } + .lyric-line.active { + color: var(--primary); + font-size: 17px; + font-weight: bold; + } + .no-lyrics { + color: var(--text-sub); + text-align: center; + margin-top: 40px; + font-size: 14px; } - .fp-lyrics-container { position: absolute; width: 100%; text-align: center; transition: transform 0.3s ease-out; touch-action: none; } - .lyric-line { padding: 6px 20px; color: var(--text-sub); font-size: 14px; transition: color 0.3s, font-size 0.3s, font-weight 0.3s; min-height: 32px; } - .lyric-line.active { color: var(--primary); font-size: 17px; font-weight: bold; } - .no-lyrics { color: var(--text-sub); text-align: center; margin-top: 40px; font-size: 14px; } /* ========================================== 7. 模态框与轻提示 (Modals & Toast) ========================================== */ .about-modal-backdrop { - position: fixed; inset: 0; background: rgba(0,0,0,0.35); z-index: 300; display: none; - align-items: center; justify-content: center; padding: 20px; - -webkit-backdrop-filter: blur(2px); backdrop-filter: blur(2px); + position: fixed; + inset: 0; + background: rgba(0,0,0,0.35); + z-index: 300; + display: none; + align-items: center; + justify-content: center; + padding: 20px; + -webkit-backdrop-filter: blur(2px); + backdrop-filter: blur(2px); } .about-modal-backdrop.show { display: flex; animation: about-fade-in 0.15s ease-out; } @keyframes about-fade-in { from { opacity: 0 } to { opacity: 1 } } .about-modal { - width: min(520px, 92vw); background: var(--card-bg); color: var(--text-main); - border: 1px solid var(--border); border-radius: 16px; box-shadow: 0 12px 30px rgba(0,0,0,0.15); - position: relative; overflow: hidden; transform: translateY(6px); animation: about-slide-up 0.18s ease-out; + width: min(520px, 92vw); + background: var(--card-bg); + color: var(--text-main); + border: 1px solid var(--border); + border-radius: 16px; + box-shadow: 0 12px 30px rgba(0,0,0,0.15); + position: relative; + overflow: hidden; + transform: translateY(6px); + animation: about-slide-up 0.18s ease-out; + } + @keyframes about-slide-up { + from { transform: translateY(16px); opacity: 0.8; } + to { transform: translateY(0); opacity: 1; } } - @keyframes about-slide-up { from { transform: translateY(16px); opacity: 0.8; } to { transform: translateY(0); opacity: 1; } } .about-close { - position: absolute; top: 10px; right: 10px; width: 32px; height: 32px; border-radius: 50%; - border: none; background: transparent; color: var(--text-sub); font-size: 20px; cursor: pointer; + position: absolute; + top: 10px; + right: 10px; + width: 32px; + height: 32px; + border-radius: 50%; + border: none; + background: transparent; + color: var(--text-sub); + font-size: 20px; + cursor: pointer; } .about-close:active { background: var(--border); color: var(--text-main); } .about-header { display: flex; gap: 12px; align-items: center; padding: 18px 18px 0 18px; } - .about-logo { width: 42px; height: 42px; border-radius: 10px; overflow: hidden; border: 1px solid var(--border); background: var(--bg-color); display: grid; place-items: center; flex: 0 0 auto; } + .about-logo { + width: 42px; + height: 42px; + border-radius: 10px; + overflow: hidden; + border: 1px solid var(--border); + background: var(--bg-color); + display: grid; + place-items: center; + flex: 0 0 auto; + } .about-logo img { width: 100%; height: 100%; object-fit: cover; } .about-title-wrap { min-width: 0; } .about-title-wrap h2 { font-size: 18px; line-height: 1.2; margin: 0; font-weight: 800; white-space: nowrap; overflow: hidden; text-overflow: ellipsis; } @@ -343,51 +790,105 @@ .about-features li { margin: 4px 0; color: var(--text-sub); } .about-link { padding: 8px 10px; background: var(--bg-color); border: 1px dashed var(--border); border-radius: 10px; overflow-wrap: anywhere; font-size: 13px; } .about-link a { color: var(--primary); text-decoration: none; font-weight: 500; transition: opacity 0.2s; } - .about-link a:active { opacity: 0.7; } .about-footer { padding: 12px 18px 18px 18px; display: flex; justify-content: flex-end; gap: 8px; } .about-primary { background: var(--primary); color: #fff; border: none; border-radius: 10px; padding: 10px 16px; font-size: 14px; cursor: pointer; } .about-primary:active { opacity: 0.8; } - /* 自定义弹窗:组合输入框样式 */ .modal-input-group { - display: flex; align-items: center; background: var(--bg-color); - border: 1px solid var(--border); border-radius: 10px; margin-top: 12px; - transition: border-color 0.2s; overflow: hidden; + display: flex; + align-items: center; + background: var(--bg-color); + border: 1px solid var(--border); + border-radius: 10px; + margin-top: 12px; + transition: border-color 0.2s; + overflow: hidden; } .modal-input-group:focus-within { border-color: var(--primary); } .modal-input-group input { - flex: 1; border: none; background: transparent; padding: 12px 14px 12px 8px; - font-size: 15px; color: var(--text-main); outline: none; + flex: 1; + border: none; + background: transparent; + padding: 12px 14px 12px 8px; + font-size: 15px; + color: var(--text-main); + outline: none; } .about-secondary { - background: transparent; color: var(--text-main); border: 1px solid var(--border); - border-radius: 10px; padding: 10px 16px; font-size: 14px; cursor: pointer; transition: background 0.2s; + background: transparent; + color: var(--text-main); + border: 1px solid var(--border); + border-radius: 10px; + padding: 10px 16px; + font-size: 14px; + cursor: pointer; + transition: background 0.2s; } .about-secondary:active { background: var(--bg-color); } - .about-danger { - background: #ef4444; color: #fff; border: none; border-radius: 10px; - padding: 10px 16px; font-size: 14px; cursor: pointer; transition: opacity 0.2s; - } + .about-danger { background: #ef4444; color: #fff; border: none; border-radius: 10px; padding: 10px 16px; font-size: 14px; cursor: pointer; transition: opacity 0.2s; } .about-danger:active { opacity: 0.8; } .toast-message { - position: fixed; bottom: calc(var(--player-height) + env(safe-area-inset-bottom) + 80px); - left: 50%; transform: translateX(-50%); background: rgba(0, 0, 0, 0.7); color: #fff; - padding: 10px 20px; border-radius: 20px; font-size: 14px; z-index: 1000; opacity: 0; - pointer-events: none; transition: opacity 0.3s ease-in-out; - backdrop-filter: blur(5px); -webkit-backdrop-filter: blur(5px); white-space: nowrap; + position: fixed; + bottom: calc(var(--player-height) + env(safe-area-inset-bottom) + 80px); + left: 50%; + transform: translateX(-50%); + background: rgba(0, 0, 0, 0.7); + color: #fff; + padding: 10px 20px; + border-radius: 20px; + font-size: 14px; + z-index: 1000; + opacity: 0; + pointer-events: none; + transition: opacity 0.3s ease-in-out; + backdrop-filter: blur(5px); + -webkit-backdrop-filter: blur(5px); + white-space: nowrap; } .toast-message.show { opacity: 1; } /* ========================================== - 8. 宽屏适配 / 电脑端居中 + 8. 插件管理弹窗样式 + ========================================== */ + .mf-plugin-item { + display: flex; + align-items: center; + justify-content: space-between; + padding: 12px; + background: var(--bg-color); + border: 1px solid var(--border); + border-radius: 10px; + gap: 10px; + flex-wrap: wrap; + margin-bottom: 10px; + } + .mf-plugin-info { display: flex; flex-direction: row; align-items: center; gap: 8px; flex: 1; min-width: 0; } + .mf-plugin-name { font-size: 15px; font-weight: 600; color: var(--text-main); white-space: nowrap; overflow: hidden; text-overflow: ellipsis; } + .mf-plugin-status { font-size: 11px; padding: 2px 8px; border-radius: 12px; font-weight: 600; display: inline-block; white-space: nowrap; } + .mf-plugin-status.enabled { background: rgba(0, 123, 255, 0.1); color: #007bff; } + .mf-plugin-status.disabled { background: rgba(239, 68, 68, 0.1); color: #ef4444; } + .mf-plugin-actions { display: flex; gap: 6px; } + .mf-btn-sm { padding: 6px 12px; font-size: 12px; border-radius: 6px; cursor: pointer; transition: opacity 0.2s; } + .mf-btn-sm:active { opacity: 0.7; } + .mf-btn-blue { background: #007bff; color: #fff; border: none; } + .mf-btn-red { background: #ef4444; color: #fff; border: none; } + .mf-btn-grey { background: #6b7280; color: #fff; border: none; } + @keyframes spin-hourglass { 100% { transform: rotate(180deg); } } + + /* ========================================== + 9. 宽屏适配 ========================================== */ @media (min-width: 600px) { html { background-color: #e5e7eb; overflow-y: scroll; scrollbar-gutter: stable; } @media (prefers-color-scheme: dark) { html { background-color: #050505; } } body { - width: 480px !important; margin: 0 auto !important; min-height: 100vh; - box-shadow: 0 0 60px rgba(0,0,0,0.15); border-left: 1px solid var(--border); border-right: 1px solid var(--border); + width: 480px !important; + margin: 0 auto !important; + min-height: 100vh; + box-shadow: 0 0 60px rgba(0,0,0,0.15); + border-left: 1px solid var(--border); + border-right: 1px solid var(--border); overflow-x: visible; } .player-bar, .full-player { width: 480px !important; left: 50% !important; margin-left: -240px !important; } @@ -397,70 +898,106 @@ #fp-lyrics-wrapper, #fp-lyrics-container, .lyric-line, .now-playing-title, .header, .playlist, .player-bar, .full-player { -webkit-user-select: none; -moz-user-select: none; user-select: none; } #fp-cover { -webkit-user-drag: none; user-drag: none; -webkit-user-select: none; user-select: none; pointer-events: auto; } } -
-
- -
-
iWebPlayer
-
XiaoMusic播放器
-
-
-
-
-
本机
-
    -
    +
    -
      +
      • - 刷新歌单 + 刷新曲库
      • 编辑歌单
      • +
      • + 插件管理 +
      • +
      • + 歌曲下载 +
      • - 配置参数 + 后台配置
      • 版本
    -
    -
    -
    -
    -
    加载中
    -
      -
      - -
      - - -
      - - +
      + +
      +
      iWebPlayer
      +
      XiaoMusic播放器
      +
      - +
      +
      +
      本机
      +
        +
        +
        +
        + +
        + +
        +
        + +
        +
        加载中
        +
          +
          + +
          +
          + +
          + + +
          +
          + +
          +
          +
          +
          MusicFree
          +
            +
          • MusicFree
          • +
          • LXServer
          • +
          +
          +
          +
          +
          所有插件
          +
            +
            +
            + +
            + + +
            + +
            + +
            + + +
            +
            正在加载音乐...
            @@ -471,7 +1008,7 @@
            - cover + ...
            @@ -496,7 +1033,7 @@
            -
            +
            @@ -513,22 +1050,18 @@ - - - -
            -

            自定义歌单 功能正在开发中。

            +

            自定义歌单 功能正在开发中。

            确定要删除该歌单吗?

            -

            仅删除歌单分类,里面的歌曲文件不会被删除。

            +

            仅删除歌单分类,歌曲文件不会被删除。

            -