sa2kit 2.0.0 → 2.0.2

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.
Files changed (264) hide show
  1. package/README.md +1 -1
  2. package/dist/CollisionBalls-BpHufX3H.d.mts +41 -0
  3. package/dist/CollisionBalls-BpHufX3H.d.ts +41 -0
  4. package/dist/ConfigService-BxK06xP6.d.mts +262 -0
  5. package/dist/ConfigService-BxK06xP6.d.ts +262 -0
  6. package/dist/UniversalFileService-BpvbZitV.d.mts +139 -0
  7. package/dist/UniversalFileService-GsP6D3Rc.d.ts +139 -0
  8. package/dist/audioDetection/index.d.mts +449 -0
  9. package/dist/audioDetection/index.d.ts +449 -0
  10. package/dist/audioDetection/index.js +1244 -0
  11. package/dist/audioDetection/index.js.map +1 -0
  12. package/dist/audioDetection/index.mjs +1227 -0
  13. package/dist/audioDetection/index.mjs.map +1 -0
  14. package/dist/auth/legacy/core/index.d.mts +42 -0
  15. package/dist/auth/legacy/core/index.d.ts +42 -0
  16. package/dist/auth/legacy/core/index.js +242 -0
  17. package/dist/auth/legacy/core/index.js.map +1 -0
  18. package/dist/auth/legacy/core/index.mjs +226 -0
  19. package/dist/auth/legacy/core/index.mjs.map +1 -0
  20. package/dist/auth/legacy/db/index.d.mts +5 -0
  21. package/dist/auth/legacy/db/index.d.ts +5 -0
  22. package/dist/auth/legacy/db/index.js +261 -0
  23. package/dist/auth/legacy/db/index.js.map +1 -0
  24. package/dist/auth/legacy/db/index.mjs +250 -0
  25. package/dist/auth/legacy/db/index.mjs.map +1 -0
  26. package/dist/auth/legacy/index.d.mts +5 -0
  27. package/dist/auth/legacy/index.d.ts +5 -0
  28. package/dist/auth/legacy/index.js +1107 -0
  29. package/dist/auth/legacy/index.js.map +1 -0
  30. package/dist/auth/legacy/index.mjs +1086 -0
  31. package/dist/auth/legacy/index.mjs.map +1 -0
  32. package/dist/auth/legacy/logic/index.d.mts +9 -0
  33. package/dist/auth/legacy/logic/index.d.ts +9 -0
  34. package/dist/auth/legacy/logic/index.js +194 -0
  35. package/dist/auth/legacy/logic/index.js.map +1 -0
  36. package/dist/auth/legacy/logic/index.mjs +187 -0
  37. package/dist/auth/legacy/logic/index.mjs.map +1 -0
  38. package/dist/auth/legacy/miniapp/index.d.mts +5 -0
  39. package/dist/auth/legacy/miniapp/index.d.ts +5 -0
  40. package/dist/auth/legacy/miniapp/index.js +506 -0
  41. package/dist/auth/legacy/miniapp/index.js.map +1 -0
  42. package/dist/auth/legacy/miniapp/index.mjs +487 -0
  43. package/dist/auth/legacy/miniapp/index.mjs.map +1 -0
  44. package/dist/auth/legacy/routes/index.d.mts +53 -0
  45. package/dist/auth/legacy/routes/index.d.ts +53 -0
  46. package/dist/auth/legacy/routes/index.js +278 -0
  47. package/dist/auth/legacy/routes/index.js.map +1 -0
  48. package/dist/auth/legacy/routes/index.mjs +271 -0
  49. package/dist/auth/legacy/routes/index.mjs.map +1 -0
  50. package/dist/auth/legacy/schema/index.d.mts +401 -0
  51. package/dist/auth/legacy/schema/index.d.ts +401 -0
  52. package/dist/auth/legacy/schema/index.js +50 -0
  53. package/dist/auth/legacy/schema/index.js.map +1 -0
  54. package/dist/auth/legacy/schema/index.mjs +44 -0
  55. package/dist/auth/legacy/schema/index.mjs.map +1 -0
  56. package/dist/auth/legacy/server/index.d.mts +13 -0
  57. package/dist/auth/legacy/server/index.d.ts +13 -0
  58. package/dist/auth/legacy/server/index.js +21 -0
  59. package/dist/auth/legacy/server/index.js.map +1 -0
  60. package/dist/auth/legacy/server/index.mjs +19 -0
  61. package/dist/auth/legacy/server/index.mjs.map +1 -0
  62. package/dist/auth/legacy/services/index.d.mts +40 -0
  63. package/dist/auth/legacy/services/index.d.ts +40 -0
  64. package/dist/auth/legacy/services/index.js +258 -0
  65. package/dist/auth/legacy/services/index.js.map +1 -0
  66. package/dist/auth/legacy/services/index.mjs +252 -0
  67. package/dist/auth/legacy/services/index.mjs.map +1 -0
  68. package/dist/auth/legacy/ui/miniapp/index.d.mts +10 -0
  69. package/dist/auth/legacy/ui/miniapp/index.d.ts +10 -0
  70. package/dist/auth/legacy/ui/miniapp/index.js +298 -0
  71. package/dist/auth/legacy/ui/miniapp/index.js.map +1 -0
  72. package/dist/auth/legacy/ui/miniapp/index.mjs +290 -0
  73. package/dist/auth/legacy/ui/miniapp/index.mjs.map +1 -0
  74. package/dist/auth/legacy/ui/web/index.d.mts +22 -0
  75. package/dist/auth/legacy/ui/web/index.d.ts +22 -0
  76. package/dist/auth/legacy/ui/web/index.js +899 -0
  77. package/dist/auth/legacy/ui/web/index.js.map +1 -0
  78. package/dist/auth/legacy/ui/web/index.mjs +889 -0
  79. package/dist/auth/legacy/ui/web/index.mjs.map +1 -0
  80. package/dist/auth/legacy/web/index.d.mts +5 -0
  81. package/dist/auth/legacy/web/index.d.ts +5 -0
  82. package/dist/auth/legacy/web/index.js +1107 -0
  83. package/dist/auth/legacy/web/index.js.map +1 -0
  84. package/dist/auth/legacy/web/index.mjs +1086 -0
  85. package/dist/auth/legacy/web/index.mjs.map +1 -0
  86. package/dist/auth/rn/index.d.mts +64 -0
  87. package/dist/auth/rn/index.d.ts +64 -0
  88. package/dist/auth/rn/index.js +765 -0
  89. package/dist/auth/rn/index.js.map +1 -0
  90. package/dist/auth/rn/index.mjs +754 -0
  91. package/dist/auth/rn/index.mjs.map +1 -0
  92. package/dist/base-api-client-ACKKt13v.d.mts +277 -0
  93. package/dist/base-api-client-ACKKt13v.d.ts +277 -0
  94. package/dist/boothVaultService-Cn4WPhjg.d.mts +83 -0
  95. package/dist/boothVaultService-Cn4WPhjg.d.ts +83 -0
  96. package/dist/business/index.d.mts +6 -0
  97. package/dist/business/index.d.ts +6 -0
  98. package/dist/business/index.js +1682 -0
  99. package/dist/business/index.js.map +1 -0
  100. package/dist/business/index.mjs +1675 -0
  101. package/dist/business/index.mjs.map +1 -0
  102. package/dist/calendar/index.d.mts +1325 -0
  103. package/dist/calendar/index.d.ts +1325 -0
  104. package/dist/calendar/index.js +5964 -0
  105. package/dist/calendar/index.js.map +1 -0
  106. package/dist/calendar/index.mjs +5878 -0
  107. package/dist/calendar/index.mjs.map +1 -0
  108. package/dist/components/index.d.mts +405 -0
  109. package/dist/components/index.d.ts +405 -0
  110. package/dist/components/index.js +2516 -0
  111. package/dist/components/index.js.map +1 -0
  112. package/dist/components/index.mjs +2396 -0
  113. package/dist/components/index.mjs.map +1 -0
  114. package/dist/drizzle-schema-BNhqj2AZ.d.mts +1114 -0
  115. package/dist/drizzle-schema-BNhqj2AZ.d.ts +1114 -0
  116. package/dist/festivalCard/index.d.mts +75 -0
  117. package/dist/festivalCard/index.d.ts +75 -0
  118. package/dist/festivalCard/index.js +1492 -0
  119. package/dist/festivalCard/index.js.map +1 -0
  120. package/dist/festivalCard/index.mjs +1475 -0
  121. package/dist/festivalCard/index.mjs.map +1 -0
  122. package/dist/festivalCard/server/index.d.mts +120 -0
  123. package/dist/festivalCard/server/index.d.ts +120 -0
  124. package/dist/festivalCard/server/index.js +272 -0
  125. package/dist/festivalCard/server/index.js.map +1 -0
  126. package/dist/festivalCard/server/index.mjs +265 -0
  127. package/dist/festivalCard/server/index.mjs.map +1 -0
  128. package/dist/festivalCardService-CZomuQ4E.d.mts +80 -0
  129. package/dist/festivalCardService-CZomuQ4E.d.ts +80 -0
  130. package/dist/index-1Ag7IBXN.d.ts +144 -0
  131. package/dist/index-DNKZ7-R_.d.mts +184 -0
  132. package/dist/index-DNKZ7-R_.d.ts +184 -0
  133. package/dist/index-DSel44Ke.d.mts +93 -0
  134. package/dist/index-DSel44Ke.d.ts +93 -0
  135. package/dist/index-DdeZSeTJ.d.mts +144 -0
  136. package/dist/index-DrPcMJPc.d.mts +250 -0
  137. package/dist/index-DrPcMJPc.d.ts +250 -0
  138. package/dist/index.d.mts +5333 -0
  139. package/dist/index.d.ts +5333 -0
  140. package/dist/index.js +18809 -0
  141. package/dist/index.js.map +1 -0
  142. package/dist/index.mjs +18533 -0
  143. package/dist/index.mjs.map +1 -0
  144. package/dist/mikuContest/ui/web/index.d.mts +2 -0
  145. package/dist/mikuContest/ui/web/index.d.ts +2 -0
  146. package/dist/mikuContest/ui/web/index.js +353 -0
  147. package/dist/mikuContest/ui/web/index.js.map +1 -0
  148. package/dist/mikuContest/ui/web/index.mjs +343 -0
  149. package/dist/mikuContest/ui/web/index.mjs.map +1 -0
  150. package/dist/mikuFireworks3D/index.d.mts +268 -0
  151. package/dist/mikuFireworks3D/index.d.ts +268 -0
  152. package/dist/mikuFireworks3D/index.js +1267 -0
  153. package/dist/mikuFireworks3D/index.js.map +1 -0
  154. package/dist/mikuFireworks3D/index.mjs +1228 -0
  155. package/dist/mikuFireworks3D/index.mjs.map +1 -0
  156. package/dist/mikuFusionGame/index.d.mts +117 -0
  157. package/dist/mikuFusionGame/index.d.ts +117 -0
  158. package/dist/mikuFusionGame/index.js +1208 -0
  159. package/dist/mikuFusionGame/index.js.map +1 -0
  160. package/dist/mikuFusionGame/index.mjs +1195 -0
  161. package/dist/mikuFusionGame/index.mjs.map +1 -0
  162. package/dist/mmd/admin/index.d.mts +487 -0
  163. package/dist/mmd/admin/index.d.ts +487 -0
  164. package/dist/mmd/admin/index.js +1058 -0
  165. package/dist/mmd/admin/index.js.map +1 -0
  166. package/dist/mmd/admin/index.mjs +1027 -0
  167. package/dist/mmd/admin/index.mjs.map +1 -0
  168. package/dist/mmd/index.d.mts +2467 -0
  169. package/dist/mmd/index.d.ts +2467 -0
  170. package/dist/mmd/index.js +10119 -0
  171. package/dist/mmd/index.js.map +1 -0
  172. package/dist/mmd/index.mjs +10028 -0
  173. package/dist/mmd/index.mjs.map +1 -0
  174. package/dist/mmd/server/index.d.mts +139 -0
  175. package/dist/mmd/server/index.d.ts +139 -0
  176. package/dist/mmd/server/index.js +424 -0
  177. package/dist/mmd/server/index.js.map +1 -0
  178. package/dist/mmd/server/index.mjs +404 -0
  179. package/dist/mmd/server/index.mjs.map +1 -0
  180. package/dist/music/index.d.mts +74 -0
  181. package/dist/music/index.d.ts +74 -0
  182. package/dist/music/index.js +830 -0
  183. package/dist/music/index.js.map +1 -0
  184. package/dist/music/index.mjs +809 -0
  185. package/dist/music/index.mjs.map +1 -0
  186. package/dist/music/server/index.d.mts +1 -0
  187. package/dist/music/server/index.d.ts +1 -0
  188. package/dist/music/server/index.js +194 -0
  189. package/dist/music/server/index.js.map +1 -0
  190. package/dist/music/server/index.mjs +182 -0
  191. package/dist/music/server/index.mjs.map +1 -0
  192. package/dist/navigation/index.d.mts +93 -0
  193. package/dist/navigation/index.d.ts +93 -0
  194. package/dist/navigation/index.js +453 -0
  195. package/dist/navigation/index.js.map +1 -0
  196. package/dist/navigation/index.mjs +443 -0
  197. package/dist/navigation/index.mjs.map +1 -0
  198. package/dist/portfolio/index.d.mts +66 -0
  199. package/dist/portfolio/index.d.ts +66 -0
  200. package/dist/portfolio/index.js +736 -0
  201. package/dist/portfolio/index.js.map +1 -0
  202. package/dist/portfolio/index.mjs +724 -0
  203. package/dist/portfolio/index.mjs.map +1 -0
  204. package/dist/qqbot/server/index.d.mts +216 -0
  205. package/dist/qqbot/server/index.d.ts +216 -0
  206. package/dist/qqbot/server/index.js +394 -0
  207. package/dist/qqbot/server/index.js.map +1 -0
  208. package/dist/qqbot/server/index.mjs +385 -0
  209. package/dist/qqbot/server/index.mjs.map +1 -0
  210. package/dist/qqbot/ui/web/index.d.mts +10 -0
  211. package/dist/qqbot/ui/web/index.d.ts +10 -0
  212. package/dist/qqbot/ui/web/index.js +105 -0
  213. package/dist/qqbot/ui/web/index.js.map +1 -0
  214. package/dist/qqbot/ui/web/index.mjs +99 -0
  215. package/dist/qqbot/ui/web/index.mjs.map +1 -0
  216. package/dist/screenReceiver/index.d.mts +86 -0
  217. package/dist/screenReceiver/index.d.ts +86 -0
  218. package/dist/screenReceiver/index.js +281 -0
  219. package/dist/screenReceiver/index.js.map +1 -0
  220. package/dist/screenReceiver/index.mjs +273 -0
  221. package/dist/screenReceiver/index.mjs.map +1 -0
  222. package/dist/testYourself/admin/index.d.mts +58 -0
  223. package/dist/testYourself/admin/index.d.ts +58 -0
  224. package/dist/testYourself/admin/index.js +1009 -0
  225. package/dist/testYourself/admin/index.js.map +1 -0
  226. package/dist/testYourself/admin/index.mjs +1002 -0
  227. package/dist/testYourself/admin/index.mjs.map +1 -0
  228. package/dist/testYourself/index.d.mts +53 -0
  229. package/dist/testYourself/index.d.ts +53 -0
  230. package/dist/testYourself/index.js +2551 -0
  231. package/dist/testYourself/index.js.map +1 -0
  232. package/dist/testYourself/index.mjs +2531 -0
  233. package/dist/testYourself/index.mjs.map +1 -0
  234. package/dist/testYourself/server/index.d.mts +1029 -0
  235. package/dist/testYourself/server/index.d.ts +1029 -0
  236. package/dist/testYourself/server/index.js +825 -0
  237. package/dist/testYourself/server/index.js.map +1 -0
  238. package/dist/testYourself/server/index.mjs +816 -0
  239. package/dist/testYourself/server/index.mjs.map +1 -0
  240. package/dist/types-BTiaMsBz.d.mts +292 -0
  241. package/dist/types-DyG3ZV9V.d.mts +270 -0
  242. package/dist/types-DyG3ZV9V.d.ts +270 -0
  243. package/dist/types-ERmJyjx8.d.ts +292 -0
  244. package/dist/types-HorDyIRv.d.mts +303 -0
  245. package/dist/types-HorDyIRv.d.ts +303 -0
  246. package/dist/vocaloidBooth/index.d.mts +64 -0
  247. package/dist/vocaloidBooth/index.d.ts +64 -0
  248. package/dist/vocaloidBooth/index.js +376 -0
  249. package/dist/vocaloidBooth/index.js.map +1 -0
  250. package/dist/vocaloidBooth/index.mjs +362 -0
  251. package/dist/vocaloidBooth/index.mjs.map +1 -0
  252. package/dist/vocaloidBooth/server/index.d.mts +111 -0
  253. package/dist/vocaloidBooth/server/index.d.ts +111 -0
  254. package/dist/vocaloidBooth/server/index.js +247 -0
  255. package/dist/vocaloidBooth/server/index.js.map +1 -0
  256. package/dist/vocaloidBooth/server/index.mjs +237 -0
  257. package/dist/vocaloidBooth/server/index.mjs.map +1 -0
  258. package/dist/vocaloidBooth/web/index.d.mts +3 -0
  259. package/dist/vocaloidBooth/web/index.d.ts +3 -0
  260. package/dist/vocaloidBooth/web/index.js +376 -0
  261. package/dist/vocaloidBooth/web/index.js.map +1 -0
  262. package/dist/vocaloidBooth/web/index.mjs +362 -0
  263. package/dist/vocaloidBooth/web/index.mjs.map +1 -0
  264. package/package.json +1 -1
@@ -0,0 +1,809 @@
1
+ import React, { useState, useRef, useEffect, useCallback, useMemo } from 'react';
2
+ import { clsx } from 'clsx';
3
+ import useSWR from 'swr';
4
+ import Meting from '@meting/core';
5
+
6
+ // src/music/components/MusicPlayer.tsx
7
+ function MusicPlayer({
8
+ track,
9
+ onPlay,
10
+ onPause,
11
+ onStop,
12
+ onVolumeChange,
13
+ onSeek,
14
+ initialVolume = 0.7,
15
+ className = "",
16
+ compact = false,
17
+ ultraCompact = false,
18
+ hideVolumeControl = false,
19
+ showTrackInfo = true,
20
+ isPlaying,
21
+ currentTime,
22
+ duration,
23
+ externalVolume
24
+ }) {
25
+ const [volume, setVolume] = useState(externalVolume ?? initialVolume);
26
+ const [isLoading, setIsLoading] = useState(false);
27
+ const [error, setError] = useState();
28
+ const progressRef = useRef(null);
29
+ const volumeRef = useRef(null);
30
+ const [isDraggingProgress, setIsDraggingProgress] = useState(false);
31
+ const [isDraggingVolume, setIsDraggingVolume] = useState(false);
32
+ useEffect(() => {
33
+ if (externalVolume !== void 0) {
34
+ setVolume(externalVolume);
35
+ }
36
+ }, [externalVolume]);
37
+ const formatTime = (seconds) => {
38
+ if (!seconds || isNaN(seconds)) return "0:00";
39
+ const mins = Math.floor(seconds / 60);
40
+ const secs = Math.floor(seconds % 60);
41
+ return mins + ":" + secs.toString().padStart(2, "0");
42
+ };
43
+ const handlePlay = useCallback(() => {
44
+ onPlay?.();
45
+ }, [onPlay]);
46
+ const handlePause = useCallback(() => {
47
+ onPause?.();
48
+ }, [onPause]);
49
+ const handleStop = useCallback(() => {
50
+ onStop?.();
51
+ }, [onStop]);
52
+ const handleVolumeChange = useCallback((newVolume) => {
53
+ const clampedVolume = Math.max(0, Math.min(1, newVolume));
54
+ setVolume(clampedVolume);
55
+ onVolumeChange?.(clampedVolume);
56
+ }, [onVolumeChange]);
57
+ const handleSeek = useCallback((time) => {
58
+ if (!duration || isNaN(duration)) return;
59
+ const seekTime = Math.max(0, Math.min(duration, time));
60
+ onSeek?.(seekTime);
61
+ }, [duration, onSeek]);
62
+ const handleProgressMouseDown = useCallback((e) => {
63
+ if (!progressRef.current || !duration) return;
64
+ setIsDraggingProgress(true);
65
+ const rect = progressRef.current.getBoundingClientRect();
66
+ const percent = (e.clientX - rect.left) / rect.width;
67
+ const time = percent * duration;
68
+ handleSeek(time);
69
+ }, [duration, handleSeek]);
70
+ const handleVolumeMouseDown = useCallback((e) => {
71
+ if (!volumeRef.current) return;
72
+ setIsDraggingVolume(true);
73
+ const rect = volumeRef.current.getBoundingClientRect();
74
+ const percent = (e.clientX - rect.left) / rect.width;
75
+ handleVolumeChange(percent);
76
+ }, [handleVolumeChange]);
77
+ useEffect(() => {
78
+ const handleMouseMove = (e) => {
79
+ if (isDraggingProgress && progressRef.current && duration) {
80
+ const rect = progressRef.current.getBoundingClientRect();
81
+ const percent = Math.max(0, Math.min(1, (e.clientX - rect.left) / rect.width));
82
+ const time = percent * duration;
83
+ handleSeek(time);
84
+ }
85
+ if (isDraggingVolume && volumeRef.current) {
86
+ const rect = volumeRef.current.getBoundingClientRect();
87
+ const percent = Math.max(0, Math.min(1, (e.clientX - rect.left) / rect.width));
88
+ handleVolumeChange(percent);
89
+ }
90
+ };
91
+ const handleMouseUp = () => {
92
+ setIsDraggingProgress(false);
93
+ setIsDraggingVolume(false);
94
+ };
95
+ if (isDraggingProgress || isDraggingVolume) {
96
+ document.addEventListener("mousemove", handleMouseMove);
97
+ document.addEventListener("mouseup", handleMouseUp);
98
+ }
99
+ return () => {
100
+ document.removeEventListener("mousemove", handleMouseMove);
101
+ document.removeEventListener("mouseup", handleMouseUp);
102
+ };
103
+ }, [isDraggingProgress, isDraggingVolume, duration, handleSeek, handleVolumeChange]);
104
+ const stopPropagation = useCallback((e) => {
105
+ e.preventDefault();
106
+ e.stopPropagation();
107
+ }, []);
108
+ if (ultraCompact) {
109
+ return /* @__PURE__ */ React.createElement(
110
+ "div",
111
+ {
112
+ className: clsx("flex items-center gap-2 bg-white/90 backdrop-blur-sm rounded-xl p-2 shadow-lg border border-purple-200", className),
113
+ style: { width: hideVolumeControl ? "120px" : "192px" },
114
+ onClick: stopPropagation,
115
+ onMouseDown: stopPropagation,
116
+ onMouseUp: stopPropagation,
117
+ onTouchStart: stopPropagation,
118
+ onTouchEnd: stopPropagation,
119
+ onPointerDown: stopPropagation,
120
+ onPointerUp: stopPropagation
121
+ },
122
+ /* @__PURE__ */ React.createElement("div", { className: clsx("flex items-center gap-1", hideVolumeControl ? "w-full justify-center" : "") }, /* @__PURE__ */ React.createElement(
123
+ "button",
124
+ {
125
+ onClick: (e) => {
126
+ stopPropagation(e);
127
+ handleStop();
128
+ },
129
+ onMouseDown: stopPropagation,
130
+ onMouseUp: stopPropagation,
131
+ onTouchStart: stopPropagation,
132
+ onTouchEnd: stopPropagation,
133
+ onPointerDown: stopPropagation,
134
+ onPointerUp: stopPropagation,
135
+ className: "w-7 h-7 rounded-lg bg-gray-100 hover:bg-gray-200 border border-gray-300 flex items-center justify-center transition-colors",
136
+ title: "\u505C\u6B62"
137
+ },
138
+ /* @__PURE__ */ React.createElement("div", { className: "w-2.5 h-2.5 bg-gray-600 rounded-sm" })
139
+ ), /* @__PURE__ */ React.createElement(
140
+ "button",
141
+ {
142
+ onClick: (e) => {
143
+ stopPropagation(e);
144
+ isPlaying ? handlePause() : handlePlay();
145
+ },
146
+ onMouseDown: stopPropagation,
147
+ onMouseUp: stopPropagation,
148
+ onTouchStart: stopPropagation,
149
+ onTouchEnd: stopPropagation,
150
+ onPointerDown: stopPropagation,
151
+ onPointerUp: stopPropagation,
152
+ className: clsx("w-8 h-8 rounded-lg border flex items-center justify-center transition-colors", isPlaying ? "bg-gradient-to-r from-purple-500 to-pink-500 hover:from-purple-600 hover:to-pink-600 text-white border-purple-400" : "bg-gradient-to-r from-green-500 to-blue-500 hover:from-green-600 hover:to-blue-600 text-white border-green-400 cursor-pointer"),
153
+ title: isPlaying ? "\u6682\u505C" : "\u64AD\u653E"
154
+ },
155
+ isPlaying ? /* @__PURE__ */ React.createElement("div", { className: "flex gap-0.5" }, /* @__PURE__ */ React.createElement("div", { className: "w-1 h-3 bg-white rounded-sm" }), /* @__PURE__ */ React.createElement("div", { className: "w-1 h-3 bg-white rounded-sm" })) : /* @__PURE__ */ React.createElement("div", { className: "w-0 h-0 border-l-[6px] border-l-white border-t-[4px] border-t-transparent border-b-[4px] border-b-transparent ml-0.5" })
156
+ )),
157
+ !hideVolumeControl && /* @__PURE__ */ React.createElement("div", { className: "flex items-center gap-1 flex-1" }, /* @__PURE__ */ React.createElement("div", { className: "text-gray-500 text-xs" }, "\u{1F50A}"), /* @__PURE__ */ React.createElement(
158
+ "div",
159
+ {
160
+ ref: volumeRef,
161
+ className: "flex-1 h-2 bg-gray-200 rounded-full cursor-pointer relative",
162
+ onMouseDown: handleVolumeMouseDown,
163
+ onClick: stopPropagation,
164
+ onTouchStart: stopPropagation,
165
+ onTouchEnd: stopPropagation,
166
+ onPointerDown: stopPropagation,
167
+ onPointerUp: stopPropagation
168
+ },
169
+ /* @__PURE__ */ React.createElement(
170
+ "div",
171
+ {
172
+ className: "h-full bg-gradient-to-r from-purple-400 to-pink-400 rounded-full",
173
+ style: { width: volume * 100 + "%" }
174
+ }
175
+ ),
176
+ /* @__PURE__ */ React.createElement(
177
+ "div",
178
+ {
179
+ className: "absolute top-1/2 w-3 h-3 bg-white border-2 border-purple-400 rounded-full transform -translate-y-1/2 cursor-grab",
180
+ style: { left: volume * 100 + "%", transform: "translateX(-50%) translateY(-50%)" }
181
+ }
182
+ )
183
+ ))
184
+ );
185
+ }
186
+ return /* @__PURE__ */ React.createElement(
187
+ "div",
188
+ {
189
+ className: clsx("bg-white/90 backdrop-blur-sm rounded-xl p-4 shadow-lg border border-purple-200", className),
190
+ style: { width: compact ? "280px" : "320px" },
191
+ onClick: stopPropagation,
192
+ onMouseDown: stopPropagation,
193
+ onMouseUp: stopPropagation,
194
+ onTouchStart: stopPropagation,
195
+ onTouchEnd: stopPropagation,
196
+ onPointerDown: stopPropagation,
197
+ onPointerUp: stopPropagation
198
+ },
199
+ !compact && showTrackInfo && track && /* @__PURE__ */ React.createElement("div", { className: "mb-3" }, /* @__PURE__ */ React.createElement("h3", { className: "text-sm font-medium text-gray-800 truncate" }, track.name), /* @__PURE__ */ React.createElement("p", { className: "text-xs text-gray-500" }, "\u80CC\u666F\u97F3\u4E50")),
200
+ !compact && /* @__PURE__ */ React.createElement("div", { className: "mb-3" }, /* @__PURE__ */ React.createElement(
201
+ "div",
202
+ {
203
+ ref: progressRef,
204
+ className: "w-full h-2 bg-gray-200 rounded-full cursor-pointer relative",
205
+ onMouseDown: handleProgressMouseDown,
206
+ onClick: stopPropagation,
207
+ onTouchStart: stopPropagation,
208
+ onTouchEnd: stopPropagation,
209
+ onPointerDown: stopPropagation,
210
+ onPointerUp: stopPropagation
211
+ },
212
+ /* @__PURE__ */ React.createElement(
213
+ "div",
214
+ {
215
+ className: "h-full bg-gradient-to-r from-purple-400 to-pink-400 rounded-full transition-all duration-100",
216
+ style: { width: duration > 0 ? currentTime / duration * 100 + "%" : "0%" }
217
+ }
218
+ ),
219
+ /* @__PURE__ */ React.createElement(
220
+ "div",
221
+ {
222
+ className: "absolute top-1/2 w-4 h-4 bg-white border-2 border-purple-400 rounded-full transform -translate-y-1/2 cursor-grab",
223
+ style: {
224
+ left: duration > 0 ? currentTime / duration * 100 + "%" : "0%",
225
+ transform: "translateX(-50%) translateY(-50%)"
226
+ }
227
+ }
228
+ )
229
+ ), /* @__PURE__ */ React.createElement("div", { className: "flex justify-between text-xs text-gray-500 mt-1" }, /* @__PURE__ */ React.createElement("span", null, formatTime(currentTime)), /* @__PURE__ */ React.createElement("span", null, formatTime(duration)))),
230
+ /* @__PURE__ */ React.createElement("div", { className: "flex items-center justify-center gap-3 mb-3" }, /* @__PURE__ */ React.createElement(
231
+ "button",
232
+ {
233
+ onClick: (e) => {
234
+ stopPropagation(e);
235
+ handleStop();
236
+ },
237
+ onMouseDown: stopPropagation,
238
+ onMouseUp: stopPropagation,
239
+ onTouchStart: stopPropagation,
240
+ onTouchEnd: stopPropagation,
241
+ onPointerDown: stopPropagation,
242
+ onPointerUp: stopPropagation,
243
+ className: "w-10 h-10 rounded-full bg-gray-100 hover:bg-gray-200 border border-gray-300 flex items-center justify-center transition-colors",
244
+ title: "\u505C\u6B62"
245
+ },
246
+ /* @__PURE__ */ React.createElement("div", { className: "w-4 h-4 bg-gray-600 rounded-sm" })
247
+ ), /* @__PURE__ */ React.createElement(
248
+ "button",
249
+ {
250
+ onClick: (e) => {
251
+ stopPropagation(e);
252
+ isPlaying ? handlePause() : handlePlay();
253
+ },
254
+ onMouseDown: stopPropagation,
255
+ onMouseUp: stopPropagation,
256
+ onTouchStart: stopPropagation,
257
+ onTouchEnd: stopPropagation,
258
+ onPointerDown: stopPropagation,
259
+ onPointerUp: stopPropagation,
260
+ className: clsx("w-12 h-12 rounded-full border-2 flex items-center justify-center transition-colors", isPlaying ? "bg-gradient-to-r from-purple-500 to-pink-500 hover:from-purple-600 hover:to-pink-600 text-white border-purple-400" : "bg-gradient-to-r from-green-500 to-blue-500 hover:from-green-600 hover:to-blue-600 text-white border-green-400 cursor-pointer"),
261
+ title: isPlaying ? "\u6682\u505C" : "\u64AD\u653E"
262
+ },
263
+ isLoading ? /* @__PURE__ */ React.createElement("div", { className: "w-5 h-5 border-2 border-white border-t-transparent rounded-full animate-spin" }) : isPlaying ? /* @__PURE__ */ React.createElement("div", { className: "flex gap-1" }, /* @__PURE__ */ React.createElement("div", { className: "w-1.5 h-4 bg-white rounded-sm" }), /* @__PURE__ */ React.createElement("div", { className: "w-1.5 h-4 bg-white rounded-sm" })) : /* @__PURE__ */ React.createElement("div", { className: "w-0 h-0 border-l-[10px] border-l-white border-t-[7px] border-t-transparent border-b-[7px] border-b-transparent ml-1" })
264
+ )),
265
+ !hideVolumeControl && /* @__PURE__ */ React.createElement("div", { className: "flex items-center gap-3" }, /* @__PURE__ */ React.createElement("div", { className: "text-gray-500 text-sm" }, "\u{1F50A}"), /* @__PURE__ */ React.createElement(
266
+ "div",
267
+ {
268
+ ref: volumeRef,
269
+ className: "flex-1 h-2 bg-gray-200 rounded-full cursor-pointer relative",
270
+ onMouseDown: handleVolumeMouseDown,
271
+ onClick: stopPropagation,
272
+ onTouchStart: stopPropagation,
273
+ onTouchEnd: stopPropagation,
274
+ onPointerDown: stopPropagation,
275
+ onPointerUp: stopPropagation
276
+ },
277
+ /* @__PURE__ */ React.createElement(
278
+ "div",
279
+ {
280
+ className: "h-full bg-gradient-to-r from-purple-400 to-pink-400 rounded-full",
281
+ style: { width: volume * 100 + "%" }
282
+ }
283
+ ),
284
+ /* @__PURE__ */ React.createElement(
285
+ "div",
286
+ {
287
+ className: "absolute top-1/2 w-4 h-4 bg-white border-2 border-purple-400 rounded-full transform -translate-y-1/2 cursor-grab",
288
+ style: { left: volume * 100 + "%", transform: "translateX(-50%) translateY(-50%)" }
289
+ }
290
+ )
291
+ ), /* @__PURE__ */ React.createElement("div", { className: "text-xs text-gray-500 w-8 text-right" }, Math.round(volume * 100), "%")),
292
+ error && /* @__PURE__ */ React.createElement("div", { className: "mt-2 text-xs text-red-500" }, error)
293
+ );
294
+ }
295
+ function MikutapMusicPlayer({
296
+ track,
297
+ onPlay,
298
+ onPause,
299
+ onSeek,
300
+ className = "",
301
+ isPlaying,
302
+ currentTime,
303
+ duration
304
+ }) {
305
+ const progressRef = useRef(null);
306
+ const [isDraggingProgress, setIsDraggingProgress] = useState(false);
307
+ const formatTime = (seconds) => {
308
+ if (!seconds || isNaN(seconds)) return "0:00";
309
+ const mins = Math.floor(seconds / 60);
310
+ const secs = Math.floor(seconds % 60);
311
+ return mins + ":" + secs.toString().padStart(2, "0");
312
+ };
313
+ const handlePlay = useCallback(() => {
314
+ onPlay?.();
315
+ }, [onPlay]);
316
+ const handlePause = useCallback(() => {
317
+ onPause?.();
318
+ }, [onPause]);
319
+ const handleSeek = useCallback((time) => {
320
+ if (!duration || isNaN(duration)) return;
321
+ const seekTime = Math.max(0, Math.min(duration, time));
322
+ onSeek?.(seekTime);
323
+ }, [duration, onSeek]);
324
+ const handleProgressMouseDown = useCallback((e) => {
325
+ if (!progressRef.current || !duration) return;
326
+ setIsDraggingProgress(true);
327
+ const rect = progressRef.current.getBoundingClientRect();
328
+ const percent = (e.clientX - rect.left) / rect.width;
329
+ const time = percent * duration;
330
+ handleSeek(time);
331
+ }, [duration, handleSeek]);
332
+ useEffect(() => {
333
+ const handleMouseMove = (e) => {
334
+ if (isDraggingProgress && progressRef.current && duration) {
335
+ const rect = progressRef.current.getBoundingClientRect();
336
+ const percent = Math.max(0, Math.min(1, (e.clientX - rect.left) / rect.width));
337
+ const time = percent * duration;
338
+ handleSeek(time);
339
+ }
340
+ };
341
+ const handleMouseUp = () => {
342
+ setIsDraggingProgress(false);
343
+ };
344
+ if (isDraggingProgress) {
345
+ document.addEventListener("mousemove", handleMouseMove);
346
+ document.addEventListener("mouseup", handleMouseUp);
347
+ }
348
+ return () => {
349
+ document.removeEventListener("mousemove", handleMouseMove);
350
+ document.removeEventListener("mouseup", handleMouseUp);
351
+ };
352
+ }, [isDraggingProgress, duration, handleSeek]);
353
+ const stopPropagation = useCallback((e) => {
354
+ e.preventDefault();
355
+ e.stopPropagation();
356
+ }, []);
357
+ return /* @__PURE__ */ React.createElement(
358
+ "div",
359
+ {
360
+ className: clsx("bg-gradient-to-r from-purple-900/95 to-pink-900/95 backdrop-blur-sm rounded-2xl p-4 shadow-2xl border border-purple-300/30", className),
361
+ style: { width: "200px" },
362
+ onClick: stopPropagation,
363
+ onMouseDown: stopPropagation,
364
+ onMouseUp: stopPropagation,
365
+ onTouchStart: stopPropagation,
366
+ onTouchEnd: stopPropagation,
367
+ onPointerDown: stopPropagation,
368
+ onPointerUp: stopPropagation
369
+ },
370
+ track && /* @__PURE__ */ React.createElement("div", { className: "mb-3 text-center" }, /* @__PURE__ */ React.createElement("div", { className: "text-white text-sm font-medium truncate mb-1" }, track.name), /* @__PURE__ */ React.createElement("div", { className: "text-purple-200 text-xs" }, "\u80CC\u666F\u97F3\u4E50")),
371
+ /* @__PURE__ */ React.createElement("div", { className: "flex justify-center mb-3" }, /* @__PURE__ */ React.createElement(
372
+ "button",
373
+ {
374
+ onClick: (e) => {
375
+ stopPropagation(e);
376
+ isPlaying ? handlePause() : handlePlay();
377
+ },
378
+ onMouseDown: stopPropagation,
379
+ onMouseUp: stopPropagation,
380
+ onTouchStart: stopPropagation,
381
+ onTouchEnd: stopPropagation,
382
+ onPointerDown: stopPropagation,
383
+ onPointerUp: stopPropagation,
384
+ className: clsx("w-12 h-12 rounded-full border-2 flex items-center justify-center transition-all duration-300 shadow-lg hover:scale-105", isPlaying ? "bg-gradient-to-r from-orange-400 to-red-500 hover:from-orange-500 hover:to-red-600 text-white border-orange-300 shadow-orange-500/50" : "bg-gradient-to-r from-green-400 to-emerald-500 hover:from-green-500 hover:to-emerald-600 text-white border-green-300 shadow-green-500/50"),
385
+ title: isPlaying ? "\u6682\u505C" : "\u64AD\u653E"
386
+ },
387
+ isPlaying ? /* @__PURE__ */ React.createElement("div", { className: "flex gap-1" }, /* @__PURE__ */ React.createElement("div", { className: "w-1.5 h-4 bg-white rounded-sm" }), /* @__PURE__ */ React.createElement("div", { className: "w-1.5 h-4 bg-white rounded-sm" })) : /* @__PURE__ */ React.createElement("div", { className: "w-0 h-0 border-l-[10px] border-l-white border-t-[7px] border-t-transparent border-b-[7px] border-b-transparent ml-1" })
388
+ )),
389
+ /* @__PURE__ */ React.createElement("div", { className: "mb-2" }, /* @__PURE__ */ React.createElement(
390
+ "div",
391
+ {
392
+ ref: progressRef,
393
+ className: "w-full h-2 bg-white/20 rounded-full cursor-pointer relative overflow-hidden",
394
+ onMouseDown: handleProgressMouseDown,
395
+ onClick: stopPropagation,
396
+ onTouchStart: stopPropagation,
397
+ onTouchEnd: stopPropagation,
398
+ onPointerDown: stopPropagation,
399
+ onPointerUp: stopPropagation
400
+ },
401
+ /* @__PURE__ */ React.createElement(
402
+ "div",
403
+ {
404
+ className: "h-full bg-gradient-to-r from-cyan-400 to-blue-500 rounded-full transition-all duration-100 shadow-sm",
405
+ style: { width: duration > 0 ? currentTime / duration * 100 + "%" : "0%" }
406
+ }
407
+ ),
408
+ /* @__PURE__ */ React.createElement(
409
+ "div",
410
+ {
411
+ className: "absolute top-1/2 w-3 h-3 bg-white border-2 border-cyan-400 rounded-full transform -translate-y-1/2 cursor-grab shadow-lg",
412
+ style: {
413
+ left: duration > 0 ? currentTime / duration * 100 + "%" : "0%",
414
+ transform: "translateX(-50%) translateY(-50%)"
415
+ }
416
+ }
417
+ )
418
+ ), /* @__PURE__ */ React.createElement("div", { className: "flex justify-between text-xs text-purple-200 mt-1" }, /* @__PURE__ */ React.createElement("span", null, formatTime(currentTime)), /* @__PURE__ */ React.createElement("span", null, formatTime(duration)))),
419
+ /* @__PURE__ */ React.createElement("div", { className: "flex justify-center" }, /* @__PURE__ */ React.createElement("div", { className: clsx("flex items-center gap-2 text-xs px-3 py-1 rounded-full transition-all duration-300", isPlaying ? "bg-orange-500/20 text-orange-200 border border-orange-400/30" : "bg-gray-500/20 text-gray-300 border border-gray-400/30") }, /* @__PURE__ */ React.createElement("div", { className: clsx("w-2 h-2 rounded-full transition-all duration-300", isPlaying ? "bg-orange-400 animate-pulse" : "bg-gray-400") }), /* @__PURE__ */ React.createElement("span", null, isPlaying ? "\u64AD\u653E\u4E2D" : "\u5DF2\u6682\u505C")))
420
+ );
421
+ }
422
+
423
+ // src/music/constants.ts
424
+ var DEFAULT_MUSIC_SOURCE = "kugou";
425
+
426
+ // src/music/adapters/kugou.ts
427
+ var kugouAdapter = {
428
+ parseSearchResult(data) {
429
+ const root = typeof data === "string" ? JSON.parse(data) : data;
430
+ const info = root.data?.data?.info || root.data?.info || root.info || [];
431
+ const total = root.data?.data?.total || root.data?.total || info.length;
432
+ return {
433
+ tracks: info.map((item) => {
434
+ let pic = item.pic || "";
435
+ if (item.trans_param?.union_cover) {
436
+ pic = item.trans_param.union_cover.replace("{size}", "400");
437
+ }
438
+ return {
439
+ id: item.hash || item.id,
440
+ name: item.songname || item.filename || "Unknown",
441
+ artist: item.singername || "Unknown Artist",
442
+ album: item.album_name || item.album || "",
443
+ pic,
444
+ url: item.url,
445
+ lrc: item.lrc,
446
+ source: "kugou",
447
+ isVip: item.privilege >= 8,
448
+ playable: item.status !== 0
449
+ };
450
+ }),
451
+ total
452
+ };
453
+ },
454
+ parseGetSongUrl(data) {
455
+ return data.url?.url || data.url?.backup_url?.[0] || null;
456
+ },
457
+ parseGetLyric(data) {
458
+ const root = typeof data === "string" ? JSON.parse(data) : data;
459
+ return root.lyric || root.lrc || root.data?.lyric || root.data || "";
460
+ }
461
+ };
462
+
463
+ // src/music/adapters/netease.ts
464
+ var neteaseAdapter = {
465
+ parseSearchResult(data) {
466
+ const root = typeof data === "string" ? JSON.parse(data) : data;
467
+ const songs = root.result?.songs || root.songs || (Array.isArray(root) ? root : []);
468
+ return {
469
+ tracks: songs.map((item) => ({
470
+ id: item.id,
471
+ name: item.name,
472
+ artist: Array.isArray(item.artist) ? item.artist.join(", ") : item.artist,
473
+ album: item.album?.name || item.album,
474
+ pic: item.pic || item.album?.picUrl,
475
+ url: item.url,
476
+ lrc: item.lrc,
477
+ source: "netease",
478
+ isVip: item.fee === 1 || item.fee === 4,
479
+ playable: item.noCopyrightRcmd === null
480
+ })),
481
+ total: root.result?.songCount || songs.length
482
+ };
483
+ },
484
+ parseGetSongUrl(data) {
485
+ const root = typeof data === "string" ? JSON.parse(data) : data;
486
+ const item = root.data?.[0] || root[0] || root;
487
+ return item.url || null;
488
+ },
489
+ parseGetLyric(data) {
490
+ const root = typeof data === "string" ? JSON.parse(data) : data;
491
+ return root.lyric || root.lrc || root.data?.lyric || "";
492
+ }
493
+ };
494
+
495
+ // src/music/adapters/tencent.ts
496
+ var tencentAdapter = {
497
+ parseSearchResult(data) {
498
+ const root = typeof data === "string" ? JSON.parse(data) : data;
499
+ const songData = root.data?.data?.song || root.data?.song || root.data || root;
500
+ const list = songData.list || root.songs || [];
501
+ const total = songData.totalnum || root.total || list.length;
502
+ return {
503
+ tracks: list.map((item) => {
504
+ const artist = Array.isArray(item.singer) ? item.singer.map((s) => s.name).join(", ") : item.singer?.[0]?.name || item.artist || "Unknown";
505
+ let pic = item.pic;
506
+ if (!pic && item.album?.mid) {
507
+ pic = "https://y.gtimg.cn/music/photo_new/T002R300x300M000" + item.album.mid + ".jpg";
508
+ }
509
+ return {
510
+ id: item.mid || item.id || item.songid,
511
+ name: item.name || item.title || item.songname,
512
+ artist,
513
+ album: item.album?.name || item.albumname || item.album,
514
+ pic: pic || "",
515
+ url: item.url,
516
+ lrc: item.lrc,
517
+ source: "tencent",
518
+ isVip: item.pay?.pay_play === 1,
519
+ playable: item.action?.switch !== 0
520
+ };
521
+ }),
522
+ total
523
+ };
524
+ },
525
+ parseGetSongUrl(data) {
526
+ const root = data;
527
+ const urlData = root.url.url;
528
+ let finalUrl = Object.values(urlData)[0];
529
+ console.log("finalUrl2", finalUrl);
530
+ return finalUrl.startsWith("http") ? finalUrl : "http://" + finalUrl;
531
+ },
532
+ parseGetLyric(data) {
533
+ const root = typeof data === "string" ? JSON.parse(data) : data;
534
+ return root.lyric || root.lrc || root.data?.lyric || "";
535
+ }
536
+ };
537
+
538
+ // src/music/adapters/xiami.ts
539
+ var xiamiAdapter = {
540
+ parseSearchResult(data) {
541
+ const root = typeof data === "string" ? JSON.parse(data) : data;
542
+ const result = root.data?.result || root.result || root;
543
+ const songs = result.songs || (Array.isArray(root) ? root : []);
544
+ return {
545
+ tracks: songs.map((item) => ({
546
+ id: item.id?.toString() || "",
547
+ name: item.name || "Unknown",
548
+ artist: Array.isArray(item.ar) ? item.ar.map((a) => a.name).join(", ") : item.artist || "Unknown Artist",
549
+ album: item.al?.name || item.album || "",
550
+ pic: item.al?.picUrl || item.pic || "",
551
+ url: item.url,
552
+ lrc: item.lrc,
553
+ source: "xiami",
554
+ // 这里的逻辑参考提供的数据结构
555
+ isVip: item.fee === 1 || item.fee === 8,
556
+ playable: item.copyright !== 0
557
+ })),
558
+ total: result.songCount || songs.length
559
+ };
560
+ },
561
+ parseGetSongUrl(data) {
562
+ const root = typeof data === "string" ? JSON.parse(data) : data;
563
+ const item = root.data?.[0] || root.data || root[0] || root;
564
+ return item.url || null;
565
+ },
566
+ parseGetLyric(data) {
567
+ const root = typeof data === "string" ? JSON.parse(data) : data;
568
+ return root.lyric || root.lrc || root.data?.lyric || root.data || "";
569
+ }
570
+ };
571
+
572
+ // src/music/hooks/useMusic.ts
573
+ var fetcher = (url) => fetch(url).then((res) => res.json());
574
+ var ADAPTERS = {
575
+ kugou: kugouAdapter,
576
+ netease: neteaseAdapter,
577
+ tencent: tencentAdapter,
578
+ xiami: xiamiAdapter
579
+ };
580
+ function useMusic() {
581
+ const [searchOptions, setSearchOptions] = useState(null);
582
+ const { data: rawData, error: searchError, isLoading: isSearching } = useSWR(
583
+ searchOptions ? "/api/music/search?keyword=" + encodeURIComponent(searchOptions.keyword) + "&source=" + (searchOptions.source || DEFAULT_MUSIC_SOURCE) + "&limit=" + (searchOptions.limit || 20) + "&offset=" + (searchOptions.offset || 0) + (searchOptions.miku ? "&miku=true" : "") : null,
584
+ fetcher
585
+ );
586
+ const searchResult = useMemo(() => {
587
+ if (!rawData?.data || !searchOptions) return void 0;
588
+ const adapter = ADAPTERS[searchOptions.source || DEFAULT_MUSIC_SOURCE];
589
+ if (adapter) {
590
+ return adapter.parseSearchResult(rawData.data);
591
+ }
592
+ return void 0;
593
+ }, [rawData, searchOptions]);
594
+ const search = useCallback((options) => {
595
+ setSearchOptions(options);
596
+ }, []);
597
+ const getSongUrl = useCallback(async (id, source = DEFAULT_MUSIC_SOURCE) => {
598
+ try {
599
+ const res = await fetch("/api/music/url?id=" + id + "&source=" + source);
600
+ const json = await res.json();
601
+ const adapter = ADAPTERS[source];
602
+ console.log("json2", json.data, source, adapter);
603
+ if (adapter && json.data) {
604
+ console.log("getSongUrl2", json.data);
605
+ return adapter.parseGetSongUrl(json.data) || void 0;
606
+ }
607
+ return json.data?.url;
608
+ } catch (err) {
609
+ console.error("[Music] Failed to get song URL:", err);
610
+ return void 0;
611
+ }
612
+ }, []);
613
+ const getLyric = useCallback(async (id, source = DEFAULT_MUSIC_SOURCE) => {
614
+ try {
615
+ const res = await fetch("/api/music/lyric?id=" + id + "&source=" + source);
616
+ const json = await res.json();
617
+ const adapter = ADAPTERS[source];
618
+ if (adapter && json.data) {
619
+ return adapter.parseGetLyric(json.data);
620
+ }
621
+ return json.data?.lyric;
622
+ } catch (err) {
623
+ console.error("[Music] Failed to get lyric:", err);
624
+ return void 0;
625
+ }
626
+ }, []);
627
+ return {
628
+ search,
629
+ searchResult,
630
+ isSearching,
631
+ searchError,
632
+ getSongUrl,
633
+ getLyric
634
+ };
635
+ }
636
+ var MetingService = class {
637
+ constructor() {
638
+ this.instances = /* @__PURE__ */ new Map();
639
+ }
640
+ getInstance(source) {
641
+ if (!this.instances.has(source)) {
642
+ this.instances.set(source, new Meting(source));
643
+ }
644
+ return this.instances.get(source);
645
+ }
646
+ /**
647
+ * 搜索歌曲
648
+ */
649
+ async search(options) {
650
+ const { keyword, source = DEFAULT_MUSIC_SOURCE, limit = 20, offset = 0 } = options;
651
+ const meting = this.getInstance(source);
652
+ const response = await meting.search(keyword, {
653
+ limit,
654
+ page: offset + 1
655
+ });
656
+ try {
657
+ return typeof response === "string" ? JSON.parse(response) : response;
658
+ } catch (e) {
659
+ return response;
660
+ }
661
+ }
662
+ /**
663
+ * 获取歌曲详情(包含播放链接)
664
+ */
665
+ async getSongUrl(id, source = DEFAULT_MUSIC_SOURCE) {
666
+ const meting = this.getInstance(source);
667
+ const response = await meting.song(id);
668
+ try {
669
+ return typeof response === "string" ? JSON.parse(response) : response;
670
+ } catch (e) {
671
+ return response;
672
+ }
673
+ }
674
+ /**
675
+ * 获取歌词
676
+ */
677
+ async getLyric(id, source = DEFAULT_MUSIC_SOURCE) {
678
+ const meting = this.getInstance(source);
679
+ const response = await meting.lyric(id);
680
+ try {
681
+ return typeof response === "string" ? JSON.parse(response) : response;
682
+ } catch (e) {
683
+ return response;
684
+ }
685
+ }
686
+ };
687
+ var musicService = new MetingService();
688
+
689
+ // src/music/server/miku.ts
690
+ var MikuMusicService = class {
691
+ constructor(baseService = musicService) {
692
+ this.mikuKeywords = ["\u521D\u97F3\u672A\u6765", "Miku", "Vocaloid", "MIKU"];
693
+ this.baseService = baseService;
694
+ }
695
+ /**
696
+ * 搜索歌曲,自动增加 Miku 相关关键词
697
+ */
698
+ async search(options) {
699
+ const { keyword, source = DEFAULT_MUSIC_SOURCE, limit = 20, offset = 0 } = options;
700
+ const trimmedKeyword = keyword.trim();
701
+ const hasMikuKeyword = this.mikuKeywords.some(
702
+ (k) => trimmedKeyword.toLowerCase().includes(k.toLowerCase())
703
+ );
704
+ const mikuKeyword = hasMikuKeyword ? trimmedKeyword : trimmedKeyword + " \u521D\u97F3\u672A\u6765".trim();
705
+ return this.baseService.search({
706
+ ...options,
707
+ keyword: mikuKeyword || "\u521D\u97F3\u672A\u6765"
708
+ // 如果输入为空,默认搜初音未来
709
+ });
710
+ }
711
+ /**
712
+ * 获取歌曲详情(包含播放链接)- 直接透传
713
+ */
714
+ async getSongUrl(id, source = DEFAULT_MUSIC_SOURCE) {
715
+ return this.baseService.getSongUrl(id, source);
716
+ }
717
+ /**
718
+ * 获取歌词 - 直接透传
719
+ */
720
+ async getLyric(id, source = DEFAULT_MUSIC_SOURCE) {
721
+ return this.baseService.getLyric(id, source);
722
+ }
723
+ };
724
+ var mikuMusicService = new MikuMusicService();
725
+
726
+ // src/music/server/handlers.ts
727
+ var createSearchHandler = () => {
728
+ return async (req) => {
729
+ try {
730
+ const { searchParams } = new URL(req.url);
731
+ const keyword = searchParams.get("keyword");
732
+ const source = searchParams.get("source") || DEFAULT_MUSIC_SOURCE;
733
+ const limit = parseInt(searchParams.get("limit") || "20");
734
+ const offset = parseInt(searchParams.get("offset") || "0");
735
+ const miku = searchParams.get("miku") === "true";
736
+ if (!keyword && !miku) {
737
+ return Response.json({ code: 400, message: "Keyword is required" }, { status: 400 });
738
+ }
739
+ const service = miku ? mikuMusicService : musicService;
740
+ const result = await service.search({
741
+ keyword: keyword || "",
742
+ source,
743
+ limit,
744
+ offset,
745
+ miku
746
+ });
747
+ return Response.json({
748
+ code: 200,
749
+ data: result
750
+ });
751
+ } catch (error) {
752
+ console.error("[Music] Search error:", error);
753
+ return Response.json({
754
+ code: 500,
755
+ message: error.message || "Internal Server Error"
756
+ }, { status: 500 });
757
+ }
758
+ };
759
+ };
760
+ var createSongUrlHandler = () => {
761
+ return async (req) => {
762
+ try {
763
+ const { searchParams } = new URL(req.url);
764
+ const id = searchParams.get("id");
765
+ const source = searchParams.get("source") || DEFAULT_MUSIC_SOURCE;
766
+ if (!id) {
767
+ return Response.json({ code: 400, message: "ID is required" }, { status: 400 });
768
+ }
769
+ const url = await musicService.getSongUrl(id, source);
770
+ return Response.json({
771
+ code: 200,
772
+ data: { url }
773
+ });
774
+ } catch (error) {
775
+ console.error("[Music] Get URL error:", error);
776
+ return Response.json({
777
+ code: 500,
778
+ message: error.message || "Internal Server Error"
779
+ }, { status: 500 });
780
+ }
781
+ };
782
+ };
783
+ var createLyricHandler = () => {
784
+ return async (req) => {
785
+ try {
786
+ const { searchParams } = new URL(req.url);
787
+ const id = searchParams.get("id");
788
+ const source = searchParams.get("source") || DEFAULT_MUSIC_SOURCE;
789
+ if (!id) {
790
+ return Response.json({ code: 400, message: "ID is required" }, { status: 400 });
791
+ }
792
+ const lyric = await musicService.getLyric(id, source);
793
+ return Response.json({
794
+ code: 200,
795
+ data: { lyric }
796
+ });
797
+ } catch (error) {
798
+ console.error("[Music] Get lyric error:", error);
799
+ return Response.json({
800
+ code: 500,
801
+ message: error.message || "Internal Server Error"
802
+ }, { status: 500 });
803
+ }
804
+ };
805
+ };
806
+
807
+ export { MetingService, MikuMusicService, MikutapMusicPlayer, MusicPlayer, createLyricHandler, createSearchHandler, createSongUrlHandler, kugouAdapter, mikuMusicService, musicService, neteaseAdapter, tencentAdapter, useMusic, xiamiAdapter };
808
+ //# sourceMappingURL=index.mjs.map
809
+ //# sourceMappingURL=index.mjs.map