sa2kit 1.6.2 → 1.6.3
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/audioDetection/index.js.map +1 -1
- package/dist/audioDetection/index.mjs.map +1 -1
- package/dist/{chunk-5XUE72Y3.mjs → chunk-6LEA37ZM.mjs} +2 -2
- package/dist/{chunk-5XUE72Y3.mjs.map → chunk-6LEA37ZM.mjs.map} +1 -1
- package/dist/chunk-EBP7AE6F.js +167 -0
- package/dist/chunk-EBP7AE6F.js.map +1 -0
- package/dist/chunk-MBG4DBGP.mjs +154 -0
- package/dist/chunk-MBG4DBGP.mjs.map +1 -0
- package/dist/{chunk-DQVPZTVC.js → chunk-QKXKXAAV.js} +2 -2
- package/dist/{chunk-DQVPZTVC.js.map → chunk-QKXKXAAV.js.map} +1 -1
- package/dist/imageCrop/index.js.map +1 -1
- package/dist/imageCrop/index.mjs.map +1 -1
- package/dist/index-DtLpANUB.d.mts +70 -0
- package/dist/index-DtLpANUB.d.ts +70 -0
- package/dist/index.js.map +1 -1
- package/dist/index.mjs.map +1 -1
- package/dist/mmd/admin/index.d.mts +1 -1
- package/dist/mmd/admin/index.d.ts +1 -1
- package/dist/mmd/index.d.mts +16 -2
- package/dist/mmd/index.d.ts +16 -2
- package/dist/mmd/index.js +280 -130
- package/dist/mmd/index.js.map +1 -1
- package/dist/mmd/index.mjs +280 -130
- package/dist/mmd/index.mjs.map +1 -1
- package/dist/mmd/server/index.d.mts +1 -1
- package/dist/mmd/server/index.d.ts +1 -1
- package/dist/music/index.d.mts +30 -0
- package/dist/music/index.d.ts +30 -0
- package/dist/music/index.js +458 -0
- package/dist/music/index.js.map +1 -0
- package/dist/music/index.mjs +427 -0
- package/dist/music/index.mjs.map +1 -0
- package/dist/music/server/index.d.mts +1 -0
- package/dist/music/server/index.d.ts +1 -0
- package/dist/music/server/index.js +29 -0
- package/dist/music/server/index.js.map +1 -0
- package/dist/music/server/index.mjs +4 -0
- package/dist/music/server/index.mjs.map +1 -0
- package/dist/testYourself/admin/index.js +3 -3
- package/dist/testYourself/admin/index.mjs +1 -1
- package/dist/testYourself/index.js +7 -7
- package/dist/testYourself/index.js.map +1 -1
- package/dist/testYourself/index.mjs +2 -2
- package/dist/testYourself/index.mjs.map +1 -1
- package/dist/{types-DxYJqqes.d.mts → types-B60F7EZZ.d.mts} +16 -1
- package/dist/{types-DxYJqqes.d.ts → types-B60F7EZZ.d.ts} +16 -1
- package/dist/universalFile/server/index.js +5 -5
- package/dist/universalFile/server/index.mjs +1 -1
- package/package.json +32 -19
- package/tailwind.animations.js +5 -0
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"sources":["../../src/music/adapters/kugou.ts","../../src/music/adapters/netease.ts","../../src/music/adapters/tencent.ts","../../src/music/adapters/xiami.ts","../../src/music/hooks/useMusic.ts","../../src/music/components/MusicPlayer.tsx"],"names":["useState","useSWR","DEFAULT_MUSIC_SOURCE","useMemo","useCallback","useRef","React","Search","MUSIC_SOURCES","MUSIC_SOURCE_NAMES","ListIcon","LayoutGrid","Loader2","MusicIcon","ChevronLeft","ChevronRight","SkipBack","Pause","Play","SkipForward","VolumeX","Volume2"],"mappings":"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","file":"index.js","sourcesContent":["import { SearchResult } from '../types';\nimport { MusicSourceAdapter } from './types';\n\nexport const kugouAdapter: MusicSourceAdapter = {\n parseSearchResult(data: any): SearchResult {\n const root = typeof data === 'string' ? JSON.parse(data) : data;\n const info = root.data?.data?.info || root.data?.info || root.info || [];\n const total = root.data?.data?.total || root.data?.total || info.length;\n return {\n tracks: info.map((item: any) => {\n // 优先从 trans_param.union_cover 提取封面,并替换 {size} 为 400\n let pic = item.pic || '';\n if (item.trans_param?.union_cover) {\n pic = item.trans_param.union_cover.replace('{size}', '400');\n }\n\n return {\n id: item.hash || item.id,\n name: item.songname || item.filename || 'Unknown',\n artist: item.singername || 'Unknown Artist',\n album: item.album_name || item.album || '',\n pic: pic,\n url: item.url,\n lrc: item.lrc,\n source: 'kugou',\n isVip: item.privilege >= 8,\n playable: item.status !== 0,\n };\n }),\n total: total,\n };\n },\n\n parseGetSongUrl(data: any): string | null {\n return data.url?.url || data.url?.backup_url?.[0] || null;\n },\n\n parseGetLyric(data: any): any {\n const root = typeof data === 'string' ? JSON.parse(data) : data;\n return root.lyric || root.lrc || root.data?.lyric || root.data || '';\n }\n};\n","import { SearchResult } from '../types';\nimport { MusicSourceAdapter } from './types';\n\nexport const neteaseAdapter: MusicSourceAdapter = {\n parseSearchResult(data: any): SearchResult {\n const root = typeof data === 'string' ? JSON.parse(data) : data;\n const songs = root.result?.songs || root.songs || (Array.isArray(root) ? root : []);\n \n return {\n tracks: songs.map((item: any) => ({\n id: item.id,\n name: item.name,\n artist: Array.isArray(item.artist) ? item.artist.join(', ') : item.artist,\n album: item.album?.name || item.album,\n pic: item.pic || item.album?.picUrl,\n url: item.url,\n lrc: item.lrc,\n source: 'netease',\n isVip: item.fee === 1 || item.fee === 4,\n playable: item.noCopyrightRcmd === null,\n })),\n total: root.result?.songCount || songs.length,\n };\n },\n\n parseGetSongUrl(data: any): any {\n const root = typeof data === 'string' ? JSON.parse(data) : data;\n const item = root.data?.[0] || root[0] || root;\n return item.url || null;\n },\n\n parseGetLyric(data: any): any {\n const root = typeof data === 'string' ? JSON.parse(data) : data;\n return root.lyric || root.lrc || root.data?.lyric || '';\n }\n};\n\n","import { SearchResult } from '../types';\nimport { MusicSourceAdapter } from './types';\n\nexport const tencentAdapter: MusicSourceAdapter = {\n parseSearchResult(data: any): SearchResult {\n const root = typeof data === 'string' ? JSON.parse(data) : data;\n \n // 兼容多种 QQ 音乐返回结构\n const songData = root.data?.data?.song || root.data?.song || root.data || root;\n const list = songData.list || root.songs || [];\n const total = songData.totalnum || root.total || list.length;\n \n return {\n tracks: list.map((item: any) => {\n // 解析歌手名\n const artist = Array.isArray(item.singer) \n ? item.singer.map((s: any) => s.name).join(', ') \n : (item.singer?.[0]?.name || item.artist || 'Unknown');\n\n // 处理封面图 (QQ 音乐封面通常基于 album mid)\n let pic = item.pic;\n if (!pic && item.album?.mid) {\n pic = `https://y.gtimg.cn/music/photo_new/T002R300x300M000${item.album.mid}.jpg`;\n }\n\n return {\n id: item.mid || item.id || item.songid,\n name: item.name || item.title || item.songname,\n artist: artist,\n album: item.album?.name || item.albumname || item.album,\n pic: pic || '',\n url: item.url,\n lrc: item.lrc,\n source: 'tencent',\n isVip: item.pay?.pay_play === 1,\n playable: item.action?.switch !== 0,\n };\n }),\n total: total,\n };\n },\n\n parseGetSongUrl(data: any): string | null {\n\n const root = data\n\n const urlData = root.url.url;\n let finalUrl = Object.values(urlData)[0] as string;\n console.log('finalUrl2', finalUrl);\n return finalUrl.startsWith('http') ? finalUrl : `http://${finalUrl}`;\n },\n\n parseGetLyric(data: any): any {\n const root = typeof data === 'string' ? JSON.parse(data) : data;\n return root.lyric || root.lrc || root.data?.lyric || '';\n }\n};\n\n","import { SearchResult } from '../types';\nimport { MusicSourceAdapter } from './types';\n\nexport const xiamiAdapter: MusicSourceAdapter = {\n parseSearchResult(data: any): SearchResult {\n const root = typeof data === 'string' ? JSON.parse(data) : data;\n // 虾米返回的结构(根据提供的数据,类似于网易云的结构)\n const result = root.data?.result || root.result || root;\n const songs = result.songs || (Array.isArray(root) ? root : []);\n \n return {\n tracks: songs.map((item: any) => ({\n id: item.id?.toString() || '',\n name: item.name || 'Unknown',\n artist: Array.isArray(item.ar) \n ? item.ar.map((a: any) => a.name).join(', ') \n : (item.artist || 'Unknown Artist'),\n album: item.al?.name || item.album || '',\n pic: item.al?.picUrl || item.pic || '',\n url: item.url,\n lrc: item.lrc,\n source: 'xiami',\n // 这里的逻辑参考提供的数据结构\n isVip: item.fee === 1 || item.fee === 8,\n playable: item.copyright !== 0,\n })),\n total: result.songCount || songs.length,\n };\n },\n\n parseGetSongUrl(data: any): any {\n const root = typeof data === 'string' ? JSON.parse(data) : data;\n // 兼容多种可能的包装结构\n const item = root.data?.[0] || root.data || root[0] || root;\n return item.url || null;\n },\n\n parseGetLyric(data: any): any {\n const root = typeof data === 'string' ? JSON.parse(data) : data;\n return root.lyric || root.lrc || root.data?.lyric || root.data || '';\n }\n};\n\n","import useSWR from 'swr';\nimport { useState, useCallback, useMemo } from 'react';\nimport { MusicTrack, SearchOptions, SearchResult, MusicApiResponse } from '../types';\nimport { DEFAULT_MUSIC_SOURCE } from '../constants';\nimport { \n kugouAdapter, \n neteaseAdapter, \n tencentAdapter, \n xiamiAdapter,\n MusicSourceAdapter \n} from '../adapters';\n\nconst fetcher = (url: string) => fetch(url).then(res => res.json());\n\nconst ADAPTERS: Record<string, MusicSourceAdapter> = {\n kugou: kugouAdapter,\n netease: neteaseAdapter,\n tencent: tencentAdapter,\n xiami: xiamiAdapter,\n};\n\nexport function useMusic() {\n const [searchOptions, setSearchOptions] = useState<SearchOptions | null>(null);\n\n // 搜索歌曲\n const { data: rawData, error: searchError, isLoading: isSearching } = useSWR<MusicApiResponse<any>>(\n searchOptions ? `/api/music/search?keyword=${encodeURIComponent(searchOptions.keyword)}&source=${searchOptions.source || DEFAULT_MUSIC_SOURCE}&limit=${searchOptions.limit || 20}&offset=${searchOptions.offset || 0}` : null,\n fetcher\n );\n\n const searchResult = useMemo(() => {\n if (!rawData?.data || !searchOptions) return undefined;\n const adapter = ADAPTERS[searchOptions.source || DEFAULT_MUSIC_SOURCE];\n if (adapter) {\n return adapter.parseSearchResult(rawData.data);\n }\n return undefined;\n }, [rawData, searchOptions]);\n\n const search = useCallback((options: SearchOptions) => {\n setSearchOptions(options);\n }, []);\n\n // 获取播放链接\n const getSongUrl = useCallback(async (id: string, source: string = DEFAULT_MUSIC_SOURCE): Promise<string | undefined> => {\n try {\n const res = await fetch(`/api/music/url?id=${id}&source=${source}`);\n const json: MusicApiResponse<any> = await res.json();\n const adapter = ADAPTERS[source];\n console.log('json2', json.data,source,adapter);\n if (adapter && json.data) {\n console.log('getSongUrl2', json.data);\n return adapter.parseGetSongUrl(json.data) || undefined;\n }\n return json.data?.url;\n } catch (err) {\n console.error('[Music] Failed to get song URL:', err);\n return undefined;\n }\n }, []);\n\n // 获取歌词\n const getLyric = useCallback(async (id: string, source: string = DEFAULT_MUSIC_SOURCE): Promise<string | undefined> => {\n try {\n const res = await fetch(`/api/music/lyric?id=${id}&source=${source}`);\n const json: MusicApiResponse<any> = await res.json();\n const adapter = ADAPTERS[source];\n if (adapter && json.data) {\n return adapter.parseGetLyric(json.data);\n }\n return json.data?.lyric;\n } catch (err) {\n console.error('[Music] Failed to get lyric:', err);\n return undefined;\n }\n }, []);\n\n return {\n search,\n searchResult,\n isSearching,\n searchError,\n getSongUrl,\n getLyric,\n };\n}\n\n","import React, { useState, useRef, useEffect, useCallback } from 'react';\nimport {\n Play,\n Pause,\n SkipBack,\n SkipForward,\n Search,\n Volume2,\n VolumeX,\n Music as MusicIcon,\n Loader2,\n ChevronLeft,\n ChevronRight,\n LayoutGrid,\n List as ListIcon\n} from 'lucide-react';\nimport { useMusic } from '../hooks/useMusic';\nimport { MusicTrack } from '../types';\nimport { MUSIC_SOURCES, DEFAULT_MUSIC_SOURCE, MusicSource, MUSIC_SOURCE_NAMES } from '../constants';\n\nexport const MusicPlayer: React.FC = () => {\n const { search, searchResult: searchData, isSearching, getSongUrl } = useMusic();\n const [keyword, setKeyword] = useState('');\n const [selectedSource, setSelectedSource] = useState<MusicSource>(DEFAULT_MUSIC_SOURCE);\n const [currentPage, setCurrentPage] = useState(0);\n const [layoutMode, setLayoutMode] = useState<'grid' | 'list'>('grid');\n const pageSize = 20;\n\n const [currentTrack, setCurrentTrack] = useState<MusicTrack | null>(null);\n const [isPlaying, setIsPlaying] = useState(false);\n const [progress, setProgress] = useState(0);\n const [duration, setDuration] = useState(0);\n const [volume, setVolume] = useState(0.7);\n const [isMuted, setIsMuted] = useState(false);\n const [isLoadingUrl, setIsLoadingUrl] = useState(false);\n\n const audioRef = useRef<HTMLAudioElement | null>(null);\n\n const handleSearch = (e: React.FormEvent) => {\n e.preventDefault();\n if (keyword.trim()) {\n setCurrentPage(0);\n search({ keyword, source: selectedSource, offset: 0, limit: pageSize });\n }\n };\n\n const handlePageChange = (newPage: number) => {\n setCurrentPage(newPage);\n search({ keyword, source: selectedSource, offset: newPage, limit: pageSize });\n };\n\n const playTrack = async (track: MusicTrack) => {\n setIsLoadingUrl(true);\n const url = await getSongUrl(track.id, track.source);\n setIsLoadingUrl(false);\n\n if (url) {\n const fullTrack = { ...track, url };\n setCurrentTrack(fullTrack);\n setIsPlaying(true);\n if (audioRef.current) {\n audioRef.current.src = url;\n audioRef.current.play();\n }\n } else {\n alert('无法获取播放链接');\n }\n };\n\n const togglePlay = () => {\n if (!audioRef.current || !currentTrack) return;\n\n if (isPlaying) {\n audioRef.current.pause();\n } else {\n audioRef.current.play();\n }\n setIsPlaying(!isPlaying);\n };\n\n const handleTimeUpdate = () => {\n if (audioRef.current) {\n setProgress(audioRef.current.currentTime);\n setDuration(audioRef.current.duration);\n }\n };\n\n const handleSeek = (e: React.ChangeEvent<HTMLInputElement>) => {\n const time = parseFloat(e.target.value);\n setProgress(time);\n if (audioRef.current) {\n audioRef.current.currentTime = time;\n }\n };\n\n const formatTime = (time: number) => {\n if (isNaN(time)) return '00:00';\n const mins = Math.floor(time / 60);\n const secs = Math.floor(time % 60);\n return `${mins.toString().padStart(2, '0')}:${secs.toString().padStart(2, '0')}`;\n };\n\n return (\n <div className=\"flex flex-col h-full bg-black text-white font-sans\">\n {/* 搜索栏 */}\n <div className=\"p-6 border-b border-gray-800 max-w-400 mx-auto\">\n <form onSubmit={handleSearch} className=\"flex flex-row items-center gap-4 max-w-screen mx-auto\">\n <div className=\"relative flex-1\">\n <Search className=\"absolute left-3 top-1/2 -translate-y-1/2 w-4 h-4 text-gray-500\" />\n <input\n type=\"text\"\n value={keyword}\n onChange={(e) => setKeyword(e.target.value)}\n placeholder=\"搜索歌曲、歌手...\"\n className=\"w-full bg-gray-900 border border-gray-700 rounded-full py-2 pl-10 pr-4 focus:outline-none focus:ring-2 focus:ring-blue-500 focus:border-transparent transition-all\"\n />\n </div>\n <select\n value={selectedSource}\n onChange={(e) => setSelectedSource(e.target.value as MusicSource)}\n className=\"bg-gray-900 p-2 border border-gray-700 text-gray-300 text-sm rounded-full px-4 focus:outline-none focus:ring-2 focus:ring-blue-500 transition-all cursor-pointer hover:bg-gray-800\"\n >\n {MUSIC_SOURCES.map((src) => (\n <option key={src} value={src}>\n {MUSIC_SOURCE_NAMES[src]}\n </option>\n ))}\n </select>\n <div className=\" flex items-center justify-center max-w-lg bg-gray-900 rounded-full p-2 border border-gray-700\">\n <button\n \n onClick={() => setLayoutMode('list')}\n className={`p-1.5 rounded-full transition-all ${layoutMode === 'list' ? 'bg-blue-600 text-white' : 'text-gray-500 hover:text-gray-300'}`}\n title=\"列表视图\"\n >\n <ListIcon className=\"w-4 h-4\" />\n </button>\n <button\n \n onClick={() => setLayoutMode('grid')}\n className={`p-1.5 rounded-full transition-all ${layoutMode === 'grid' ? 'bg-blue-600 text-white' : 'text-gray-500 hover:text-gray-300'}`}\n title=\"网格视图\"\n >\n <LayoutGrid className=\"w-4 h-4\" />\n </button>\n </div>\n <button\n type=\"submit\"\n disabled={isSearching}\n className=\"bg-blue-600 hover:bg-blue-700 disabled:bg-blue-800 text-white rounded-full px-8 py-2 font-medium transition-all hover:scale-105 active:scale-95 flex items-center justify-center gap-2 shrink-0\"\n >\n {isSearching ? <Loader2 className=\"w-4 h-4 animate-spin\" /> : '搜索'}\n </button>\n </form>\n </div>\n\n {/* 歌曲列表和详情区域 */}\n <div className=\"flex-1 flex overflow-hidden\">\n {/* 左侧列表 */}\n <div className=\"flex-1 overflow-y-auto p-6 scrollbar-thin scrollbar-thumb-gray-800\">\n {Array.isArray(searchData?.tracks) && searchData.tracks.length > 0 ? (\n <div className={layoutMode === 'grid'\n ? \"grid grid-cols-1 md:grid-cols-2 lg:grid-cols-3 gap-4\"\n : \"flex flex-col gap-2 max-w-5xl mx-auto\"\n }>\n {searchData.tracks.map((track) => (\n <div\n key={track.id}\n onClick={() => playTrack(track)}\n className={`flex items-center gap-4 p-3 rounded-xl cursor-pointer transition-all ${currentTrack?.id === track.id\n ? 'bg-blue-600/20 border border-blue-500/50 shadow-[0_0_15px_rgba(59,130,246,0.2)]'\n : 'bg-gray-900/50 border border-gray-800 hover:bg-gray-800/80 hover:border-gray-700'\n } ${layoutMode === 'list' ? 'hover:pl-5' : ''}`}\n >\n <div className={`relative rounded-lg overflow-hidden shrink-0 bg-gray-800 transition-all ${layoutMode === 'grid' ? 'w-14 h-14' : 'w-12 h-12'\n }`}>\n {track.pic ? (\n <img src={track.pic} alt={track.name} className=\"w-full h-full object-cover\" />\n ) : (\n <div className=\"w-full h-full flex items-center justify-center\">\n <MusicIcon className=\"w-6 h-6 text-gray-600\" />\n </div>\n )}\n {currentTrack?.id === track.id && isPlaying && (\n <div className=\"absolute inset-0 bg-black/40 flex items-center justify-center\">\n <div className=\"flex gap-0.5 items-end h-4\">\n <div className=\"w-0.5 bg-blue-400 animate-music-bar\" style={{ height: '60%' }} />\n <div className=\"w-0.5 bg-blue-400 animate-music-bar\" style={{ height: '100%', animationDelay: '0.2s' }} />\n <div className=\"w-0.5 bg-blue-400 animate-music-bar\" style={{ height: '40%', animationDelay: '0.4s' }} />\n </div>\n </div>\n )}\n </div>\n <div className=\"flex-1 min-w-0\">\n <div className=\"flex items-center gap-2\">\n <h3 className={`font-semibold truncate ${layoutMode === 'grid' ? 'text-sm' : 'text-base'}`}>{track.name}</h3>\n <span className=\"text-[10px] px-1.5 py-0.5 rounded-md bg-gray-800 text-gray-400 shrink-0\">\n {MUSIC_SOURCE_NAMES[track.source].replace('音乐', '')}\n </span>\n {track.isVip && (\n <span className=\"text-[10px] px-1.5 py-0.5 rounded-md bg-yellow-500/10 text-yellow-500 border border-yellow-500/20 shrink-0 font-bold\">\n VIP\n </span>\n )}\n </div>\n <p className=\"text-xs text-gray-400 truncate mt-1\">{track.artist}</p>\n </div>\n {layoutMode === 'list' && (\n <div className=\"hidden sm:block text-xs text-gray-500 px-4 truncate max-w-[200px]\">\n {track.album}\n </div>\n )}\n </div>\n ))}\n </div>\n ) : (\n <div className=\"h-full flex flex-col items-center justify-center text-gray-500 gap-4\">\n <div className=\"w-16 h-16 rounded-full bg-gray-900 flex items-center justify-center\">\n <MusicIcon className=\"w-8 h-8\" />\n </div>\n <p>{isSearching ? '正在搜索...' : '搜索你喜欢的音乐'}</p>\n </div>\n )}\n\n {/* 分页控制 */}\n {searchData?.tracks && searchData.tracks.length > 0 && (\n <div className=\"mt-8 flex items-center justify-center gap-4 pb-8\">\n <button\n onClick={() => handlePageChange(Math.max(0, currentPage - 1))}\n disabled={currentPage === 0 || isSearching}\n className=\"p-2 rounded-full bg-gray-900 border border-gray-800 text-gray-400 hover:text-white hover:border-gray-700 disabled:opacity-50 disabled:cursor-not-allowed transition-all\"\n >\n <ChevronLeft className=\"w-5 h-5\" />\n </button>\n <div className=\"flex items-center gap-2\">\n <span className=\"text-sm font-medium text-blue-500 bg-blue-500/10 px-3 py-1 rounded-md\">\n 第 {currentPage + 1} 页\n </span>\n {searchData.total > 0 && (\n <span className=\"text-xs text-gray-500\">\n 共 {Math.ceil(searchData.total / pageSize)} 页\n </span>\n )}\n </div>\n <button\n onClick={() => handlePageChange(currentPage + 1)}\n disabled={isSearching || (searchData.total > 0 && (currentPage + 1) * pageSize >= searchData.total)}\n className=\"p-2 rounded-full bg-gray-900 border border-gray-800 text-gray-400 hover:text-white hover:border-gray-700 disabled:opacity-50 disabled:cursor-not-allowed transition-all\"\n >\n <ChevronRight className=\"w-5 h-5\" />\n </button>\n </div>\n )}\n </div>\n </div>\n\n {/* 底部播放控制栏 */}\n <div className=\"bg-gray-900/80 backdrop-blur-xl border-t border-gray-800 p-4 pb-8 md:pb-4\">\n <div className=\"max-w-7xl mx-auto flex flex-col md:flex-row items-center gap-4\">\n {/* 歌曲信息 */}\n <div className=\"flex items-center gap-4 w-full md:w-1/4\">\n <div className=\"w-12 h-12 rounded-lg overflow-hidden bg-gray-800 shrink-0\">\n {currentTrack?.pic ? (\n <img src={currentTrack.pic} alt=\"\" className=\"w-full h-full object-cover\" />\n ) : (\n <div className=\"w-full h-full flex items-center justify-center\">\n <MusicIcon className=\"w-5 h-5 text-gray-600\" />\n </div>\n )}\n </div>\n <div className=\"flex-1 min-w-0\">\n <h4 className=\"font-medium text-sm truncate\">{currentTrack?.name || '未在播放'}</h4>\n <p className=\"text-xs text-gray-400 truncate mt-0.5\">{currentTrack?.artist || '-'}</p>\n </div>\n </div>\n\n {/* 播放控制 */}\n <div className=\"flex flex-col items-center gap-2 flex-1 w-full\">\n <div className=\"flex items-center gap-6\">\n <button className=\"text-gray-400 hover:text-white transition-colors\">\n <SkipBack className=\"w-5 h-5 fill-current\" />\n </button>\n <button\n onClick={togglePlay}\n disabled={!currentTrack || isLoadingUrl}\n className=\"w-10 h-10 rounded-full bg-white text-black flex items-center justify-center hover:scale-105 transition-transform disabled:opacity-50 disabled:scale-100\"\n >\n {isLoadingUrl ? (\n <Loader2 className=\"w-5 h-5 animate-spin\" />\n ) : isPlaying ? (\n <Pause className=\"w-5 h-5 fill-current\" />\n ) : (\n <Play className=\"w-5 h-5 fill-current ml-0.5\" />\n )}\n </button>\n <button className=\"text-gray-400 hover:text-white transition-colors\">\n <SkipForward className=\"w-5 h-5 fill-current\" />\n </button>\n </div>\n\n <div className=\"flex items-center gap-3 w-full max-w-2xl text-xs text-gray-400\">\n <span>{formatTime(progress)}</span>\n <div className=\"flex-1 relative h-1 group cursor-pointer\">\n <input\n type=\"range\"\n min=\"0\"\n max={duration || 0}\n step=\"0.1\"\n value={progress}\n onChange={handleSeek}\n className=\"absolute inset-0 w-full h-full opacity-0 z-10 cursor-pointer\"\n />\n <div className=\"absolute inset-0 bg-gray-700 rounded-full overflow-hidden\">\n <div\n className=\"h-full bg-blue-500 group-hover:bg-blue-400 transition-colors\"\n style={{ width: `${(progress / (duration || 1)) * 100}%` }}\n />\n </div>\n </div>\n <span>{formatTime(duration)}</span>\n </div>\n </div>\n\n {/* 音量控制 */}\n <div className=\"hidden md:flex items-center gap-3 w-1/4 justify-end\">\n <button\n onClick={() => setIsMuted(!isMuted)}\n className=\"text-gray-400 hover:text-white transition-colors\"\n >\n {isMuted || volume === 0 ? <VolumeX className=\"w-5 h-5\" /> : <Volume2 className=\"w-5 h-5\" />}\n </button>\n <div className=\"w-24 relative h-1 group\">\n <input\n type=\"range\"\n min=\"0\"\n max=\"1\"\n step=\"0.01\"\n value={isMuted ? 0 : volume}\n onChange={(e) => {\n const val = parseFloat(e.target.value);\n setVolume(val);\n setIsMuted(false);\n if (audioRef.current) audioRef.current.volume = val;\n }}\n className=\"absolute inset-0 w-full h-full opacity-0 z-10 cursor-pointer\"\n />\n <div className=\"absolute inset-0 bg-gray-700 rounded-full overflow-hidden\">\n <div\n className=\"h-full bg-gray-300 group-hover:bg-blue-400 transition-colors\"\n style={{ width: `${(isMuted ? 0 : volume) * 100}%` }}\n />\n </div>\n </div>\n </div>\n </div>\n </div>\n\n <audio\n ref={audioRef}\n {...({ referrerPolicy: 'no-referrer' } as any)}\n onTimeUpdate={handleTimeUpdate}\n onEnded={() => setIsPlaying(false)}\n onPlay={() => setIsPlaying(true)}\n onPause={() => setIsPlaying(false)}\n style={{ display: 'none' }}\n />\n </div>\n );\n};\n"]}
|
|
@@ -0,0 +1,427 @@
|
|
|
1
|
+
import { DEFAULT_MUSIC_SOURCE, MUSIC_SOURCES, MUSIC_SOURCE_NAMES } from '../chunk-MBG4DBGP.mjs';
|
|
2
|
+
export { MetingService, createLyricHandler, createSearchHandler, createSongUrlHandler, musicService } from '../chunk-MBG4DBGP.mjs';
|
|
3
|
+
import '../chunk-BJTO5JO5.mjs';
|
|
4
|
+
import React, { useState, useMemo, useCallback, useRef } from 'react';
|
|
5
|
+
import { Search, List, LayoutGrid, Loader2, Music, ChevronLeft, ChevronRight, SkipBack, Pause, Play, SkipForward, VolumeX, Volume2 } from 'lucide-react';
|
|
6
|
+
import useSWR from 'swr';
|
|
7
|
+
|
|
8
|
+
// src/music/adapters/kugou.ts
|
|
9
|
+
var kugouAdapter = {
|
|
10
|
+
parseSearchResult(data) {
|
|
11
|
+
const root = typeof data === "string" ? JSON.parse(data) : data;
|
|
12
|
+
const info = root.data?.data?.info || root.data?.info || root.info || [];
|
|
13
|
+
const total = root.data?.data?.total || root.data?.total || info.length;
|
|
14
|
+
return {
|
|
15
|
+
tracks: info.map((item) => {
|
|
16
|
+
let pic = item.pic || "";
|
|
17
|
+
if (item.trans_param?.union_cover) {
|
|
18
|
+
pic = item.trans_param.union_cover.replace("{size}", "400");
|
|
19
|
+
}
|
|
20
|
+
return {
|
|
21
|
+
id: item.hash || item.id,
|
|
22
|
+
name: item.songname || item.filename || "Unknown",
|
|
23
|
+
artist: item.singername || "Unknown Artist",
|
|
24
|
+
album: item.album_name || item.album || "",
|
|
25
|
+
pic,
|
|
26
|
+
url: item.url,
|
|
27
|
+
lrc: item.lrc,
|
|
28
|
+
source: "kugou",
|
|
29
|
+
isVip: item.privilege >= 8,
|
|
30
|
+
playable: item.status !== 0
|
|
31
|
+
};
|
|
32
|
+
}),
|
|
33
|
+
total
|
|
34
|
+
};
|
|
35
|
+
},
|
|
36
|
+
parseGetSongUrl(data) {
|
|
37
|
+
return data.url?.url || data.url?.backup_url?.[0] || null;
|
|
38
|
+
},
|
|
39
|
+
parseGetLyric(data) {
|
|
40
|
+
const root = typeof data === "string" ? JSON.parse(data) : data;
|
|
41
|
+
return root.lyric || root.lrc || root.data?.lyric || root.data || "";
|
|
42
|
+
}
|
|
43
|
+
};
|
|
44
|
+
|
|
45
|
+
// src/music/adapters/netease.ts
|
|
46
|
+
var neteaseAdapter = {
|
|
47
|
+
parseSearchResult(data) {
|
|
48
|
+
const root = typeof data === "string" ? JSON.parse(data) : data;
|
|
49
|
+
const songs = root.result?.songs || root.songs || (Array.isArray(root) ? root : []);
|
|
50
|
+
return {
|
|
51
|
+
tracks: songs.map((item) => ({
|
|
52
|
+
id: item.id,
|
|
53
|
+
name: item.name,
|
|
54
|
+
artist: Array.isArray(item.artist) ? item.artist.join(", ") : item.artist,
|
|
55
|
+
album: item.album?.name || item.album,
|
|
56
|
+
pic: item.pic || item.album?.picUrl,
|
|
57
|
+
url: item.url,
|
|
58
|
+
lrc: item.lrc,
|
|
59
|
+
source: "netease",
|
|
60
|
+
isVip: item.fee === 1 || item.fee === 4,
|
|
61
|
+
playable: item.noCopyrightRcmd === null
|
|
62
|
+
})),
|
|
63
|
+
total: root.result?.songCount || songs.length
|
|
64
|
+
};
|
|
65
|
+
},
|
|
66
|
+
parseGetSongUrl(data) {
|
|
67
|
+
const root = typeof data === "string" ? JSON.parse(data) : data;
|
|
68
|
+
const item = root.data?.[0] || root[0] || root;
|
|
69
|
+
return item.url || null;
|
|
70
|
+
},
|
|
71
|
+
parseGetLyric(data) {
|
|
72
|
+
const root = typeof data === "string" ? JSON.parse(data) : data;
|
|
73
|
+
return root.lyric || root.lrc || root.data?.lyric || "";
|
|
74
|
+
}
|
|
75
|
+
};
|
|
76
|
+
|
|
77
|
+
// src/music/adapters/tencent.ts
|
|
78
|
+
var tencentAdapter = {
|
|
79
|
+
parseSearchResult(data) {
|
|
80
|
+
const root = typeof data === "string" ? JSON.parse(data) : data;
|
|
81
|
+
const songData = root.data?.data?.song || root.data?.song || root.data || root;
|
|
82
|
+
const list = songData.list || root.songs || [];
|
|
83
|
+
const total = songData.totalnum || root.total || list.length;
|
|
84
|
+
return {
|
|
85
|
+
tracks: list.map((item) => {
|
|
86
|
+
const artist = Array.isArray(item.singer) ? item.singer.map((s) => s.name).join(", ") : item.singer?.[0]?.name || item.artist || "Unknown";
|
|
87
|
+
let pic = item.pic;
|
|
88
|
+
if (!pic && item.album?.mid) {
|
|
89
|
+
pic = `https://y.gtimg.cn/music/photo_new/T002R300x300M000${item.album.mid}.jpg`;
|
|
90
|
+
}
|
|
91
|
+
return {
|
|
92
|
+
id: item.mid || item.id || item.songid,
|
|
93
|
+
name: item.name || item.title || item.songname,
|
|
94
|
+
artist,
|
|
95
|
+
album: item.album?.name || item.albumname || item.album,
|
|
96
|
+
pic: pic || "",
|
|
97
|
+
url: item.url,
|
|
98
|
+
lrc: item.lrc,
|
|
99
|
+
source: "tencent",
|
|
100
|
+
isVip: item.pay?.pay_play === 1,
|
|
101
|
+
playable: item.action?.switch !== 0
|
|
102
|
+
};
|
|
103
|
+
}),
|
|
104
|
+
total
|
|
105
|
+
};
|
|
106
|
+
},
|
|
107
|
+
parseGetSongUrl(data) {
|
|
108
|
+
const root = data;
|
|
109
|
+
const urlData = root.url.url;
|
|
110
|
+
let finalUrl = Object.values(urlData)[0];
|
|
111
|
+
console.log("finalUrl2", finalUrl);
|
|
112
|
+
return finalUrl.startsWith("http") ? finalUrl : `http://${finalUrl}`;
|
|
113
|
+
},
|
|
114
|
+
parseGetLyric(data) {
|
|
115
|
+
const root = typeof data === "string" ? JSON.parse(data) : data;
|
|
116
|
+
return root.lyric || root.lrc || root.data?.lyric || "";
|
|
117
|
+
}
|
|
118
|
+
};
|
|
119
|
+
|
|
120
|
+
// src/music/adapters/xiami.ts
|
|
121
|
+
var xiamiAdapter = {
|
|
122
|
+
parseSearchResult(data) {
|
|
123
|
+
const root = typeof data === "string" ? JSON.parse(data) : data;
|
|
124
|
+
const result = root.data?.result || root.result || root;
|
|
125
|
+
const songs = result.songs || (Array.isArray(root) ? root : []);
|
|
126
|
+
return {
|
|
127
|
+
tracks: songs.map((item) => ({
|
|
128
|
+
id: item.id?.toString() || "",
|
|
129
|
+
name: item.name || "Unknown",
|
|
130
|
+
artist: Array.isArray(item.ar) ? item.ar.map((a) => a.name).join(", ") : item.artist || "Unknown Artist",
|
|
131
|
+
album: item.al?.name || item.album || "",
|
|
132
|
+
pic: item.al?.picUrl || item.pic || "",
|
|
133
|
+
url: item.url,
|
|
134
|
+
lrc: item.lrc,
|
|
135
|
+
source: "xiami",
|
|
136
|
+
// 这里的逻辑参考提供的数据结构
|
|
137
|
+
isVip: item.fee === 1 || item.fee === 8,
|
|
138
|
+
playable: item.copyright !== 0
|
|
139
|
+
})),
|
|
140
|
+
total: result.songCount || songs.length
|
|
141
|
+
};
|
|
142
|
+
},
|
|
143
|
+
parseGetSongUrl(data) {
|
|
144
|
+
const root = typeof data === "string" ? JSON.parse(data) : data;
|
|
145
|
+
const item = root.data?.[0] || root.data || root[0] || root;
|
|
146
|
+
return item.url || null;
|
|
147
|
+
},
|
|
148
|
+
parseGetLyric(data) {
|
|
149
|
+
const root = typeof data === "string" ? JSON.parse(data) : data;
|
|
150
|
+
return root.lyric || root.lrc || root.data?.lyric || root.data || "";
|
|
151
|
+
}
|
|
152
|
+
};
|
|
153
|
+
|
|
154
|
+
// src/music/hooks/useMusic.ts
|
|
155
|
+
var fetcher = (url) => fetch(url).then((res) => res.json());
|
|
156
|
+
var ADAPTERS = {
|
|
157
|
+
kugou: kugouAdapter,
|
|
158
|
+
netease: neteaseAdapter,
|
|
159
|
+
tencent: tencentAdapter,
|
|
160
|
+
xiami: xiamiAdapter
|
|
161
|
+
};
|
|
162
|
+
function useMusic() {
|
|
163
|
+
const [searchOptions, setSearchOptions] = useState(null);
|
|
164
|
+
const { data: rawData, error: searchError, isLoading: isSearching } = useSWR(
|
|
165
|
+
searchOptions ? `/api/music/search?keyword=${encodeURIComponent(searchOptions.keyword)}&source=${searchOptions.source || DEFAULT_MUSIC_SOURCE}&limit=${searchOptions.limit || 20}&offset=${searchOptions.offset || 0}` : null,
|
|
166
|
+
fetcher
|
|
167
|
+
);
|
|
168
|
+
const searchResult = useMemo(() => {
|
|
169
|
+
if (!rawData?.data || !searchOptions) return void 0;
|
|
170
|
+
const adapter = ADAPTERS[searchOptions.source || DEFAULT_MUSIC_SOURCE];
|
|
171
|
+
if (adapter) {
|
|
172
|
+
return adapter.parseSearchResult(rawData.data);
|
|
173
|
+
}
|
|
174
|
+
return void 0;
|
|
175
|
+
}, [rawData, searchOptions]);
|
|
176
|
+
const search = useCallback((options) => {
|
|
177
|
+
setSearchOptions(options);
|
|
178
|
+
}, []);
|
|
179
|
+
const getSongUrl = useCallback(async (id, source = DEFAULT_MUSIC_SOURCE) => {
|
|
180
|
+
try {
|
|
181
|
+
const res = await fetch(`/api/music/url?id=${id}&source=${source}`);
|
|
182
|
+
const json = await res.json();
|
|
183
|
+
const adapter = ADAPTERS[source];
|
|
184
|
+
console.log("json2", json.data, source, adapter);
|
|
185
|
+
if (adapter && json.data) {
|
|
186
|
+
console.log("getSongUrl2", json.data);
|
|
187
|
+
return adapter.parseGetSongUrl(json.data) || void 0;
|
|
188
|
+
}
|
|
189
|
+
return json.data?.url;
|
|
190
|
+
} catch (err) {
|
|
191
|
+
console.error("[Music] Failed to get song URL:", err);
|
|
192
|
+
return void 0;
|
|
193
|
+
}
|
|
194
|
+
}, []);
|
|
195
|
+
const getLyric = useCallback(async (id, source = DEFAULT_MUSIC_SOURCE) => {
|
|
196
|
+
try {
|
|
197
|
+
const res = await fetch(`/api/music/lyric?id=${id}&source=${source}`);
|
|
198
|
+
const json = await res.json();
|
|
199
|
+
const adapter = ADAPTERS[source];
|
|
200
|
+
if (adapter && json.data) {
|
|
201
|
+
return adapter.parseGetLyric(json.data);
|
|
202
|
+
}
|
|
203
|
+
return json.data?.lyric;
|
|
204
|
+
} catch (err) {
|
|
205
|
+
console.error("[Music] Failed to get lyric:", err);
|
|
206
|
+
return void 0;
|
|
207
|
+
}
|
|
208
|
+
}, []);
|
|
209
|
+
return {
|
|
210
|
+
search,
|
|
211
|
+
searchResult,
|
|
212
|
+
isSearching,
|
|
213
|
+
searchError,
|
|
214
|
+
getSongUrl,
|
|
215
|
+
getLyric
|
|
216
|
+
};
|
|
217
|
+
}
|
|
218
|
+
|
|
219
|
+
// src/music/components/MusicPlayer.tsx
|
|
220
|
+
var MusicPlayer = () => {
|
|
221
|
+
const { search, searchResult: searchData, isSearching, getSongUrl } = useMusic();
|
|
222
|
+
const [keyword, setKeyword] = useState("");
|
|
223
|
+
const [selectedSource, setSelectedSource] = useState(DEFAULT_MUSIC_SOURCE);
|
|
224
|
+
const [currentPage, setCurrentPage] = useState(0);
|
|
225
|
+
const [layoutMode, setLayoutMode] = useState("grid");
|
|
226
|
+
const pageSize = 20;
|
|
227
|
+
const [currentTrack, setCurrentTrack] = useState(null);
|
|
228
|
+
const [isPlaying, setIsPlaying] = useState(false);
|
|
229
|
+
const [progress, setProgress] = useState(0);
|
|
230
|
+
const [duration, setDuration] = useState(0);
|
|
231
|
+
const [volume, setVolume] = useState(0.7);
|
|
232
|
+
const [isMuted, setIsMuted] = useState(false);
|
|
233
|
+
const [isLoadingUrl, setIsLoadingUrl] = useState(false);
|
|
234
|
+
const audioRef = useRef(null);
|
|
235
|
+
const handleSearch = (e) => {
|
|
236
|
+
e.preventDefault();
|
|
237
|
+
if (keyword.trim()) {
|
|
238
|
+
setCurrentPage(0);
|
|
239
|
+
search({ keyword, source: selectedSource, offset: 0, limit: pageSize });
|
|
240
|
+
}
|
|
241
|
+
};
|
|
242
|
+
const handlePageChange = (newPage) => {
|
|
243
|
+
setCurrentPage(newPage);
|
|
244
|
+
search({ keyword, source: selectedSource, offset: newPage, limit: pageSize });
|
|
245
|
+
};
|
|
246
|
+
const playTrack = async (track) => {
|
|
247
|
+
setIsLoadingUrl(true);
|
|
248
|
+
const url = await getSongUrl(track.id, track.source);
|
|
249
|
+
setIsLoadingUrl(false);
|
|
250
|
+
if (url) {
|
|
251
|
+
const fullTrack = { ...track, url };
|
|
252
|
+
setCurrentTrack(fullTrack);
|
|
253
|
+
setIsPlaying(true);
|
|
254
|
+
if (audioRef.current) {
|
|
255
|
+
audioRef.current.src = url;
|
|
256
|
+
audioRef.current.play();
|
|
257
|
+
}
|
|
258
|
+
} else {
|
|
259
|
+
alert("\u65E0\u6CD5\u83B7\u53D6\u64AD\u653E\u94FE\u63A5");
|
|
260
|
+
}
|
|
261
|
+
};
|
|
262
|
+
const togglePlay = () => {
|
|
263
|
+
if (!audioRef.current || !currentTrack) return;
|
|
264
|
+
if (isPlaying) {
|
|
265
|
+
audioRef.current.pause();
|
|
266
|
+
} else {
|
|
267
|
+
audioRef.current.play();
|
|
268
|
+
}
|
|
269
|
+
setIsPlaying(!isPlaying);
|
|
270
|
+
};
|
|
271
|
+
const handleTimeUpdate = () => {
|
|
272
|
+
if (audioRef.current) {
|
|
273
|
+
setProgress(audioRef.current.currentTime);
|
|
274
|
+
setDuration(audioRef.current.duration);
|
|
275
|
+
}
|
|
276
|
+
};
|
|
277
|
+
const handleSeek = (e) => {
|
|
278
|
+
const time = parseFloat(e.target.value);
|
|
279
|
+
setProgress(time);
|
|
280
|
+
if (audioRef.current) {
|
|
281
|
+
audioRef.current.currentTime = time;
|
|
282
|
+
}
|
|
283
|
+
};
|
|
284
|
+
const formatTime = (time) => {
|
|
285
|
+
if (isNaN(time)) return "00:00";
|
|
286
|
+
const mins = Math.floor(time / 60);
|
|
287
|
+
const secs = Math.floor(time % 60);
|
|
288
|
+
return `${mins.toString().padStart(2, "0")}:${secs.toString().padStart(2, "0")}`;
|
|
289
|
+
};
|
|
290
|
+
return /* @__PURE__ */ React.createElement("div", { className: "flex flex-col h-full bg-black text-white font-sans" }, /* @__PURE__ */ React.createElement("div", { className: "p-6 border-b border-gray-800 max-w-400 mx-auto" }, /* @__PURE__ */ React.createElement("form", { onSubmit: handleSearch, className: "flex flex-row items-center gap-4 max-w-screen mx-auto" }, /* @__PURE__ */ React.createElement("div", { className: "relative flex-1" }, /* @__PURE__ */ React.createElement(Search, { className: "absolute left-3 top-1/2 -translate-y-1/2 w-4 h-4 text-gray-500" }), /* @__PURE__ */ React.createElement(
|
|
291
|
+
"input",
|
|
292
|
+
{
|
|
293
|
+
type: "text",
|
|
294
|
+
value: keyword,
|
|
295
|
+
onChange: (e) => setKeyword(e.target.value),
|
|
296
|
+
placeholder: "\u641C\u7D22\u6B4C\u66F2\u3001\u6B4C\u624B...",
|
|
297
|
+
className: "w-full bg-gray-900 border border-gray-700 rounded-full py-2 pl-10 pr-4 focus:outline-none focus:ring-2 focus:ring-blue-500 focus:border-transparent transition-all"
|
|
298
|
+
}
|
|
299
|
+
)), /* @__PURE__ */ React.createElement(
|
|
300
|
+
"select",
|
|
301
|
+
{
|
|
302
|
+
value: selectedSource,
|
|
303
|
+
onChange: (e) => setSelectedSource(e.target.value),
|
|
304
|
+
className: "bg-gray-900 p-2 border border-gray-700 text-gray-300 text-sm rounded-full px-4 focus:outline-none focus:ring-2 focus:ring-blue-500 transition-all cursor-pointer hover:bg-gray-800"
|
|
305
|
+
},
|
|
306
|
+
MUSIC_SOURCES.map((src) => /* @__PURE__ */ React.createElement("option", { key: src, value: src }, MUSIC_SOURCE_NAMES[src]))
|
|
307
|
+
), /* @__PURE__ */ React.createElement("div", { className: " flex items-center justify-center max-w-lg bg-gray-900 rounded-full p-2 border border-gray-700" }, /* @__PURE__ */ React.createElement(
|
|
308
|
+
"button",
|
|
309
|
+
{
|
|
310
|
+
onClick: () => setLayoutMode("list"),
|
|
311
|
+
className: `p-1.5 rounded-full transition-all ${layoutMode === "list" ? "bg-blue-600 text-white" : "text-gray-500 hover:text-gray-300"}`,
|
|
312
|
+
title: "\u5217\u8868\u89C6\u56FE"
|
|
313
|
+
},
|
|
314
|
+
/* @__PURE__ */ React.createElement(List, { className: "w-4 h-4" })
|
|
315
|
+
), /* @__PURE__ */ React.createElement(
|
|
316
|
+
"button",
|
|
317
|
+
{
|
|
318
|
+
onClick: () => setLayoutMode("grid"),
|
|
319
|
+
className: `p-1.5 rounded-full transition-all ${layoutMode === "grid" ? "bg-blue-600 text-white" : "text-gray-500 hover:text-gray-300"}`,
|
|
320
|
+
title: "\u7F51\u683C\u89C6\u56FE"
|
|
321
|
+
},
|
|
322
|
+
/* @__PURE__ */ React.createElement(LayoutGrid, { className: "w-4 h-4" })
|
|
323
|
+
)), /* @__PURE__ */ React.createElement(
|
|
324
|
+
"button",
|
|
325
|
+
{
|
|
326
|
+
type: "submit",
|
|
327
|
+
disabled: isSearching,
|
|
328
|
+
className: "bg-blue-600 hover:bg-blue-700 disabled:bg-blue-800 text-white rounded-full px-8 py-2 font-medium transition-all hover:scale-105 active:scale-95 flex items-center justify-center gap-2 shrink-0"
|
|
329
|
+
},
|
|
330
|
+
isSearching ? /* @__PURE__ */ React.createElement(Loader2, { className: "w-4 h-4 animate-spin" }) : "\u641C\u7D22"
|
|
331
|
+
))), /* @__PURE__ */ React.createElement("div", { className: "flex-1 flex overflow-hidden" }, /* @__PURE__ */ React.createElement("div", { className: "flex-1 overflow-y-auto p-6 scrollbar-thin scrollbar-thumb-gray-800" }, Array.isArray(searchData?.tracks) && searchData.tracks.length > 0 ? /* @__PURE__ */ React.createElement("div", { className: layoutMode === "grid" ? "grid grid-cols-1 md:grid-cols-2 lg:grid-cols-3 gap-4" : "flex flex-col gap-2 max-w-5xl mx-auto" }, searchData.tracks.map((track) => /* @__PURE__ */ React.createElement(
|
|
332
|
+
"div",
|
|
333
|
+
{
|
|
334
|
+
key: track.id,
|
|
335
|
+
onClick: () => playTrack(track),
|
|
336
|
+
className: `flex items-center gap-4 p-3 rounded-xl cursor-pointer transition-all ${currentTrack?.id === track.id ? "bg-blue-600/20 border border-blue-500/50 shadow-[0_0_15px_rgba(59,130,246,0.2)]" : "bg-gray-900/50 border border-gray-800 hover:bg-gray-800/80 hover:border-gray-700"} ${layoutMode === "list" ? "hover:pl-5" : ""}`
|
|
337
|
+
},
|
|
338
|
+
/* @__PURE__ */ React.createElement("div", { className: `relative rounded-lg overflow-hidden shrink-0 bg-gray-800 transition-all ${layoutMode === "grid" ? "w-14 h-14" : "w-12 h-12"}` }, track.pic ? /* @__PURE__ */ React.createElement("img", { src: track.pic, alt: track.name, className: "w-full h-full object-cover" }) : /* @__PURE__ */ React.createElement("div", { className: "w-full h-full flex items-center justify-center" }, /* @__PURE__ */ React.createElement(Music, { className: "w-6 h-6 text-gray-600" })), currentTrack?.id === track.id && isPlaying && /* @__PURE__ */ React.createElement("div", { className: "absolute inset-0 bg-black/40 flex items-center justify-center" }, /* @__PURE__ */ React.createElement("div", { className: "flex gap-0.5 items-end h-4" }, /* @__PURE__ */ React.createElement("div", { className: "w-0.5 bg-blue-400 animate-music-bar", style: { height: "60%" } }), /* @__PURE__ */ React.createElement("div", { className: "w-0.5 bg-blue-400 animate-music-bar", style: { height: "100%", animationDelay: "0.2s" } }), /* @__PURE__ */ React.createElement("div", { className: "w-0.5 bg-blue-400 animate-music-bar", style: { height: "40%", animationDelay: "0.4s" } })))),
|
|
339
|
+
/* @__PURE__ */ React.createElement("div", { className: "flex-1 min-w-0" }, /* @__PURE__ */ React.createElement("div", { className: "flex items-center gap-2" }, /* @__PURE__ */ React.createElement("h3", { className: `font-semibold truncate ${layoutMode === "grid" ? "text-sm" : "text-base"}` }, track.name), /* @__PURE__ */ React.createElement("span", { className: "text-[10px] px-1.5 py-0.5 rounded-md bg-gray-800 text-gray-400 shrink-0" }, MUSIC_SOURCE_NAMES[track.source].replace("\u97F3\u4E50", "")), track.isVip && /* @__PURE__ */ React.createElement("span", { className: "text-[10px] px-1.5 py-0.5 rounded-md bg-yellow-500/10 text-yellow-500 border border-yellow-500/20 shrink-0 font-bold" }, "VIP")), /* @__PURE__ */ React.createElement("p", { className: "text-xs text-gray-400 truncate mt-1" }, track.artist)),
|
|
340
|
+
layoutMode === "list" && /* @__PURE__ */ React.createElement("div", { className: "hidden sm:block text-xs text-gray-500 px-4 truncate max-w-[200px]" }, track.album)
|
|
341
|
+
))) : /* @__PURE__ */ React.createElement("div", { className: "h-full flex flex-col items-center justify-center text-gray-500 gap-4" }, /* @__PURE__ */ React.createElement("div", { className: "w-16 h-16 rounded-full bg-gray-900 flex items-center justify-center" }, /* @__PURE__ */ React.createElement(Music, { className: "w-8 h-8" })), /* @__PURE__ */ React.createElement("p", null, isSearching ? "\u6B63\u5728\u641C\u7D22..." : "\u641C\u7D22\u4F60\u559C\u6B22\u7684\u97F3\u4E50")), searchData?.tracks && searchData.tracks.length > 0 && /* @__PURE__ */ React.createElement("div", { className: "mt-8 flex items-center justify-center gap-4 pb-8" }, /* @__PURE__ */ React.createElement(
|
|
342
|
+
"button",
|
|
343
|
+
{
|
|
344
|
+
onClick: () => handlePageChange(Math.max(0, currentPage - 1)),
|
|
345
|
+
disabled: currentPage === 0 || isSearching,
|
|
346
|
+
className: "p-2 rounded-full bg-gray-900 border border-gray-800 text-gray-400 hover:text-white hover:border-gray-700 disabled:opacity-50 disabled:cursor-not-allowed transition-all"
|
|
347
|
+
},
|
|
348
|
+
/* @__PURE__ */ React.createElement(ChevronLeft, { className: "w-5 h-5" })
|
|
349
|
+
), /* @__PURE__ */ React.createElement("div", { className: "flex items-center gap-2" }, /* @__PURE__ */ React.createElement("span", { className: "text-sm font-medium text-blue-500 bg-blue-500/10 px-3 py-1 rounded-md" }, "\u7B2C ", currentPage + 1, " \u9875"), searchData.total > 0 && /* @__PURE__ */ React.createElement("span", { className: "text-xs text-gray-500" }, "\u5171 ", Math.ceil(searchData.total / pageSize), " \u9875")), /* @__PURE__ */ React.createElement(
|
|
350
|
+
"button",
|
|
351
|
+
{
|
|
352
|
+
onClick: () => handlePageChange(currentPage + 1),
|
|
353
|
+
disabled: isSearching || searchData.total > 0 && (currentPage + 1) * pageSize >= searchData.total,
|
|
354
|
+
className: "p-2 rounded-full bg-gray-900 border border-gray-800 text-gray-400 hover:text-white hover:border-gray-700 disabled:opacity-50 disabled:cursor-not-allowed transition-all"
|
|
355
|
+
},
|
|
356
|
+
/* @__PURE__ */ React.createElement(ChevronRight, { className: "w-5 h-5" })
|
|
357
|
+
)))), /* @__PURE__ */ React.createElement("div", { className: "bg-gray-900/80 backdrop-blur-xl border-t border-gray-800 p-4 pb-8 md:pb-4" }, /* @__PURE__ */ React.createElement("div", { className: "max-w-7xl mx-auto flex flex-col md:flex-row items-center gap-4" }, /* @__PURE__ */ React.createElement("div", { className: "flex items-center gap-4 w-full md:w-1/4" }, /* @__PURE__ */ React.createElement("div", { className: "w-12 h-12 rounded-lg overflow-hidden bg-gray-800 shrink-0" }, currentTrack?.pic ? /* @__PURE__ */ React.createElement("img", { src: currentTrack.pic, alt: "", className: "w-full h-full object-cover" }) : /* @__PURE__ */ React.createElement("div", { className: "w-full h-full flex items-center justify-center" }, /* @__PURE__ */ React.createElement(Music, { className: "w-5 h-5 text-gray-600" }))), /* @__PURE__ */ React.createElement("div", { className: "flex-1 min-w-0" }, /* @__PURE__ */ React.createElement("h4", { className: "font-medium text-sm truncate" }, currentTrack?.name || "\u672A\u5728\u64AD\u653E"), /* @__PURE__ */ React.createElement("p", { className: "text-xs text-gray-400 truncate mt-0.5" }, currentTrack?.artist || "-"))), /* @__PURE__ */ React.createElement("div", { className: "flex flex-col items-center gap-2 flex-1 w-full" }, /* @__PURE__ */ React.createElement("div", { className: "flex items-center gap-6" }, /* @__PURE__ */ React.createElement("button", { className: "text-gray-400 hover:text-white transition-colors" }, /* @__PURE__ */ React.createElement(SkipBack, { className: "w-5 h-5 fill-current" })), /* @__PURE__ */ React.createElement(
|
|
358
|
+
"button",
|
|
359
|
+
{
|
|
360
|
+
onClick: togglePlay,
|
|
361
|
+
disabled: !currentTrack || isLoadingUrl,
|
|
362
|
+
className: "w-10 h-10 rounded-full bg-white text-black flex items-center justify-center hover:scale-105 transition-transform disabled:opacity-50 disabled:scale-100"
|
|
363
|
+
},
|
|
364
|
+
isLoadingUrl ? /* @__PURE__ */ React.createElement(Loader2, { className: "w-5 h-5 animate-spin" }) : isPlaying ? /* @__PURE__ */ React.createElement(Pause, { className: "w-5 h-5 fill-current" }) : /* @__PURE__ */ React.createElement(Play, { className: "w-5 h-5 fill-current ml-0.5" })
|
|
365
|
+
), /* @__PURE__ */ React.createElement("button", { className: "text-gray-400 hover:text-white transition-colors" }, /* @__PURE__ */ React.createElement(SkipForward, { className: "w-5 h-5 fill-current" }))), /* @__PURE__ */ React.createElement("div", { className: "flex items-center gap-3 w-full max-w-2xl text-xs text-gray-400" }, /* @__PURE__ */ React.createElement("span", null, formatTime(progress)), /* @__PURE__ */ React.createElement("div", { className: "flex-1 relative h-1 group cursor-pointer" }, /* @__PURE__ */ React.createElement(
|
|
366
|
+
"input",
|
|
367
|
+
{
|
|
368
|
+
type: "range",
|
|
369
|
+
min: "0",
|
|
370
|
+
max: duration || 0,
|
|
371
|
+
step: "0.1",
|
|
372
|
+
value: progress,
|
|
373
|
+
onChange: handleSeek,
|
|
374
|
+
className: "absolute inset-0 w-full h-full opacity-0 z-10 cursor-pointer"
|
|
375
|
+
}
|
|
376
|
+
), /* @__PURE__ */ React.createElement("div", { className: "absolute inset-0 bg-gray-700 rounded-full overflow-hidden" }, /* @__PURE__ */ React.createElement(
|
|
377
|
+
"div",
|
|
378
|
+
{
|
|
379
|
+
className: "h-full bg-blue-500 group-hover:bg-blue-400 transition-colors",
|
|
380
|
+
style: { width: `${progress / (duration || 1) * 100}%` }
|
|
381
|
+
}
|
|
382
|
+
))), /* @__PURE__ */ React.createElement("span", null, formatTime(duration)))), /* @__PURE__ */ React.createElement("div", { className: "hidden md:flex items-center gap-3 w-1/4 justify-end" }, /* @__PURE__ */ React.createElement(
|
|
383
|
+
"button",
|
|
384
|
+
{
|
|
385
|
+
onClick: () => setIsMuted(!isMuted),
|
|
386
|
+
className: "text-gray-400 hover:text-white transition-colors"
|
|
387
|
+
},
|
|
388
|
+
isMuted || volume === 0 ? /* @__PURE__ */ React.createElement(VolumeX, { className: "w-5 h-5" }) : /* @__PURE__ */ React.createElement(Volume2, { className: "w-5 h-5" })
|
|
389
|
+
), /* @__PURE__ */ React.createElement("div", { className: "w-24 relative h-1 group" }, /* @__PURE__ */ React.createElement(
|
|
390
|
+
"input",
|
|
391
|
+
{
|
|
392
|
+
type: "range",
|
|
393
|
+
min: "0",
|
|
394
|
+
max: "1",
|
|
395
|
+
step: "0.01",
|
|
396
|
+
value: isMuted ? 0 : volume,
|
|
397
|
+
onChange: (e) => {
|
|
398
|
+
const val = parseFloat(e.target.value);
|
|
399
|
+
setVolume(val);
|
|
400
|
+
setIsMuted(false);
|
|
401
|
+
if (audioRef.current) audioRef.current.volume = val;
|
|
402
|
+
},
|
|
403
|
+
className: "absolute inset-0 w-full h-full opacity-0 z-10 cursor-pointer"
|
|
404
|
+
}
|
|
405
|
+
), /* @__PURE__ */ React.createElement("div", { className: "absolute inset-0 bg-gray-700 rounded-full overflow-hidden" }, /* @__PURE__ */ React.createElement(
|
|
406
|
+
"div",
|
|
407
|
+
{
|
|
408
|
+
className: "h-full bg-gray-300 group-hover:bg-blue-400 transition-colors",
|
|
409
|
+
style: { width: `${(isMuted ? 0 : volume) * 100}%` }
|
|
410
|
+
}
|
|
411
|
+
)))))), /* @__PURE__ */ React.createElement(
|
|
412
|
+
"audio",
|
|
413
|
+
{
|
|
414
|
+
ref: audioRef,
|
|
415
|
+
...{ referrerPolicy: "no-referrer" },
|
|
416
|
+
onTimeUpdate: handleTimeUpdate,
|
|
417
|
+
onEnded: () => setIsPlaying(false),
|
|
418
|
+
onPlay: () => setIsPlaying(true),
|
|
419
|
+
onPause: () => setIsPlaying(false),
|
|
420
|
+
style: { display: "none" }
|
|
421
|
+
}
|
|
422
|
+
));
|
|
423
|
+
};
|
|
424
|
+
|
|
425
|
+
export { MusicPlayer, kugouAdapter, neteaseAdapter, tencentAdapter, useMusic, xiamiAdapter };
|
|
426
|
+
//# sourceMappingURL=index.mjs.map
|
|
427
|
+
//# sourceMappingURL=index.mjs.map
|