diff --git a/TestAudio/EN - Bad Love/audio.flac b/TestAudio/EN - Bad Love/audio.flac deleted file mode 100644 index d01de89..0000000 Binary files a/TestAudio/EN - Bad Love/audio.flac and /dev/null differ diff --git a/TestAudio/EN - Bad Love/cover.jpg b/TestAudio/EN - Bad Love/cover.jpg deleted file mode 100644 index 6176451..0000000 Binary files a/TestAudio/EN - Bad Love/cover.jpg and /dev/null differ diff --git a/TestAudio/EN - Bad Love/lyrics.lrc b/TestAudio/EN - Bad Love/lyrics.lrc deleted file mode 100644 index 9325911..0000000 --- a/TestAudio/EN - Bad Love/lyrics.lrc +++ /dev/null @@ -1,44 +0,0 @@ -[id: tgtbfasl] -[ar: Eric Clapton] -[al: Journeyman] -[ti: Bad Love] -[length: 05:09] -[00:56.35]Oh, what a feeling I get when I'm with you -[01:03.92]You take my heart into everything you do -[01:11.06]And it makes me sad for the lonely people -[01:15.70]I walked that road for so long -[01:18.99]Now I know that I'm one of the lucky people -[01:23.55]Your love is making me strong -[01:26.78]I've had enough of bad love -[01:30.49]I need something I can be proud of -[01:34.15]I've had enough of bad love -[01:39.24]No more bad love -[01:43.43] -[01:57.84]And now I see that my life has been so blue -[02:05.74]With all the heartaches I had 'till I met you -[02:12.74]But I'm glad to say now that's all behind me -[02:17.48]With you here by my side -[02:20.64]And there's no more memories to remind me -[02:25.11]Your love will keep me alive -[02:28.18]I've had enough of bad love -[02:32.12]I need something I can be proud of -[02:35.62]I've had enough bad love -[02:40.65]No more bad love -[02:43.89] -[04:04.06]I've had enough of bad love -[04:08.17]I need something I can be proud of -[04:11.89]I've had enough of bad love -[04:16.58]No more bad love -[04:19.52]Had enough of bad love -[04:23.32]I need something I can be proud of -[04:27.28]I've had enough of bad love -[04:32.18]No more bad love -[04:34.80]I've had enough -[04:35.94] -[04:42.51]I've had enough -[04:47.07]No more bad love -[04:49.93]Had enough -[04:51.40] -[04:57.66]I've had enough -[05:02.22]No more bad love -[05:04.85] \ No newline at end of file diff --git a/TestAudio/JP - Wine Red No Kokoro/audio.flac b/TestAudio/JP - Wine Red No Kokoro/audio.flac deleted file mode 100644 index c138e76..0000000 Binary files a/TestAudio/JP - Wine Red No Kokoro/audio.flac and /dev/null differ diff --git a/TestAudio/JP - Wine Red No Kokoro/cover.jpg b/TestAudio/JP - Wine Red No Kokoro/cover.jpg deleted file mode 100644 index 49fcf44..0000000 Binary files a/TestAudio/JP - Wine Red No Kokoro/cover.jpg and /dev/null differ diff --git a/TestAudio/JP - Wine Red No Kokoro/lyrics.lrc b/TestAudio/JP - Wine Red No Kokoro/lyrics.lrc deleted file mode 100644 index 4bca00c..0000000 --- a/TestAudio/JP - Wine Red No Kokoro/lyrics.lrc +++ /dev/null @@ -1,25 +0,0 @@ -[00:18.50]もっと勝手に恋したり -[00:24.06]もっとKissを楽しんだり -[00:32.06]忘れそうな想い出を -[00:38.62]そっと抱いているより -[00:44.43]忘れてしまえば -[00:49.20] -[00:50.87]今以上 それ以上 愛されるのに -[00:58.66]あなたは その透き通った瞳のままで -[01:05.79]あの消えそうに燃えそうなワインレッドの -[01:13.80]心を持つあなたの願いがかなうのに -[01:40.89]もっと何度も抱き合ったり -[01:47.58]ずーっと今夜をゆれ合ったり -[01:54.73]哀しそうな言葉に -[02:01.13]酔って泣いているより -[02:07.17]ワインをあけたら -[02:12.12] -[02:13.52]今以上 それ以上 愛されるのに -[02:20.71]あなたはただ恥らうより てだてがなくて -[02:28.36]あの消えそうに燃えそうなワインレッドの -[02:37.11]心をまだもてあましているのさ この夜も -[02:46.91] -[03:02.19]今以上 それ以上 愛されるまで -[03:08.46]あなたのその透き通った瞳の中に -[03:17.04]あの消えそうに燃えそうなワインレッドの -[03:25.35]心を写しだしてみせてよ ゆれながら diff --git a/TestAudio/README.md b/TestAudio/README.md deleted file mode 100644 index f632c1f..0000000 --- a/TestAudio/README.md +++ /dev/null @@ -1,26 +0,0 @@ -# 关于本目录 / About This Directory - -## 介绍 / Introduction -本目录中存储一些测试曲目,每个包含歌词、封面、音频。文件仅用于测试程序,未经原作者许可禁止转载商用! - -The directory stores a number of testing tracks, each with an audio, a lyrics file and an image of cover art. The files are only provided for testing. DO NOT redistribute without permission of original author. - -### 使用方法 / How to Use - -1. 下载文件到本地。 -2. 点击专辑封面,在文件选择窗口进入文件目录,**同时选中目录下的三个文件**,然后确认。 - -1. Download the files to local storage -2. Click on the cover art on the webpage, enter file directory in the file selection window. Then **select the three files under the directory at the same time**, and hit confirm (or anything similar). - -## 版权相关 / Copyrights -`/TestAudio/`目录下文件版权归原作者所有,仅供测试使用,未经原作者允许不得转载商用。 - -Files under `/TestAudio/` are only for testing, and their copyrights are owned by their original author(s). Therefore please DO NOT reference / modify / redistribute those files without the permission of the original author. - -## 政治和道德相关 / About Politics and Ethics -`/TestAudio/` 下的内容均来自网络或其他作者,仅供测试程序,不代表程序本体作者和贡献者观点。 - -File under `/TestAudio/` are from third-party sources, which are only provided for testing the program and DOES NOT represent the author's / contributors' views. - -~~牢罗啊牢罗 歌词别再玩脱了啊 不然真的很麻烦啊 (Lo! I would be very thankful if u can write your lyrics properly next time!)~~ \ No newline at end of file diff --git a/TestAudio/SC - Hong Qing Ting/audio.flac b/TestAudio/SC - Hong Qing Ting/audio.flac deleted file mode 100644 index 1b0d03c..0000000 Binary files a/TestAudio/SC - Hong Qing Ting/audio.flac and /dev/null differ diff --git a/TestAudio/SC - Hong Qing Ting/cover.jpg b/TestAudio/SC - Hong Qing Ting/cover.jpg deleted file mode 100644 index b09eec6..0000000 Binary files a/TestAudio/SC - Hong Qing Ting/cover.jpg and /dev/null differ diff --git a/TestAudio/SC - Hong Qing Ting/lyrics.lrc b/TestAudio/SC - Hong Qing Ting/lyrics.lrc deleted file mode 100644 index cb28e8c..0000000 --- a/TestAudio/SC - Hong Qing Ting/lyrics.lrc +++ /dev/null @@ -1,57 +0,0 @@ -[00:00.74]小虎队 - 红蜻蜓 -[00:02.92]作词:李子恒 -[00:04.80]作曲:长渕刚 -[00:33.50]飞呀飞呀 -[00:34.45]看那红色蜻蜓飞在蓝色天空 -[00:37.55]游戏在风中不断追逐他的梦 -[00:41.76]天空是永恒的家 -[00:43.74]大地就是他的王国 -[00:45.97]飞翔是生活 -[00:50.08]我们的童年也像追逐 -[00:52.67]成长吹来的风 -[00:54.45]轻轻地吹着梦想 -[00:56.33]慢慢地升空 -[00:58.56]红色的蜻蜓是我 -[01:00.44]小时候的小小英雄 -[01:02.68]多希望有一天能和他一起飞 -[01:07.04]当烦恼越来越多 -[01:08.87]玻璃弹珠越来越少 -[01:11.05]我知道我已慢慢地长大了 -[01:15.57]红色的蜻蜓曾几何时 -[01:18.05]也在我岁月慢慢不见了 -[01:23.85]我们都已经长大 -[01:27.86]好多梦正在飞 -[01:32.19]就像童年看到地红色的蜻蜓 -[01:40.71]我们都已经长大 -[01:44.58]好多梦还要飞 -[01:49.05]就像现在心目中红色的蜻蜓 -[02:09.86]飞呀飞呀 -[02:10.82]看那红色蜻蜓飞在蓝色天空 -[02:13.97]游戏在风中不断追逐他的梦 -[02:18.08]天空是永恒的家 -[02:19.96]大地就是他的王国 -[02:22.29]飞翔是生活 -[02:26.51]我们的童年也像追逐 -[02:28.91]成长吹来的风 -[02:30.74]轻轻地吹着梦想 -[02:32.62]慢慢地升空 -[02:35.00]红色的蜻蜓是我 -[02:36.78]小时候的小小英雄 -[02:38.96]多希望有一天能和他一起飞 -[02:43.53]当烦恼越来越多 -[02:45.41]玻璃弹珠越来越少 -[02:47.49]我知道我已慢慢地长大了 -[02:51.71]红色的蜻蜓曾几何时 -[02:54.24]也在我岁月慢慢不见了 -[03:00.29]我们都已经长大 -[03:04.25]好多梦正在飞 -[03:08.37]就像童年看到地红色的蜻蜓 -[03:17.05]我们都已经长大 -[03:21.06]好多梦还要飞 -[03:25.17]就像现在心目中红色的蜻蜓 -[03:33.90]我们都已经长大 -[03:37.76]好多梦正在飞 -[03:41.87]就像童年看到地红色的蜻蜓 -[03:50.56]我们都已经长大 -[03:54.56]好多梦还要飞 -[03:58.67]就像现在心目中红色的蜻蜓 diff --git a/TestAudio/TC - Fei Che/audio.flac b/TestAudio/TC - Fei Che/audio.flac deleted file mode 100644 index e3fc5a9..0000000 Binary files a/TestAudio/TC - Fei Che/audio.flac and /dev/null differ diff --git a/TestAudio/TC - Fei Che/cover.jpg b/TestAudio/TC - Fei Che/cover.jpg deleted file mode 100644 index f70b8ff..0000000 Binary files a/TestAudio/TC - Fei Che/cover.jpg and /dev/null differ diff --git a/TestAudio/TC - Fei Che/lyrics.lrc b/TestAudio/TC - Fei Che/lyrics.lrc deleted file mode 100644 index 4319833..0000000 --- a/TestAudio/TC - Fei Che/lyrics.lrc +++ /dev/null @@ -1,51 +0,0 @@ -[00:00.00]作詞:林夕 -[00:10.00]作曲:羅大佑 -[00:16.00]飛車飛車 在高速公路 -[00:20.00]追車過車 絕不管燈號 -[00:24.00]飛車飛車 是思想速度 -[00:28.00]要到未到 引擎也憤怒 -[00:32.00]警車警車 在追趕拘捕 -[00:36.00]千噸貨車 直通海關路 -[00:40.00]火車火車 共識的軌道 -[00:44.00]各有各去 各自上旅途 -[00:48.00]單車單車 異鄉的溫柔 -[00:52.00]坦克戰車 歴史的荒謬 -[00:56.00]偷車偷車 像江水東流 -[01:00.00]去去去去 再沒法轉頭 -[01:04.00]跑車跑車 刺激的感受 -[01:08.00]鹿車馬車 怎麼可忍受 -[01:12.00]房車房車 是資產派頭 -[01:16.00]進進退退 看時勢氣候 -[01:19.00]前後前後兜兜轉轉左左右右分清界限 -[01:23.00]何日何地不必刹摯衝出勝利關 -[01:27.00]紅綠紅綠燈色百變崎嶇舊路車速太慢 -[01:31.00]離合離合推推送送只恐沒時間 -[01:35.00]前後前後兜兜轉轉左左右右警惕界限 -[01:39.00]何日何地不必告票飛車過大關 -[01:43.00]紅綠紅綠燈色百變修改道路車速太慢 -[01:47.00]時代時代跑得太快趕不及時間 -[01:51.00]飛車飛車 在高速公路 -[01:54.00]追車過車 絕不管燈號 -[01:59.00]飛車飛車 是思想速度 -[02:03.00]要到未到 引擎也憤怒 -[02:06.00]警車警車 在追趕拘捕 -[02:10.00]千噸貨車 直通海關路 -[02:14.00]火車火車 共識的軌道 -[02:19.00]各有各去 各自上旅途 -[02:22.00]前後前後兜兜轉轉左左右右分清界限 -[02:26.00]何日何地不必刹摯衝出革命灣 -[02:30.00]紅綠紅綠燈色百變崎嶇舊路車速太慢 -[02:34.00]離合離合推推送送只恐沒時間 -[02:38.00]前後前後兜兜轉轉左左右右警惕界限 -[02:42.00]何日何地不必告票飛車過大關 -[02:46.00]紅綠紅綠燈色百變修改道路車速太慢 -[02:50.00]時代時代跑得太快趕不及時間 -[03:02.00]柴灣 北角 銅鑼灣 灣仔 中環 金鐘 尖沙咀 油麻地 旺角 太子 九龍塘 沙田 上水 羅湖 深圳 廣州 廈門 台北 福州 南京 上海 北京 中環 -[03:25.00]前後前後兜兜轉轉左左右右分清界限 -[03:29.00]何日何地不必刹摯衝出鑽石山 -[03:33.00]紅綠紅綠燈色百變崎嶇舊路車速太慢 -[03:37.00]離合離合推推送送只恐沒時間 -[03:41.00]前後前後兜兜轉轉左左右右警惕界限 -[03:45.00]何日何地不必告票飛車過大關 -[03:49.00]紅綠紅綠燈色百變修改道路車速太慢 -[03:53.00]時代時代跑得太快趕不及時間 \ No newline at end of file diff --git a/TestAudio/TestAudioList.json b/TestAudio/TestAudioList.json deleted file mode 100644 index 446b5cc..0000000 --- a/TestAudio/TestAudioList.json +++ /dev/null @@ -1,4 +0,0 @@ -{"Bad Love": "EN - Bad Love", - "ワインレッドの心": "JP - Wine Red No Kokoro", - "红蜻蜓": "SC - Hong Qing Ting", - "飛車": "TC - Fei Che"} \ No newline at end of file diff --git a/index.css b/index.css index f95d49b..97ca52e 100644 --- a/index.css +++ b/index.css @@ -41,11 +41,8 @@ body { flex-direction: row; align-items: center; justify-content: center; - /* -webkit-backdrop-filter: blur(20px); - backdrop-filter: blur(20px); */ z-index: 2; margin: 0; - /* background: #e8e8e8; */ } .main { @@ -61,7 +58,6 @@ body { flex-direction: column; align-items: center; justify-content: center; - width: 50vw; height: 100vh; } @@ -124,7 +120,6 @@ input[type="file"] { height: 100%; background: #fff; border-radius: 100px; - /* box-shadow: 0 0 3px #0009; */ } .time { @@ -229,35 +224,23 @@ body:not(.no-files) .leftcontent { black 35%, black 65%, transparent); - /* background-image: linear-gradient(to bottom, - transparent, - black 35%, - black 65%, - transparent); */ -webkit-mask-repeat: no-repeat; mask-repeat: no-repeat; } .lyrics { max-width: 100%; - /* font-size: 24px; */ - /* line-height: 40px; */ z-index: 2; } .lyrics>.item { position: absolute; padding: 25px; - box-sizing: border-box; - background-color: transparent; border-radius: 15px; color: rgba(255, 255, 255, 0.2); line-height: 250%; - - /*transition-timing-function: cubic-bezier(.19,.11,0,1); - transition: transform 0.5s;*/ } .lyrics>.item>p { @@ -267,68 +250,6 @@ body:not(.no-files) .leftcontent { letter-spacing: 0.6px; } -/* -.lyrics p { - position: relative; - margin: 0; - margin: 4% 0; - will-change: opacity, font-weight, margin-left, margin-top, margin-bottom, transform; - transition: opacity 0.75s cubic-bezier(0.25, 0.8, 0.25, 1), - - font-weight 0.75s cubic-bezier(0.25, 0.8, 0.25, 1), - margin-left 0.75s cubic-bezier(0.25, 0.8, 0.25, 1), - margin-top 0.6s cubic-bezier(.01,1.22,.97,1.12), - margin-bottom 1s cubic-bezier(0.25, 0.8, 0.25, 1), - transform 0.75s cubic-bezier(0.25, 0.8, 0.25, 1); - width: 100%; - font-weight: normal; - font-size: inherit; - margin-top: 4%; - font-size: 36px; - text-shadow: -1px 1px 20px #0009, 0 1px 5px #0009; - align-self: flex-start; - transform: matrix(1, 0, 0, 1, 0, 0); - transform-origin: 0px 50%; - word-wrap: break-word; - white-space: normal; - color: #fff; - opacity: 0.3; - -webkit-background-clip: text; - background-clip: text; - z-index: 2; -} - -.lyrics p.highlight { - margin: 5% 0; - font-weight: bold; - filter: none; - margin-top: 4%; - opacity: 0.9; - transform: matrix(1.2, 0, 0, 1.2, 0, 0); - background-size: 100% 100%, 100% 100%; - transform-origin: 0px 50%; - word-wrap: break-word; - white-space: normal; - font-family: "SFPro-Semibold", "PingFangSC-Semibold"; -} -*/ -/* .lyrics p::after { - content: attr(data-text); - position: absolute; - top: 0; - left: 0; - width: 100%; - height: 100%; - z-index: 3; - color: #fff; - clip-path: polygon(0 0, 0 0, 0 100%, 0 100%); - transition: clip-path var(--type-time) linear; -} - -.lyrics p.highlight::after { - clip-path: polygon(0 0, 100% 0, 100% 100%, 0 100%); -} */ - .background { margin: 0; position: fixed; @@ -442,4 +363,114 @@ body:not(.no-files) .leftcontent { filter: blur(30px) saturate(2.5) brightness(0.6); pointer-events: none; background-color: #000; +} + +/* 搜索框样式,能看就行 */ +#search_container { + position: fixed; + top: 20px; + right: 20px; + z-index: 1000; + font-family: inherit; +} + +#search_trigger { + width: 40px; + height: 40px; + background: rgba(255, 255, 255, 0.15); + backdrop-filter: blur(10px); + border-radius: 50%; + display: flex; + align-items: center; + justify-content: center; + font-size: 20px; + color: white; + cursor: pointer; + box-shadow: 0 4px 12px rgba(0, 0, 0, 0.3); + transition: 0.2s; + border: 1px solid rgba(255, 255, 255, 0.2); +} + +#search_trigger:hover { + background: rgba(255, 255, 255, 0.25); + transform: scale(1.05); +} + +#search_dropdown { + position: absolute; + top: 50px; + right: 0; + width: 260px; + max-height: 360px; + background: rgba(30, 30, 30, 0.85); + backdrop-filter: blur(20px); + border-radius: 12px; + border: 1px solid rgba(255, 255, 255, 0.15); + box-shadow: 0 8px 20px rgba(0, 0, 0, 0.5); + overflow: hidden; + display: flex; + flex-direction: column; + transition: opacity 0.2s, transform 0.2s; +} + +#search_dropdown.hidden { + opacity: 0; + transform: translateY(-10px); + pointer-events: none; +} + +#search_input { + width: 100%; + padding: 12px 15px; + background: transparent; + border: none; + color: white; + font-size: 14px; + outline: none; + border-bottom: 1px solid rgba(255, 255, 255, 0.15); + box-sizing: border-box; +} + +#search_input::placeholder { + color: rgba(255, 255, 255, 0.5); +} + +#search_results { + overflow-y: auto; + max-height: 280px; + padding: 6px 0; +} + +.search-result-item { + padding: 10px 15px; + color: white; + cursor: pointer; + transition: background 0.2s; + border-bottom: 1px solid rgba(255, 255, 255, 0.05); + display: flex; + flex-direction: column; +} + +.search-result-item:hover { + background: rgba(255, 255, 255, 0.1); +} + +.search-result-item .song-name { + font-weight: 500; + font-size: 14px; + margin-bottom: 2px; +} + +.search-result-item .artist-name { + font-size: 12px; + color: rgba(255, 255, 255, 0.6); +} + +.search-loading, +.search-error, +.search-no-result { + padding: 15px; + text-align: center; + color: rgba(255, 255, 255, 0.5); + font-size: 13px; } \ No newline at end of file diff --git a/index.html b/index.html index 33abdb8..28b77a5 100644 --- a/index.html +++ b/index.html @@ -9,6 +9,15 @@ + +
+
+ +
+
diff --git a/index.js b/index.js index b0f44a5..1d55f65 100644 --- a/index.js +++ b/index.js @@ -25,26 +25,7 @@ const LINE_HEIGHT = 20; const LYRICS_OFFSET = window.innerHeight / 3.5; let lastLyric = -1 -/* -function mainDivScalePosition(width, height) { - // width: 1280, height: 720 (Image loaded) - // width: 325, height: 437 (Image unloaded) - const scaleX = mainDiv.clientWidth / width; - const scaleY = mainDiv.clientHeight / height; - const scale = Math.max(scaleX, scaleY); - - mainDiv.style.transform = `scale(${scale})`; - mainDiv.style.top = `calc(50% - ${mainDiv.clientHeight / 2}px)`; - mainDiv.style.left = `calc(50% - ${mainDiv.clientWidth / 2}px)`; - - rightContent.style.paddingLeft = `${10 / scaleX}%`; -} -window.addEventListener("resize", () => { - mainDivScalePosition(width, height); -}); -mainDivScalePosition(width, height); -*/ let bgImg = new Image(); bgImg.src = "./default.svg"; @@ -63,36 +44,15 @@ let audioLoaded = false; let lrcLoaded = false; svgcontainer.addEventListener("click", async () => { - // const filePaths = await window.electron.openDialog(); - // if (filePaths && filePaths.length > 0) { - // // 处理选中的文件 - // for (const filePath of filePaths) { - // const file = new File([await fetch(filePath).then(r => r.blob())], filePath.split('/').pop()); - // const event = { target: { files: [file] } }; - // audioFileInput.dispatchEvent(new CustomEvent('change', { detail: event })); - // } - // } audioFileInput.click(); }); audioPlayer.addEventListener("loadedmetadata", () => { endTime.textContent = `-${formatTime(audioPlayer.duration)}`; - // if (imageLoaded && audioLoaded && lrcLoaded) { - // setTimeout(() => { - // playBtn.click(); - // }, 100); - // } else if (!lrcLoaded && imageLoaded && audioLoaded) { - // window.dispatchEvent(new Event("resize")); - // setTimeout(() => { - // playBtn.click(); - // }, 100); - // } if (audioLoaded) { if (!lrcLoaded) { width = 325; height = 437; - // window.dispatchEvent(new Event("resize")); - // mainDiv.style.marginLeft = "0"; } playBtn.click(); } else { @@ -223,7 +183,6 @@ audioPlayer.addEventListener("timeupdate", () => { process.style.width = `${(audioPlayer.currentTime / audioPlayer.duration) * 100}%`; startTime.textContent = formatTime(audioPlayer.currentTime); endTime.textContent = `-${formatTime(audioPlayer.duration - audioPlayer.currentTime)}`; - // 歌词触发计算 const cTime = audioPlayer.currentTime; let lList = []; @@ -328,124 +287,16 @@ function parseLrc(lrcText) { } }); - //mainDivScalePosition(width, height); - return { lyrics: lrcArray, allTimes: allTimes }; } -/* -function updateLyrics() { - if (!playing) return; - - const currentTime = audioPlayer.currentTime; - const lyricLines = lyricsElement.querySelectorAll('*'); - if (called) { - lyricsElement.style.transition = "all 1s cubic-bezier(0.25, 0.8, 0.25, 1)"; - } else { - centerActiveLine(lyricLines[0]); - } - let activeIndex = -1; - - for (let i = 0; i < lyrics.length; i++) { - if (currentTime >= lyrics[i].time) { - activeIndex = i; - } else { - break; - } - } - - lyricLines.forEach((line, index) => { - const distance = Math.abs(activeIndex - index); - const thisTime = allTimes[activeIndex]; - - if (distance > 8) { - line.style.visibility = "hidden"; - return; - } - - if (index === activeIndex) { - applyActiveLineStyle(line, index, lyricLines, thisTime); - } else { - applyNearbyLineStyle(line, distance); - } - }); - - if (activeIndex >= 0) { - requestAnimationFrame(() => { - setTimeout(() => { - centerActiveLine(lyricLines[activeIndex]); - }, 120); - }); - } - - requestAnimationFrame(updateLyrics); -} - -function applyActiveLineStyle(line, index, allLines, thisTime) { - void line.offsetWidth; - setTimeout(() => { - line.classList.add("highlight"); - line.style.filter = "none"; - line.style.marginLeft = "0"; - line.style.visibility = "visible"; - line.style.opacity = "0.6"; - line.style.setProperty("--type-time", `${thisTime / 2}s`); - }, 300); - - if (!processedLines.has(index)) { - processedLines.add(index); - - const start = Math.max(0, index - 3); - const end = Math.min(allLines.length - 1, index + 3); - const displayingLines = Array.from(allLines).slice(start, end + 1); - - displayingLines.forEach((nline, i) => { - setTimeout(() => { - nline.style.marginTop = `${line.clientHeight}px`; - - setTimeout(() => { - nline.style.marginTop = "4%"; - }, 250); - }, i * 75); - }); - } -} - -function applyNearbyLineStyle(line, distance) { - void line.offsetWidth; - line.classList.remove("highlight"); - line.style.filter = `blur(${distance * 0.5}px)`; - line.style.marginLeft = `${distance * 1.25}px`; - line.style.opacity = `${0.3 - distance / 100}`; - line.style.visibility = "visible"; -} - -function centerActiveLine(activeLine) { - if (!activeLine) return; - if (!called) called = true; - const container = document.querySelector(".lyricscontainer"); - const containerHeight = container.clientHeight; - const activeLineOffset = activeLine.offsetTop; - const offset = (containerHeight / 2) - activeLineOffset - (0.1 * containerHeight); - - lyricsElement.style.transform = `translateY(${offset}px)`; -} -*/ audioPlayer.addEventListener('play', () => { //requestAnimationFrame(updateLyrics); }); -/* -window.addEventListener('resize', () => { - lyricsElement.classList.add("noTransition"); - updateLyrics(); - lyricsElement.classList.remove("noTransition"); -}); -updateLyrics(); -*/ function getDominantColors(imageData, colorCount = 4, minColorDistance = 60) { const pixels = imageData.data; const { width, height } = imageData; @@ -589,7 +440,7 @@ bgImg.onload = () => { animate(); }; -// 新增的函数 + // 动态计算布局的函数 function GetLyricsLayout(now, to, data) { @@ -631,3 +482,210 @@ function UpdateLyricsLayout(index, data, init = 1) { }, (n * 70 - n * 10) * init); } } + +// 搜索框功能 +const searchContainer = document.getElementById('search_container'); +const searchTrigger = document.getElementById('search_trigger'); +const searchDropdown = document.getElementById('search_dropdown'); +const searchInput = document.getElementById('search_input'); +const searchResults = document.getElementById('search_results'); + +let searchKeyword = ''; +let searchResultList = []; + +// 点击触发器切换显示 +searchTrigger.addEventListener('click', (e) => { + e.stopPropagation(); + searchDropdown.classList.toggle('hidden'); +}); + +// 点击其他区域关闭 +document.addEventListener('click', (e) => { + if (!searchContainer.contains(e.target)) { + searchDropdown.classList.add('hidden'); + } +}); + + +searchDropdown.addEventListener('click', (e) => { + e.stopPropagation(); +}); + +// ESC 键关闭 +document.addEventListener('keydown', (e) => { + if (e.key === 'Escape') { + searchDropdown.classList.add('hidden'); + } +}); + +// 输入防抖 +let searchTimer; +searchInput.addEventListener('input', (e) => { + clearTimeout(searchTimer); + const keyword = e.target.value.trim(); + if (keyword === '') { + searchResults.innerHTML = ''; + return; + } + searchTimer = setTimeout(() => { + performSearch(keyword); + }, 400); +}); + +// 执行搜索 +async function performSearch(keyword) { + searchKeyword = keyword; + searchResults.innerHTML = '
搜索中...
'; + try { + const url = `https://oiapi.net/api/Kuwo?msg=${encodeURIComponent(keyword)}&limit=10`; + const res = await fetch(url); + const data = await res.json(); + if (data.code === 1 && data.data && data.data.length > 0) { + searchResultList = data.data; + renderSearchResults(data.data); + } else { + searchResults.innerHTML = '
未找到相关歌曲
'; + } + } catch (err) { + console.error('搜索失败', err); + searchResults.innerHTML = '
搜索出错,请重试
'; + } +} + + +function renderSearchResults(results) { + let html = ''; + results.forEach((item, index) => { + html += ` +
+ ${escapeHtml(item.song)} + ${escapeHtml(item.singer)} +
+ `; + }); + searchResults.innerHTML = html; + + // 点击事件 + document.querySelectorAll('.search-result-item').forEach(el => { + el.addEventListener('click', (e) => { + const index = e.currentTarget.dataset.index; + playSelectedSong(index); + }); + }); +} + +// XSS +function escapeHtml(unsafe) { + return unsafe.replace(/[&<>"]/g, function(m) { + if (m === '&') return '&'; + if (m === '<') return '<'; + if (m === '>') return '>'; + if (m === '"') return '"'; + return m; + }); +} + +// 播放歌曲 +async function playSelectedSong(index) { + const item = searchResultList[index]; + if (!item) return; + + // 加载状态 + audioName.textContent = `加载中...`; + + try { + // 获取歌曲详细 + // 使用原始关键词 + n 参数获取该歌曲的详细信息 + const detailUrl = `https://oiapi.net/api/Kuwo?msg=${encodeURIComponent(searchKeyword)}&n=${Number(index)+1}`; + const detailRes = await fetch(detailUrl); + const detailData = await detailRes.json(); + + // 提取url + let audioUrl = ''; + if (detailData.code === 1) { + if (Array.isArray(detailData.data)) { + audioUrl = detailData.data[0]?.url; + } else if (typeof detailData.data === 'object') { + audioUrl = detailData.data?.url; + } + } + + if (!audioUrl) { + throw new Error('无法获取播放链接'); + } + + + audioPlayer.src = audioUrl; + audioLoaded = true; + + // 更新封面 + if (item.picture && item.picture !== 'https://h5s.kuwo.cn/www/kw-www/img/logo.ce08bf7.png') { + bgImg.src = item.picture; + } else { + // 默认背景 + bgImg.src = './default.svg'; + } + + // 更新歌曲名显示 + let displayName = item.song; + if (item.singer) displayName += ` - ${item.singer}`; + audioName.textContent = displayName.length > 40 ? displayName.substring(0, 40) + '...' : displayName; + + // 获取歌词 + fetchLyricBySongName(item.song, item.singer).then(lyric => { + if (lyric) { + processLrcText(lyric); + } else { + // 无歌词时清空显示 + lyricsElement.innerHTML = ''; + lrcLoaded = false; + disableLyric(); + } + }).catch(() => { + disableLyric(); + }); + + // 自动播放 + setTimeout(() => { + if (audioPlayer.readyState >= 2) { + playBtn.click(); + } + }, 500); + + } catch (err) { + console.error('播放失败', err); + alert('无法加载歌曲,请稍后重试'); + } +} + +// 歌词API,QQ音乐源 +const API_BASE = 'https://api.wuhy.de5.net'; + +async function searchSongmid(keyword) { + const url = `${API_BASE}/getSearchByKey?key=${encodeURIComponent(keyword)}&limit=1`; + const response = await fetch(url); + const data = await response.json(); + const songList = data?.response?.data?.song?.list; + if (songList && songList.length > 0) { + return songList[0].songmid; + } + return null; +} + +async function getLyric(songmid) { + const url = `${API_BASE}/getLyric?songmid=${encodeURIComponent(songmid)}`; + const response = await fetch(url); + const data = await response.json(); + return data?.response?.lyric || ''; +} + +async function fetchLyricBySongName(title, artist) { + const keyword = `${title} ${artist}`; + const songmid = await searchSongmid(keyword); + if (!songmid) { + console.warn('未找到歌词'); + return ''; + } + const lyric = await getLyric(songmid); + return lyric; +} \ No newline at end of file