@give-tech/ec-player-vue 0.0.1-beta.1 → 0.0.1-beta.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.
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"usePlayer.d.ts","sourceRoot":"","sources":["../../src/composables/usePlayer.ts"],"names":[],"mappings":"AAAA;;GAEG;AAEH,OAAO,EAA0C,KAAK,GAAG,EAAE,MAAM,KAAK,CAAA;AACtE,OAAO,EACL,YAAY,EAIZ,KAAK,aAAa,EAEnB,MAAM,sBAAsB,CAAA;AAC7B,OAAO,KAAK,EAAiB,aAAa,EAAE,MAAM,UAAU,CAAA;AAG5D;;GAEG;AACH,MAAM,WAAW,eAAe;IAC9B,kBAAkB;IAClB,SAAS,EAAE,GAAG,CAAC,iBAAiB,GAAG,IAAI,CAAC,CAAA;IACxC,YAAY;IACZ,MAAM,EAAE,GAAG,CAAC,YAAY,GAAG,IAAI,CAAC,CAAA;IAChC,YAAY;IACZ,KAAK,EAAE,aAAa,CAAA;IACpB,aAAa;IACb,SAAS,EAAE,GAAG,CAAC,OAAO,CAAC,CAAA;IACvB,aAAa;IACb,cAAc,EAAE,GAAG,CAAC,MAAM,CAAC,CAAA;IAC3B,aAAa;IACb,MAAM,EAAE,GAAG,CAAC,OAAO,CAAC,CAAA;IACpB,SAAS;IACT,IAAI,EAAE,CAAC,OAAO,EAAE;QAAE,GAAG,EAAE,MAAM,CAAC;QAAC,MAAM,CAAC,EAAE,OAAO,CAAA;KAAE,KAAK,OAAO,CAAC,IAAI,CAAC,CAAA;IACnE,WAAW;IACX,UAAU,EAAE,CAAC,OAAO,EAAE,aAAa,KAAK,IAAI,CAAA;IAC5C,aAAa;IACb,WAAW,EAAE,CAAC,KAAK,EAAE,MAAM,KAAK,IAAI,CAAA;IACpC,SAAS;IACT,KAAK,EAAE,MAAM,IAAI,CAAA;IACjB,WAAW;IACX,MAAM,EAAE,MAAM,OAAO,CAAC,IAAI,CAAC,CAAA;IAC3B,SAAS;IACT,IAAI,EAAE,CAAC,IAAI,EAAE,MAAM,KAAK,OAAO,CAAC,IAAI,CAAC,CAAA;IACrC,cAAc;IACd,SAAS,EAAE,MAAM,YAAY,GAAG,IAAI,CAAA;IACpC,WAAW;IACX,QAAQ,EAAE,MAAM,aAAa,CAAA;IAC7B,aAAa;IACb,cAAc,EAAE,MAAM,MAAM,CAAA;IAC5B,YAAY;IACZ,WAAW,EAAE,MAAM,MAAM,CAAA;IACzB,YAAY;IACZ,OAAO,EAAE,MAAM,IAAI,CAAA;CACpB;AAkBD;;GAEG;AACH,wBAAgB,SAAS,CACvB,IAAI,EAAE;IACJ,CAAC,CAAC,EAAE,MAAM,GAAG,IAAI,CAAA;IACjB,CAAC,CAAC,EAAE,OAAO,GAAG,IAAI,CAAA;CACnB,GACA,eAAe,
|
|
1
|
+
{"version":3,"file":"usePlayer.d.ts","sourceRoot":"","sources":["../../src/composables/usePlayer.ts"],"names":[],"mappings":"AAAA;;GAEG;AAEH,OAAO,EAA0C,KAAK,GAAG,EAAE,MAAM,KAAK,CAAA;AACtE,OAAO,EACL,YAAY,EAIZ,KAAK,aAAa,EAEnB,MAAM,sBAAsB,CAAA;AAC7B,OAAO,KAAK,EAAiB,aAAa,EAAE,MAAM,UAAU,CAAA;AAG5D;;GAEG;AACH,MAAM,WAAW,eAAe;IAC9B,kBAAkB;IAClB,SAAS,EAAE,GAAG,CAAC,iBAAiB,GAAG,IAAI,CAAC,CAAA;IACxC,YAAY;IACZ,MAAM,EAAE,GAAG,CAAC,YAAY,GAAG,IAAI,CAAC,CAAA;IAChC,YAAY;IACZ,KAAK,EAAE,aAAa,CAAA;IACpB,aAAa;IACb,SAAS,EAAE,GAAG,CAAC,OAAO,CAAC,CAAA;IACvB,aAAa;IACb,cAAc,EAAE,GAAG,CAAC,MAAM,CAAC,CAAA;IAC3B,aAAa;IACb,MAAM,EAAE,GAAG,CAAC,OAAO,CAAC,CAAA;IACpB,SAAS;IACT,IAAI,EAAE,CAAC,OAAO,EAAE;QAAE,GAAG,EAAE,MAAM,CAAC;QAAC,MAAM,CAAC,EAAE,OAAO,CAAA;KAAE,KAAK,OAAO,CAAC,IAAI,CAAC,CAAA;IACnE,WAAW;IACX,UAAU,EAAE,CAAC,OAAO,EAAE,aAAa,KAAK,IAAI,CAAA;IAC5C,aAAa;IACb,WAAW,EAAE,CAAC,KAAK,EAAE,MAAM,KAAK,IAAI,CAAA;IACpC,SAAS;IACT,KAAK,EAAE,MAAM,IAAI,CAAA;IACjB,WAAW;IACX,MAAM,EAAE,MAAM,OAAO,CAAC,IAAI,CAAC,CAAA;IAC3B,SAAS;IACT,IAAI,EAAE,CAAC,IAAI,EAAE,MAAM,KAAK,OAAO,CAAC,IAAI,CAAC,CAAA;IACrC,cAAc;IACd,SAAS,EAAE,MAAM,YAAY,GAAG,IAAI,CAAA;IACpC,WAAW;IACX,QAAQ,EAAE,MAAM,aAAa,CAAA;IAC7B,aAAa;IACb,cAAc,EAAE,MAAM,MAAM,CAAA;IAC5B,YAAY;IACZ,WAAW,EAAE,MAAM,MAAM,CAAA;IACzB,gBAAgB;IAChB,MAAM,EAAE,MAAM,IAAI,CAAA;IAClB,YAAY;IACZ,OAAO,EAAE,MAAM,IAAI,CAAA;CACpB;AAkBD;;GAEG;AACH,wBAAgB,SAAS,CACvB,IAAI,EAAE;IACJ,CAAC,CAAC,EAAE,MAAM,GAAG,IAAI,CAAA;IACjB,CAAC,CAAC,EAAE,OAAO,GAAG,IAAI,CAAA;CACnB,GACA,eAAe,CAkOjB"}
|
package/dist/ec-player-vue.css
CHANGED
|
@@ -1,24 +1,22 @@
|
|
|
1
1
|
|
|
2
|
-
.gt-player-container[data-v-
|
|
2
|
+
.gt-player-container[data-v-c1c61728] {
|
|
3
3
|
width: 100%;
|
|
4
4
|
height: 100%;
|
|
5
5
|
}
|
|
6
|
-
.gt-video-wrapper[data-v-
|
|
6
|
+
.gt-video-wrapper[data-v-c1c61728] {
|
|
7
7
|
position: relative;
|
|
8
8
|
width: 100%;
|
|
9
9
|
height: 100%;
|
|
10
10
|
background: #000;
|
|
11
11
|
overflow: hidden;
|
|
12
12
|
}
|
|
13
|
-
.gt-player-canvas[data-v-
|
|
13
|
+
.gt-player-canvas[data-v-c1c61728] {
|
|
14
14
|
position: absolute;
|
|
15
15
|
top: 50%;
|
|
16
16
|
left: 50%;
|
|
17
17
|
transform: translate(-50%, -50%);
|
|
18
|
-
max-width: 100%;
|
|
19
|
-
max-height: 100%;
|
|
20
18
|
}
|
|
21
|
-
.gt-placeholder[data-v-
|
|
19
|
+
.gt-placeholder[data-v-c1c61728] {
|
|
22
20
|
position: absolute;
|
|
23
21
|
top: 0;
|
|
24
22
|
left: 0;
|
|
@@ -31,7 +29,7 @@
|
|
|
31
29
|
}
|
|
32
30
|
|
|
33
31
|
/* 加载中动画 */
|
|
34
|
-
.gt-loading-spinner[data-v-
|
|
32
|
+
.gt-loading-spinner[data-v-c1c61728] {
|
|
35
33
|
position: absolute;
|
|
36
34
|
top: 0;
|
|
37
35
|
left: 0;
|
|
@@ -43,22 +41,22 @@
|
|
|
43
41
|
background: rgba(0, 0, 0, 0.5);
|
|
44
42
|
z-index: 10;
|
|
45
43
|
}
|
|
46
|
-
.gt-spinner[data-v-
|
|
44
|
+
.gt-spinner[data-v-c1c61728] {
|
|
47
45
|
width: 8vmin;
|
|
48
46
|
height: 8vmin;
|
|
49
47
|
border: 0.5vmin solid rgba(255, 255, 255, 0.3);
|
|
50
48
|
border-top-color: #fff;
|
|
51
49
|
border-radius: 50%;
|
|
52
|
-
animation: gt-spin-
|
|
50
|
+
animation: gt-spin-c1c61728 1s linear infinite;
|
|
53
51
|
}
|
|
54
|
-
@keyframes gt-spin-
|
|
52
|
+
@keyframes gt-spin-c1c61728 {
|
|
55
53
|
to {
|
|
56
54
|
transform: rotate(360deg);
|
|
57
55
|
}
|
|
58
56
|
}
|
|
59
57
|
|
|
60
58
|
/* 视频控制条 */
|
|
61
|
-
.gt-video-controls[data-v-
|
|
59
|
+
.gt-video-controls[data-v-c1c61728] {
|
|
62
60
|
position: absolute;
|
|
63
61
|
bottom: 0;
|
|
64
62
|
left: 0;
|
|
@@ -71,13 +69,13 @@ to {
|
|
|
71
69
|
align-items: center;
|
|
72
70
|
gap: 12px;
|
|
73
71
|
}
|
|
74
|
-
.gt-flex-spacer[data-v-
|
|
72
|
+
.gt-flex-spacer[data-v-c1c61728] {
|
|
75
73
|
flex: 1;
|
|
76
74
|
}
|
|
77
|
-
.gt-video-controls.visible[data-v-
|
|
75
|
+
.gt-video-controls.visible[data-v-c1c61728] {
|
|
78
76
|
opacity: 1;
|
|
79
77
|
}
|
|
80
|
-
.gt-control-btn[data-v-
|
|
78
|
+
.gt-control-btn[data-v-c1c61728] {
|
|
81
79
|
width: 28px;
|
|
82
80
|
height: 28px;
|
|
83
81
|
border: none;
|
|
@@ -91,14 +89,14 @@ to {
|
|
|
91
89
|
transition: all 0.2s ease;
|
|
92
90
|
flex-shrink: 0;
|
|
93
91
|
}
|
|
94
|
-
.gt-control-btn[data-v-
|
|
92
|
+
.gt-control-btn[data-v-c1c61728]:hover {
|
|
95
93
|
background: rgba(255, 255, 255, 0.2);
|
|
96
94
|
}
|
|
97
|
-
.gt-control-btn svg[data-v-
|
|
95
|
+
.gt-control-btn svg[data-v-c1c61728] {
|
|
98
96
|
width: 14px;
|
|
99
97
|
height: 14px;
|
|
100
98
|
}
|
|
101
|
-
.gt-progress-container[data-v-
|
|
99
|
+
.gt-progress-container[data-v-c1c61728] {
|
|
102
100
|
flex: 1;
|
|
103
101
|
position: relative;
|
|
104
102
|
cursor: pointer;
|
|
@@ -106,7 +104,7 @@ to {
|
|
|
106
104
|
display: flex;
|
|
107
105
|
align-items: center;
|
|
108
106
|
}
|
|
109
|
-
.gt-progress-bar[data-v-
|
|
107
|
+
.gt-progress-bar[data-v-c1c61728] {
|
|
110
108
|
width: 100%;
|
|
111
109
|
height: 4px;
|
|
112
110
|
background: rgba(255, 255, 255, 0.2);
|
|
@@ -115,10 +113,10 @@ to {
|
|
|
115
113
|
overflow: hidden;
|
|
116
114
|
transition: height 0.2s ease;
|
|
117
115
|
}
|
|
118
|
-
.gt-progress-container:hover .gt-progress-bar[data-v-
|
|
116
|
+
.gt-progress-container:hover .gt-progress-bar[data-v-c1c61728] {
|
|
119
117
|
height: 6px;
|
|
120
118
|
}
|
|
121
|
-
.gt-progress-buffered[data-v-
|
|
119
|
+
.gt-progress-buffered[data-v-c1c61728] {
|
|
122
120
|
position: absolute;
|
|
123
121
|
top: 0;
|
|
124
122
|
left: 0;
|
|
@@ -127,7 +125,7 @@ to {
|
|
|
127
125
|
border-radius: 2px;
|
|
128
126
|
transition: width 0.1s;
|
|
129
127
|
}
|
|
130
|
-
.gt-progress-played[data-v-
|
|
128
|
+
.gt-progress-played[data-v-c1c61728] {
|
|
131
129
|
position: absolute;
|
|
132
130
|
top: 0;
|
|
133
131
|
left: 0;
|
|
@@ -136,7 +134,7 @@ to {
|
|
|
136
134
|
border-radius: 2px;
|
|
137
135
|
transition: width 0.1s;
|
|
138
136
|
}
|
|
139
|
-
.gt-progress-handle[data-v-
|
|
137
|
+
.gt-progress-handle[data-v-c1c61728] {
|
|
140
138
|
position: absolute;
|
|
141
139
|
right: -6px;
|
|
142
140
|
top: 50%;
|
|
@@ -149,11 +147,11 @@ to {
|
|
|
149
147
|
opacity: 0;
|
|
150
148
|
transition: opacity 0.2s, transform 0.2s;
|
|
151
149
|
}
|
|
152
|
-
.gt-progress-container:hover .gt-progress-handle[data-v-
|
|
150
|
+
.gt-progress-container:hover .gt-progress-handle[data-v-c1c61728] {
|
|
153
151
|
opacity: 1;
|
|
154
152
|
transform: translateY(-50%) scale(1.2);
|
|
155
153
|
}
|
|
156
|
-
.gt-progress-tooltip[data-v-
|
|
154
|
+
.gt-progress-tooltip[data-v-c1c61728] {
|
|
157
155
|
position: absolute;
|
|
158
156
|
bottom: calc(100% + 8px);
|
|
159
157
|
transform: translateX(-50%);
|
|
@@ -165,20 +163,20 @@ to {
|
|
|
165
163
|
white-space: nowrap;
|
|
166
164
|
pointer-events: none;
|
|
167
165
|
}
|
|
168
|
-
.gt-time-display[data-v-
|
|
166
|
+
.gt-time-display[data-v-c1c61728] {
|
|
169
167
|
color: white;
|
|
170
168
|
font-size: 12px;
|
|
171
169
|
font-family: -apple-system, BlinkMacSystemFont, 'Segoe UI', Roboto, sans-serif;
|
|
172
170
|
white-space: nowrap;
|
|
173
171
|
flex-shrink: 0;
|
|
174
172
|
}
|
|
175
|
-
.gt-time-separator[data-v-
|
|
173
|
+
.gt-time-separator[data-v-c1c61728] {
|
|
176
174
|
margin: 0 4px;
|
|
177
175
|
opacity: 0.6;
|
|
178
176
|
}
|
|
179
177
|
|
|
180
178
|
/* 直播指示器 */
|
|
181
|
-
.gt-live-indicator[data-v-
|
|
179
|
+
.gt-live-indicator[data-v-c1c61728] {
|
|
182
180
|
display: flex;
|
|
183
181
|
align-items: center;
|
|
184
182
|
gap: 6px;
|
|
@@ -186,17 +184,17 @@ to {
|
|
|
186
184
|
font-size: 12px;
|
|
187
185
|
font-weight: 500;
|
|
188
186
|
}
|
|
189
|
-
.gt-live-dot[data-v-
|
|
187
|
+
.gt-live-dot[data-v-c1c61728] {
|
|
190
188
|
width: 8px;
|
|
191
189
|
height: 8px;
|
|
192
190
|
background: #ff2d55;
|
|
193
191
|
border-radius: 50%;
|
|
194
|
-
animation: gt-live-pulse-
|
|
192
|
+
animation: gt-live-pulse-c1c61728 1.5s ease-in-out infinite;
|
|
195
193
|
}
|
|
196
|
-
.gt-live-text[data-v-
|
|
194
|
+
.gt-live-text[data-v-c1c61728] {
|
|
197
195
|
color: #ff2d55;
|
|
198
196
|
}
|
|
199
|
-
@keyframes gt-live-pulse-
|
|
197
|
+
@keyframes gt-live-pulse-c1c61728 {
|
|
200
198
|
0%, 100% {
|
|
201
199
|
opacity: 1;
|
|
202
200
|
}
|
|
@@ -206,7 +204,7 @@ to {
|
|
|
206
204
|
}
|
|
207
205
|
|
|
208
206
|
/* 居中播放按钮 */
|
|
209
|
-
.gt-center-play-btn[data-v-
|
|
207
|
+
.gt-center-play-btn[data-v-c1c61728] {
|
|
210
208
|
position: absolute;
|
|
211
209
|
top: 50%;
|
|
212
210
|
left: 50%;
|
|
@@ -221,11 +219,11 @@ to {
|
|
|
221
219
|
cursor: pointer;
|
|
222
220
|
transition: all 0.2s ease;
|
|
223
221
|
}
|
|
224
|
-
.gt-center-play-btn[data-v-
|
|
222
|
+
.gt-center-play-btn[data-v-c1c61728]:hover {
|
|
225
223
|
background: rgba(0, 0, 0, 0.7);
|
|
226
224
|
transform: translate(-50%, -50%) scale(1.05);
|
|
227
225
|
}
|
|
228
|
-
.gt-center-play-btn svg[data-v-
|
|
226
|
+
.gt-center-play-btn svg[data-v-c1c61728] {
|
|
229
227
|
width: 24px;
|
|
230
228
|
height: 24px;
|
|
231
229
|
color: white;
|
|
@@ -233,7 +231,7 @@ to {
|
|
|
233
231
|
}
|
|
234
232
|
|
|
235
233
|
/* 环境信息面板 */
|
|
236
|
-
.gt-env-panel[data-v-
|
|
234
|
+
.gt-env-panel[data-v-c1c61728] {
|
|
237
235
|
position: absolute;
|
|
238
236
|
top: 12px;
|
|
239
237
|
left: 12px;
|
|
@@ -247,46 +245,46 @@ to {
|
|
|
247
245
|
max-height: calc(100% - 24px);
|
|
248
246
|
overflow-y: auto;
|
|
249
247
|
backdrop-filter: blur(10px);
|
|
250
|
-
animation: gt-env-fade-in-
|
|
248
|
+
animation: gt-env-fade-in-c1c61728 0.15s ease;
|
|
251
249
|
z-index: 15;
|
|
252
250
|
}
|
|
253
|
-
.gt-env-panel[data-v-
|
|
251
|
+
.gt-env-panel[data-v-c1c61728]::-webkit-scrollbar {
|
|
254
252
|
width: 4px;
|
|
255
253
|
}
|
|
256
|
-
.gt-env-panel[data-v-
|
|
254
|
+
.gt-env-panel[data-v-c1c61728]::-webkit-scrollbar-track {
|
|
257
255
|
background: transparent;
|
|
258
256
|
}
|
|
259
|
-
.gt-env-panel[data-v-
|
|
257
|
+
.gt-env-panel[data-v-c1c61728]::-webkit-scrollbar-thumb {
|
|
260
258
|
background: rgba(255, 255, 255, 0.3);
|
|
261
259
|
border-radius: 2px;
|
|
262
260
|
}
|
|
263
|
-
@keyframes gt-env-fade-in-
|
|
261
|
+
@keyframes gt-env-fade-in-c1c61728 {
|
|
264
262
|
from { opacity: 0; transform: translateY(-4px);
|
|
265
263
|
}
|
|
266
264
|
to { opacity: 1; transform: translateY(0);
|
|
267
265
|
}
|
|
268
266
|
}
|
|
269
|
-
.gt-env-panel .gt-env-row[data-v-
|
|
267
|
+
.gt-env-panel .gt-env-row[data-v-c1c61728] {
|
|
270
268
|
display: flex;
|
|
271
269
|
justify-content: space-between;
|
|
272
270
|
align-items: center;
|
|
273
271
|
padding: 2px 0;
|
|
274
272
|
color: rgba(255, 255, 255, 0.7);
|
|
275
273
|
}
|
|
276
|
-
.gt-env-panel .gt-env-row span[data-v-
|
|
274
|
+
.gt-env-panel .gt-env-row span[data-v-c1c61728]:first-child {
|
|
277
275
|
color: rgba(255, 255, 255, 0.5);
|
|
278
276
|
margin-right: 16px;
|
|
279
277
|
}
|
|
280
|
-
.gt-env-panel .gt-env-row span[data-v-
|
|
278
|
+
.gt-env-panel .gt-env-row span[data-v-c1c61728]:last-child {
|
|
281
279
|
font-variant-numeric: tabular-nums;
|
|
282
280
|
}
|
|
283
|
-
.gt-env-panel .gt-env-row .ok[data-v-
|
|
281
|
+
.gt-env-panel .gt-env-row .ok[data-v-c1c61728] { color: #4caf50;
|
|
284
282
|
}
|
|
285
|
-
.gt-env-panel .gt-env-row .warn[data-v-
|
|
283
|
+
.gt-env-panel .gt-env-row .warn[data-v-c1c61728] { color: #ff9800;
|
|
286
284
|
}
|
|
287
|
-
.gt-env-panel .gt-env-row .err[data-v-
|
|
285
|
+
.gt-env-panel .gt-env-row .err[data-v-c1c61728] { color: #f44336;
|
|
288
286
|
}
|
|
289
|
-
.gt-env-divider[data-v-
|
|
287
|
+
.gt-env-divider[data-v-c1c61728] {
|
|
290
288
|
height: 1px;
|
|
291
289
|
background: rgba(255, 255, 255, 0.1);
|
|
292
290
|
margin: 4px 0;
|
package/dist/index.js
CHANGED
|
@@ -213,6 +213,9 @@ function usePlayer(emit) {
|
|
|
213
213
|
player.value = null;
|
|
214
214
|
}
|
|
215
215
|
}
|
|
216
|
+
function resize() {
|
|
217
|
+
player.value?.resize();
|
|
218
|
+
}
|
|
216
219
|
onUnmounted(() => {
|
|
217
220
|
destroy();
|
|
218
221
|
});
|
|
@@ -233,6 +236,7 @@ function usePlayer(emit) {
|
|
|
233
236
|
getState,
|
|
234
237
|
getCurrentTime,
|
|
235
238
|
getDuration,
|
|
239
|
+
resize,
|
|
236
240
|
destroy
|
|
237
241
|
};
|
|
238
242
|
}
|
|
@@ -495,11 +499,20 @@ const _sfc_main = /* @__PURE__ */ defineComponent({
|
|
|
495
499
|
player.play(parsed);
|
|
496
500
|
}
|
|
497
501
|
}, { immediate: true, deep: true });
|
|
502
|
+
let resizeObserver = null;
|
|
498
503
|
onMounted(() => {
|
|
499
504
|
document.addEventListener("fullscreenchange", handleFullscreenChange);
|
|
505
|
+
if (containerRef.value) {
|
|
506
|
+
resizeObserver = new ResizeObserver(() => {
|
|
507
|
+
player.resize();
|
|
508
|
+
});
|
|
509
|
+
resizeObserver.observe(containerRef.value);
|
|
510
|
+
}
|
|
500
511
|
});
|
|
501
512
|
onUnmounted(() => {
|
|
502
513
|
document.removeEventListener("fullscreenchange", handleFullscreenChange);
|
|
514
|
+
resizeObserver?.disconnect();
|
|
515
|
+
resizeObserver = null;
|
|
503
516
|
});
|
|
504
517
|
__expose({
|
|
505
518
|
play,
|
|
@@ -731,7 +744,7 @@ const _export_sfc = (sfc, props) => {
|
|
|
731
744
|
}
|
|
732
745
|
return target;
|
|
733
746
|
};
|
|
734
|
-
const EcPlayer = /* @__PURE__ */ _export_sfc(_sfc_main, [["__scopeId", "data-v-
|
|
747
|
+
const EcPlayer = /* @__PURE__ */ _export_sfc(_sfc_main, [["__scopeId", "data-v-c1c61728"]]);
|
|
735
748
|
export {
|
|
736
749
|
DEFAULT_EC_PLAYER_PROPS,
|
|
737
750
|
DEFAULT_PLAYER_OPTIONS,
|
package/dist/index.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"index.js","sources":["../src/types.ts","../src/composables/usePlayer.ts","../src/composables/useControls.ts","../src/composables/useEnvInfo.ts","../src/components/EcPlayer.vue"],"sourcesContent":["/**\n * Vue 组件类型定义\n */\n\nimport type { EcPlayerCoreConfig, EcPlayerState, EnvInfo } from '@give-tech/ec-player'\nexport { LogLevel } from '@give-tech/ec-player'\n\n/**\n * WASM 路径配置\n */\nexport interface WasmPathConfig {\n /**\n * SIMD 版本 WASM 路径(推荐,性能更好)\n * 用于支持 SIMD 的现代浏览器\n */\n simd?: string\n /**\n * 非 SIMD 版本 WASM 路径\n * 用于不支持 SIMD 的旧浏览器作为降级方案\n */\n nonSimd?: string\n}\n\n/**\n * 全局配置\n *\n * 必须在使用 EcPlayer 组件前调用\n *\n * @example\n * ```typescript\n * // main.ts\n * import { configureEcPlayer } from '@give-tech/ec-player-vue'\n *\n * // 配置 SIMD 和非 SIMD 路径,支持自动降级\n * configureEcPlayer({\n * wasm: {\n * simd: '/wasm/decoder-simd.js',\n * nonSimd: '/wasm/decoder.js'\n * }\n * })\n *\n * // 使用 CDN\n * configureEcPlayer({\n * wasm: {\n * simd: 'https://unpkg.com/@give-tech/ec-player@latest/wasm/decoder-simd.js',\n * nonSimd: 'https://unpkg.com/@give-tech/ec-player@latest/wasm/decoder.js'\n * }\n * })\n * ```\n */\nexport interface EcPlayerGlobalConfig {\n /**\n * WASM 路径配置(必填)\n * 支持 SIMD 和非 SIMD 自动降级\n */\n wasm?: WasmPathConfig\n /** 默认是否显示控制条 */\n showControls?: boolean\n /** 默认缓冲目标帧数 */\n targetBufferSize?: number\n /** 默认每批解码帧数 */\n decodeBatchSize?: number\n /** 默认队列上限 */\n maxQueueSize?: number\n}\n\n/**\n * 播放器配置选项\n */\nexport interface PlayerOptions {\n /** 帧缓冲区目标大小 */\n targetBufferSize?: number\n /** 每批解码帧数 */\n decodeBatchSize?: number\n /** NAL/Sample 队列上限 */\n maxQueueSize?: number\n}\n\n/**\n * 视频源配置\n */\nexport interface EcPlayerSource {\n /** 视频 URL */\n url: string\n /** 是否为直播流 */\n isLive?: boolean\n /** 版本号,用于强制重新加载 */\n version?: number\n}\n\n/**\n * 控制条选项\n */\nexport interface EcPlayerControlOption {\n /** 是否显示控制条 */\n show?: boolean\n /** 是否显示全屏按钮 */\n fullscreen?: boolean\n /** 是否显示环境信息按钮 */\n info?: boolean\n}\n\n/**\n * EcPlayer 组件 Props\n */\nexport interface EcPlayerProps {\n /** 视频源 */\n src?: EcPlayerSource\n /** 控制条选项 */\n controlOption?: EcPlayerControlOption\n}\n\n/**\n * EcPlayer 组件 Emits\n */\nexport interface EcPlayerEmits {\n /** 播放时触发 */\n (e: 'play'): void\n /** 暂停时触发 */\n (e: 'pause'): void\n}\n\n/**\n * EcPlayer 组件 Expose 方法\n */\nexport interface EcPlayerExpose {\n /** 播放 */\n play: () => void\n /** 暂停 */\n pause: () => void\n /** 跳转到指定时间(毫秒) */\n seek: (time: number) => Promise<void>\n}\n\n/**\n * 环境信息面板数据\n */\nexport interface EnvPanelData {\n envInfo: EnvInfo | null\n state: Partial<EcPlayerState>\n}\n\n/**\n * 播放器配置(从 Props 转换)\n */\nexport interface PlayerConfigFromProps extends EcPlayerCoreConfig {\n wasmPath: string\n targetBufferSize: number\n decodeBatchSize: number\n maxQueueSize: number\n}\n\n/**\n * 默认 Props 值\n */\nexport const DEFAULT_EC_PLAYER_PROPS = {\n src: undefined as EcPlayerSource | undefined,\n controlOption: {\n show: true,\n fullscreen: true,\n info: true\n }\n}\n\n/**\n * 默认播放器配置\n */\nexport const DEFAULT_PLAYER_OPTIONS: Required<PlayerOptions> = {\n targetBufferSize: 60,\n decodeBatchSize: 2,\n maxQueueSize: 200\n}\n\n/**\n * 默认 WASM 配置\n */\nexport const DEFAULT_WASM_CONFIG: WasmPathConfig = {\n simd: '/wasm/decoder-simd.js',\n nonSimd: '/wasm/decoder.js'\n}\n\n/**\n * 全局配置存储\n */\nlet globalConfig: EcPlayerGlobalConfig = {}\n\n/**\n * 配置 EcPlayer 全局默认值\n *\n * @example\n * ```typescript\n * // main.ts\n * import { configureEcPlayer } from '@give-tech/ec-player-vue'\n *\n * // 配置 SIMD 和非 SIMD 路径,支持自动降级\n * configureEcPlayer({\n * wasm: {\n * simd: '/wasm/decoder-simd.js',\n * nonSimd: '/wasm/decoder.js'\n * }\n * })\n *\n * // 使用 CDN\n * configureEcPlayer({\n * wasm: {\n * simd: 'https://unpkg.com/@give-tech/ec-player@latest/wasm/decoder-simd.js',\n * nonSimd: 'https://unpkg.com/@give-tech/ec-player@latest/wasm/decoder.js'\n * }\n * })\n * ```\n */\nexport function configureEcPlayer(config: EcPlayerGlobalConfig): void {\n globalConfig = { ...globalConfig, ...config }\n}\n\n/**\n * 获取全局配置\n */\nexport function getGlobalConfig(): EcPlayerGlobalConfig {\n return { ...globalConfig }\n}\n\n/**\n * 获取 WASM 路径配置\n */\nexport function getWasmConfig(): WasmPathConfig {\n return {\n simd: globalConfig.wasm?.simd ?? DEFAULT_WASM_CONFIG.simd,\n nonSimd: globalConfig.wasm?.nonSimd ?? DEFAULT_WASM_CONFIG.nonSimd\n }\n}\n\n/**\n * 获取合并后的配置(props > 全局配置 > 默认值)\n */\nexport function getMergedConfig(props: EcPlayerProps) {\n return {\n src: props.src ?? DEFAULT_EC_PLAYER_PROPS.src,\n controlOption: {\n show: props.controlOption?.show ?? globalConfig.showControls ?? DEFAULT_EC_PLAYER_PROPS.controlOption.show,\n fullscreen: props.controlOption?.fullscreen ?? DEFAULT_EC_PLAYER_PROPS.controlOption.fullscreen,\n info: props.controlOption?.info ?? DEFAULT_EC_PLAYER_PROPS.controlOption.info\n }\n }\n}\n\n/**\n * 获取合并后的播放器配置(options > 全局配置 > 默认值)\n */\nexport function getMergedPlayerOptions(options: PlayerOptions): Required<PlayerOptions> {\n return {\n targetBufferSize: options.targetBufferSize ?? globalConfig.targetBufferSize ?? DEFAULT_PLAYER_OPTIONS.targetBufferSize,\n decodeBatchSize: options.decodeBatchSize ?? globalConfig.decodeBatchSize ?? DEFAULT_PLAYER_OPTIONS.decodeBatchSize,\n maxQueueSize: options.maxQueueSize ?? globalConfig.maxQueueSize ?? DEFAULT_PLAYER_OPTIONS.maxQueueSize\n }\n}\n\n/**\n * 根据环境能力选择合适的 WASM 路径\n *\n * @param hasSimdSupport 是否支持 SIMD\n * @returns 实际使用的 WASM 路径\n */\nexport function resolveWasmPath(hasSimdSupport: boolean): string {\n const wasmConfig = getWasmConfig()\n\n // 根据 SIMD 支持情况选择\n if (hasSimdSupport && wasmConfig.simd) {\n console.log('[EcPlayer] Using SIMD WASM:', wasmConfig.simd)\n return wasmConfig.simd\n }\n\n if (wasmConfig.nonSimd) {\n console.log('[EcPlayer] SIMD not supported, using non-SIMD WASM:', wasmConfig.nonSimd)\n return wasmConfig.nonSimd\n }\n\n // 降级到 SIMD 版本(兜底)\n console.log('[EcPlayer] No non-SIMD path configured, falling back to SIMD:', wasmConfig.simd)\n return wasmConfig.simd!\n}\n","/**\n * 播放器核心逻辑\n */\n\nimport { ref, shallowRef, reactive, onUnmounted, type Ref } from 'vue'\nimport {\n EcPlayerCore,\n EnvDetector,\n setLogLevel as coreSetLogLevel,\n type EcPlayerCoreConfig,\n type EcPlayerState,\n type EcPlayerCallbacks\n} from '@give-tech/ec-player'\nimport type { EcPlayerProps, PlayerOptions } from '../types'\nimport { resolveWasmPath, DEFAULT_PLAYER_OPTIONS, getGlobalConfig } from '../types'\n\n/**\n * 播放器逻辑返回值\n */\nexport interface UsePlayerReturn {\n /** Canvas 元素引用 */\n canvasRef: Ref<HTMLCanvasElement | null>\n /** 播放器实例 */\n player: Ref<EcPlayerCore | null>\n /** 响应式状态 */\n state: EcPlayerState\n /** 是否正在加载 */\n isLoading: Ref<boolean>\n /** 检测到的格式 */\n detectedFormat: Ref<string>\n /** 是否为直播流 */\n isLive: Ref<boolean>\n /** 播放 */\n play: (options: { url: string; isLive?: boolean }) => Promise<void>\n /** 设置配置 */\n setOptions: (options: PlayerOptions) => void\n /** 设置日志级别 */\n setLogLevel: (level: number) => void\n /** 暂停 */\n pause: () => void\n /** 恢复播放 */\n resume: () => Promise<void>\n /** 跳转 */\n seek: (time: number) => Promise<void>\n /** 获取播放器实例 */\n getPlayer: () => EcPlayerCore | null\n /** 获取状态 */\n getState: () => EcPlayerState\n /** 获取当前时间 */\n getCurrentTime: () => number\n /** 获取总时长 */\n getDuration: () => number\n /** 销毁播放器 */\n destroy: () => void\n}\n\n/**\n * 从配置选项创建播放器配置\n */\nfunction createConfig(options: Required<PlayerOptions>): Omit<EcPlayerCoreConfig, 'isLive'> {\n // 检测 SIMD 支持\n const envInfo = EnvDetector.detect()\n const wasmPath = resolveWasmPath(envInfo.capabilities.wasmSimd)\n\n return {\n wasmPath,\n targetBufferSize: options.targetBufferSize,\n decodeBatchSize: options.decodeBatchSize,\n maxQueueSize: options.maxQueueSize\n }\n}\n\n/**\n * 播放器逻辑 Hook\n */\nexport function usePlayer(\n emit: {\n (e: 'play'): void\n (e: 'pause'): void\n }\n): UsePlayerReturn {\n const canvasRef = ref<HTMLCanvasElement | null>(null)\n const player = shallowRef<EcPlayerCore | null>(null)\n const isLoading = ref(false)\n const detectedFormat = ref('')\n const isLive = ref(false) // 跟踪当前是否为直播流\n\n // 当前播放器配置(初始化时合并全局配置和默认值)\n const globalConfig = getGlobalConfig()\n const currentOptions = reactive<Required<PlayerOptions>>({\n targetBufferSize: globalConfig.targetBufferSize ?? DEFAULT_PLAYER_OPTIONS.targetBufferSize,\n decodeBatchSize: globalConfig.decodeBatchSize ?? DEFAULT_PLAYER_OPTIONS.decodeBatchSize,\n maxQueueSize: globalConfig.maxQueueSize ?? DEFAULT_PLAYER_OPTIONS.maxQueueSize\n })\n\n // 响应式状态\n const state = reactive<EcPlayerState>({\n isPlaying: false,\n isLoaded: false,\n isLoading: false,\n fps: 0,\n resolution: '-',\n decoded: 0,\n downloaded: 0,\n droppedFrames: 0,\n isPrefetching: false,\n segmentIndex: 0,\n totalSegments: 0,\n downloadSpeed: 0,\n currentTime: 0,\n duration: 0\n })\n\n // 创建回调\n const callbacks: EcPlayerCallbacks = {\n onStateChange: (partial) => {\n Object.assign(state, partial)\n\n // 派发 play/pause 事件\n if (partial.isPlaying === true) {\n emit('play')\n } else if (partial.isPlaying === false && state.isPlaying) {\n emit('pause')\n }\n },\n onError: (error) => {\n console.error('[EcPlayer] Error:', error)\n }\n }\n\n // 播放(加载并播放)\n async function play(options: { url: string; isLive?: boolean }): Promise<void> {\n const { url, isLive: isLiveParam = false } = options\n if (!url) {\n console.error('[EcPlayer] URL is required')\n return\n }\n\n // 如果正在加载中,先销毁当前播放器\n if (isLoading.value && player.value) {\n console.log('[EcPlayer] Aborting current load to start new one...')\n player.value.destroy()\n player.value = null\n }\n\n // 等待 canvas 准备好\n let retries = 10\n while (!canvasRef.value && retries > 0) {\n await new Promise(resolve => setTimeout(resolve, 100))\n retries--\n }\n\n if (!canvasRef.value) {\n console.error('[EcPlayer] Canvas element not found')\n return\n }\n\n isLoading.value = true\n isLive.value = isLiveParam\n\n try {\n // 销毁旧播放器\n if (player.value) {\n player.value.destroy()\n player.value = null\n }\n\n // 重置状态\n state.isPlaying = false\n state.isLoaded = false\n state.fps = 0\n state.resolution = '-'\n state.decoded = 0\n state.downloaded = 0\n state.droppedFrames = 0\n state.segmentIndex = 0\n state.totalSegments = 0\n state.downloadSpeed = 0\n state.currentTime = 0\n state.duration = 0\n detectedFormat.value = ''\n\n // 创建配置\n const config: EcPlayerCoreConfig & { canvas: HTMLCanvasElement } = {\n ...createConfig(currentOptions),\n canvas: canvasRef.value,\n isLive: isLiveParam\n }\n\n // 创建播放器\n player.value = new EcPlayerCore(config, callbacks)\n\n // 加载视频\n await player.value.load(url, isLiveParam)\n\n // 获取检测到的格式\n detectedFormat.value = player.value.getDetectedFormat()\n\n // 标记加载完成\n state.isLoaded = true\n\n // 开始播放\n await player.value.play()\n\n console.log('[EcPlayer] Playing stream, format:', detectedFormat.value)\n } catch (error: any) {\n console.error('[EcPlayer] Failed to play:', error?.message || error)\n } finally {\n isLoading.value = false\n }\n }\n\n // 设置配置\n function setOptions(options: PlayerOptions): void {\n if (options.targetBufferSize !== undefined) {\n currentOptions.targetBufferSize = options.targetBufferSize\n }\n if (options.decodeBatchSize !== undefined) {\n currentOptions.decodeBatchSize = options.decodeBatchSize\n }\n if (options.maxQueueSize !== undefined) {\n currentOptions.maxQueueSize = options.maxQueueSize\n }\n console.log('[EcPlayer] Options updated:', currentOptions)\n }\n\n // 设置日志级别\n function setLogLevel(level: number): void {\n coreSetLogLevel(level)\n }\n\n // 暂停\n function pause(): void {\n player.value?.pause()\n }\n\n // 恢复播放\n async function resume(): Promise<void> {\n if (!player.value) return\n await player.value.play()\n }\n\n // 跳转\n async function seek(time: number): Promise<void> {\n if (!player.value) return\n await player.value.seek(time)\n }\n\n // 获取播放器实例\n function getPlayer(): EcPlayerCore | null {\n return player.value\n }\n\n // 获取状态\n function getState(): EcPlayerState {\n return player.value?.getState() ?? { ...state }\n }\n\n // 获取当前时间\n function getCurrentTime(): number {\n return player.value?.getCurrentTime() ?? 0\n }\n\n // 获取总时长\n function getDuration(): number {\n return player.value?.getDuration() ?? 0\n }\n\n // 销毁播放器\n function destroy(): void {\n if (player.value) {\n player.value.destroy()\n player.value = null\n }\n }\n\n // 组件卸载时销毁\n onUnmounted(() => {\n destroy()\n })\n\n return {\n canvasRef,\n player,\n state,\n isLoading,\n detectedFormat,\n isLive,\n play,\n setOptions,\n setLogLevel,\n pause,\n resume,\n seek,\n getPlayer,\n getState,\n getCurrentTime,\n getDuration,\n destroy\n }\n}\n","/**\n * 播放器控制条逻辑\n */\n\nimport { ref, computed, type Ref } from 'vue'\n\n/**\n * 控制条逻辑参数\n */\nexport interface UseControlsParams {\n /** 是否正在播放 */\n isPlaying: Ref<boolean>\n /** 是否已加载 */\n isLoaded: Ref<boolean>\n /** 当前时间(毫秒) */\n currentTime: Ref<number>\n /** 总时长(毫秒) */\n duration: Ref<number>\n /** 分片索引 */\n segmentIndex: Ref<number>\n /** 总分片数 */\n totalSegments: Ref<number>\n /** 是否为直播流 */\n isLive: Ref<boolean>\n /** 跳转方法 */\n seek: (time: number) => Promise<void>\n}\n\n/**\n * 控制条逻辑返回值\n */\nexport interface UseControlsReturn {\n /** 是否显示控制条 */\n showControls: Ref<boolean>\n /** 进度条 hover 时间 */\n hoverTime: Ref<number | null>\n /** 进度条 hover 位置 */\n hoverPosition: Ref<number>\n /** 播放进度百分比 */\n playProgress: Ref<number>\n /** 缓冲进度百分比 */\n bufferProgress: Ref<number>\n /** 显示控制条 */\n showControlsBar: () => void\n /** 隐藏控制条 */\n hideControlsBar: () => void\n /** 处理进度条点击 */\n handleProgressClick: (event: MouseEvent) => Promise<void>\n /** 处理进度条悬停 */\n handleProgressHover: (event: MouseEvent) => void\n /** 格式化时间 */\n formatTime: (ms: number) => string\n}\n\n/**\n * 控制条逻辑 Hook\n */\nexport function useControls(params: UseControlsParams): UseControlsReturn {\n let hideControlsTimer: number | null = null\n const {\n isPlaying,\n isLoaded,\n currentTime,\n duration,\n segmentIndex,\n totalSegments,\n isLive,\n seek\n } = params\n\n const showControls = ref(true)\n const hoverTime = ref<number | null>(null)\n const hoverPosition = ref(0)\n\n // 计算播放进度\n const playProgress = computed(() => {\n if (duration.value === 0) return 0\n return (currentTime.value / duration.value) * 100\n })\n\n // 计算缓冲进度\n const bufferProgress = computed(() => {\n if (totalSegments.value === 0) return 0\n return (segmentIndex.value / totalSegments.value) * 100\n })\n\n // 显示控制条\n function showControlsBar(): void {\n showControls.value = true\n if (hideControlsTimer) {\n clearTimeout(hideControlsTimer)\n }\n hideControlsTimer = window.setTimeout(() => {\n if (isPlaying.value) {\n showControls.value = false\n }\n }, 3000)\n }\n\n // 隐藏控制条\n function hideControlsBar(): void {\n if (isPlaying.value) {\n showControls.value = false\n }\n }\n\n // 处理进度条点击\n async function handleProgressClick(event: MouseEvent): Promise<void> {\n if (duration.value === 0) return\n\n const target = event.currentTarget as HTMLElement\n const rect = target.getBoundingClientRect()\n const clickX = event.clientX - rect.left\n const percentage = clickX / rect.width\n const targetTime = percentage * duration.value\n\n await seek(targetTime)\n }\n\n // 处理进度条悬停\n function handleProgressHover(event: MouseEvent): void {\n if (duration.value === 0) return\n\n const target = event.currentTarget as HTMLElement\n const rect = target.getBoundingClientRect()\n const hoverX = event.clientX - rect.left\n const percentage = Math.max(0, Math.min(1, hoverX / rect.width))\n\n hoverTime.value = percentage * duration.value\n hoverPosition.value = percentage * 100\n }\n\n // 格式化时间\n function formatTime(ms: number): string {\n const totalSeconds = Math.floor(ms / 1000)\n const hours = Math.floor(totalSeconds / 3600)\n const minutes = Math.floor((totalSeconds % 3600) / 60)\n const seconds = totalSeconds % 60\n\n if (hours > 0) {\n return `${hours}:${minutes.toString().padStart(2, '0')}:${seconds.toString().padStart(2, '0')}`\n }\n return `${minutes}:${seconds.toString().padStart(2, '0')}`\n }\n\n return {\n showControls,\n hoverTime,\n hoverPosition,\n playProgress,\n bufferProgress,\n showControlsBar,\n hideControlsBar,\n handleProgressClick,\n handleProgressHover,\n formatTime\n }\n}\n","/**\n * 环境信息逻辑\n */\n\nimport { ref, computed, onMounted, type Ref } from 'vue'\nimport { EnvDetector, type EnvInfo } from '@give-tech/ec-player'\n\n/**\n * 环境信息逻辑返回值\n */\nexport interface UseEnvInfoReturn {\n /** 环境信息 */\n envInfo: Ref<EnvInfo | null>\n /** 是否显示环境面板 */\n showEnvPanel: Ref<boolean>\n /** 环境类型文本 */\n envTypeText: Ref<string>\n /** 切换环境面板显示 */\n toggleEnvPanel: () => void\n /** 检测环境 */\n detectEnv: () => void\n}\n\n/**\n * 环境信息逻辑 Hook\n */\nexport function useEnvInfo(\n initialShowPanel: boolean = false\n): UseEnvInfoReturn {\n const envInfo = ref<EnvInfo | null>(null)\n const showEnvPanel = ref(initialShowPanel)\n\n // 环境类型文本\n const envTypeText = computed(() => {\n if (!envInfo.value) return '未知'\n const typeMap: Record<string, string> = {\n 'pc-browser': 'PC 浏览器',\n 'mobile-browser': '移动端浏览器',\n 'wechat-miniprogram': '微信小程序',\n 'alipay-miniprogram': '支付宝小程序',\n 'other-miniprogram': '其他小程序',\n 'unknown': '未知',\n }\n return typeMap[envInfo.value.platform] || envInfo.value.platform\n })\n\n // 切换环境面板显示\n function toggleEnvPanel(): void {\n showEnvPanel.value = !showEnvPanel.value\n }\n\n // 检测环境\n function detectEnv(): void {\n envInfo.value = EnvDetector.detect()\n console.log('[EcPlayer] 环境检测结果:', envInfo.value)\n }\n\n // 组件挂载时检测环境\n onMounted(() => {\n detectEnv()\n })\n\n return {\n envInfo,\n showEnvPanel,\n envTypeText,\n toggleEnvPanel,\n detectEnv\n }\n}\n","<template>\n <div class=\"gt-player-container\" ref=\"containerRef\">\n <div\n class=\"gt-video-wrapper\"\n ref=\"videoWrapperRef\"\n @mouseenter=\"controls.showControlsBar\"\n @mousemove=\"controls.showControlsBar\"\n @mouseleave=\"controls.hideControlsBar\"\n >\n <!-- Canvas 视频渲染 -->\n <canvas ref=\"canvasRef\" class=\"gt-player-canvas\"></canvas>\n\n <!-- 封面/占位内容(未加载时显示) -->\n <div v-if=\"!player.state.isLoaded\" class=\"gt-placeholder\">\n <slot name=\"placeholder\"></slot>\n </div>\n\n <!-- 环境信息面板 -->\n <div v-if=\"showEnvPanel && envInfo\" class=\"gt-env-panel\">\n <div class=\"gt-env-row\">\n <span>platform</span>\n <span :class=\"envInfo.isMiniProgram ? 'warn' : ''\">{{ envTypeText }}</span>\n </div>\n <div class=\"gt-env-divider\"></div>\n <div class=\"gt-env-row\">\n <span>SIMD</span>\n <span :class=\"envInfo.capabilities.wasmSimd ? 'ok' : 'err'\">\n {{ envInfo.capabilities.wasmSimd ? 'Yes' : 'No' }}\n </span>\n </div>\n <div class=\"gt-env-row\">\n <span>WebGL</span>\n <span :class=\"envInfo.capabilities.webGL ? 'ok' : 'err'\">\n {{ envInfo.capabilities.webGL ? 'Yes' : 'No' }}\n </span>\n </div>\n <div class=\"gt-env-row\">\n <span>WebGL2</span>\n <span :class=\"envInfo.capabilities.webGL2 ? 'ok' : 'err'\">\n {{ envInfo.capabilities.webGL2 ? 'Yes' : 'No' }}\n </span>\n </div>\n <div class=\"gt-env-row\">\n <span>SAB</span>\n <span :class=\"envInfo.capabilities.sharedArrayBuffer ? 'ok' : 'err'\">\n {{ envInfo.capabilities.sharedArrayBuffer ? 'Yes' : 'No' }}\n </span>\n </div>\n <div class=\"gt-env-row\">\n <span>Threads</span>\n <span :class=\"envInfo.capabilities.wasmThreads ? 'ok' : 'err'\">\n {{ envInfo.capabilities.wasmThreads ? 'Yes' : 'No' }}\n </span>\n </div>\n <div class=\"gt-env-row\">\n <span>WebAudio</span>\n <span :class=\"envInfo.capabilities.webAudio ? 'ok' : 'err'\">\n {{ envInfo.capabilities.webAudio ? 'Yes' : 'No' }}\n </span>\n </div>\n <div class=\"gt-env-row\">\n <span>Stream</span>\n <span :class=\"envInfo.capabilities.readableStream ? 'ok' : 'err'\">\n {{ envInfo.capabilities.readableStream ? 'Yes' : 'No' }}\n </span>\n </div>\n <template v-if=\"player.state.isLoaded\">\n <div class=\"gt-env-divider\"></div>\n <div class=\"gt-env-row\" v-if=\"player.detectedFormat.value\"><span>Format</span><span>{{ player.detectedFormat.value }}</span></div>\n <div class=\"gt-env-row\"><span>FPS</span><span>{{ player.state.fps }}</span></div>\n <div class=\"gt-env-row\"><span>Resolution</span><span>{{ player.state.resolution }}</span></div>\n <div class=\"gt-env-row\"><span>downloaded</span><span>{{ player.state.downloaded }}</span></div>\n <div class=\"gt-env-row\"><span>decoded</span><span>{{ player.state.decoded }}</span></div>\n <div class=\"gt-env-row\"><span>Dropped</span><span>{{ player.state.droppedFrames }}</span></div>\n <div class=\"gt-env-row\"><span>Speed</span><span>{{ player.state.downloadSpeed || 0 }} KB/s</span></div>\n </template>\n </div>\n\n <!-- 加载中动画 -->\n <div class=\"gt-loading-spinner\" v-if=\"player.isLoading.value\">\n <slot name=\"loading\">\n <div class=\"gt-spinner\"></div>\n </slot>\n </div>\n\n <!-- 视频控制条 -->\n <div\n v-if=\"controlOption.show\"\n class=\"gt-video-controls\"\n :class=\"{ visible: controls.showControls.value || !player.state.isPlaying }\"\n >\n <button class=\"gt-control-btn\" @click=\"togglePlayback\">\n <svg v-if=\"player.state.isPlaying\" viewBox=\"0 0 24 24\" fill=\"currentColor\">\n <rect x=\"6\" y=\"4\" width=\"4\" height=\"16\" rx=\"1\"/>\n <rect x=\"14\" y=\"4\" width=\"4\" height=\"16\" rx=\"1\"/>\n </svg>\n <svg v-else viewBox=\"0 0 24 24\" fill=\"currentColor\">\n <path d=\"M8 5v14l11-7z\"/>\n </svg>\n </button>\n\n <!-- 直播标识 -->\n <span class=\"gt-live-indicator\" v-if=\"isLive\">\n <span class=\"gt-live-dot\"></span>\n <span class=\"gt-live-text\">实时</span>\n </span>\n\n <!-- 点播时间显示 -->\n <span class=\"gt-time-display\" v-else>\n <span class=\"gt-time-current\">{{ controls.formatTime(player.state.currentTime) }}</span>\n <span class=\"gt-time-separator\">/</span>\n <span class=\"gt-time-duration\">{{ controls.formatTime(player.state.duration) }}</span>\n </span>\n\n <!-- 进度条 (仅点播) -->\n <div\n v-if=\"!isLive\"\n class=\"gt-progress-container\"\n @click=\"controls.handleProgressClick\"\n @mousemove=\"controls.handleProgressHover\"\n @mouseleave=\"controls.hoverTime.value = null\"\n >\n <div class=\"gt-progress-bar\">\n <div class=\"gt-progress-buffered\" :style=\"{ width: controls.bufferProgress.value + '%' }\"></div>\n <div class=\"gt-progress-played\" :style=\"{ width: controls.playProgress.value + '%' }\">\n <div class=\"gt-progress-handle\"></div>\n </div>\n </div>\n <div\n class=\"gt-progress-tooltip\"\n v-if=\"controls.hoverTime.value !== null\"\n :style=\"{ left: controls.hoverPosition.value + '%' }\"\n >\n {{ controls.formatTime(controls.hoverTime.value) }}\n </div>\n </div>\n\n <!-- 直播流占位符 -->\n <div class=\"gt-flex-spacer\" v-else></div>\n\n <!-- 环境信息按钮 -->\n <button v-if=\"controlOption.info\" class=\"gt-control-btn gt-env-info-btn\" @click=\"toggleEnvPanel\" :title=\"showEnvPanel ? '隐藏信息' : '显示信息'\">\n <svg viewBox=\"0 0 24 24\" fill=\"currentColor\">\n <path d=\"M12 2C6.48 2 2 6.48 2 12s4.48 10 10 10 10-4.48 10-10S17.52 2 12 2zm1 15h-2v-6h2v6zm0-8h-2V7h2v2z\"/>\n </svg>\n </button>\n\n <!-- 全屏按钮 -->\n <button v-if=\"controlOption.fullscreen\" class=\"gt-control-btn gt-fullscreen-btn\" @click=\"toggleFullscreen\" :title=\"isFullscreen ? '退出全屏' : '全屏'\">\n <!-- 退出全屏图标 -->\n <svg v-if=\"isFullscreen\" viewBox=\"0 0 24 24\" fill=\"currentColor\">\n <path d=\"M5 16h3v3h2v-5H5v2zm3-8H5v2h5V5H8v3zm6 11h2v-3h3v-2h-5v5zm2-11V5h-2v5h5V8h-3z\"/>\n </svg>\n <!-- 全屏图标 -->\n <svg v-else viewBox=\"0 0 24 24\" fill=\"currentColor\">\n <path d=\"M7 14H5v5h5v-2H7v-3zm-2-4h2V7h3V5H5v5zm12 7h-3v2h5v-5h-2v3zM14 5v2h3v3h2V5h-5z\"/>\n </svg>\n </button>\n </div>\n\n <!-- 大播放按钮(居中) -->\n <div\n class=\"gt-center-play-btn\"\n v-if=\"player.state.isLoaded && !player.state.isPlaying\"\n @click=\"togglePlayback\"\n >\n <svg viewBox=\"0 0 24 24\" fill=\"currentColor\">\n <path d=\"M8 5v14l11-7z\"/>\n </svg>\n </div>\n </div>\n </div>\n</template>\n\n<script setup lang=\"ts\">\nimport { computed, ref, watch, onMounted, onUnmounted } from 'vue'\nimport { usePlayer } from '../composables/usePlayer'\nimport { useControls } from '../composables/useControls'\nimport { useEnvInfo } from '../composables/useEnvInfo'\nimport type { EcPlayerProps, EcPlayerExpose, EcPlayerSource, EcPlayerControlOption } from '../types'\nimport { DEFAULT_EC_PLAYER_PROPS } from '../types'\n\n// Props\nconst props = withDefaults(defineProps<EcPlayerProps>(), DEFAULT_EC_PLAYER_PROPS)\n\n// Emits\nconst emit = defineEmits<{\n (e: 'play'): void\n (e: 'pause'): void\n}>()\n\n// Canvas ref(本地)\nconst canvasRef = ref<HTMLCanvasElement | null>(null)\n\n// 容器引用(用于全屏)\nconst containerRef = ref<HTMLElement | null>(null)\n\n// 全屏状态\nconst isFullscreen = ref(false)\n\n// 解析 controlOption\nconst controlOption = computed<Required<EcPlayerControlOption>>(() => ({\n show: props.controlOption?.show ?? DEFAULT_EC_PLAYER_PROPS.controlOption.show,\n fullscreen: props.controlOption?.fullscreen ?? DEFAULT_EC_PLAYER_PROPS.controlOption.fullscreen,\n info: props.controlOption?.info ?? DEFAULT_EC_PLAYER_PROPS.controlOption.info\n}))\n\n// 环境信息逻辑\nconst { envInfo, showEnvPanel, envTypeText, toggleEnvPanel } = useEnvInfo(false)\n\n// 播放器逻辑\nconst player = usePlayer(emit)\n\n// 同步 canvas ref 到 player\nwatch(canvasRef, (el) => {\n player.canvasRef.value = el\n}, { immediate: true })\n\n// isLive 计算属性(用于模板)\nconst isLive = computed(() => player.isLive.value)\n\n// 控制条逻辑\nconst isPlayingRef = computed(() => player.state.isPlaying)\nconst isLoadedRef = computed(() => player.state.isLoaded)\nconst currentTimeRef = computed(() => player.state.currentTime)\nconst durationRef = computed(() => player.state.duration)\nconst segmentIndexRef = computed(() => player.state.segmentIndex)\nconst totalSegmentsRef = computed(() => player.state.totalSegments)\n\nconst controls = useControls({\n isPlaying: isPlayingRef,\n isLoaded: isLoadedRef,\n currentTime: currentTimeRef,\n duration: durationRef,\n segmentIndex: segmentIndexRef,\n totalSegments: totalSegmentsRef,\n isLive,\n seek: player.seek\n})\n\n// 视频包装器引用\nconst videoWrapperRef = ref<HTMLElement | null>(null)\n\n// 解析 src\nfunction parseSrc(src: EcPlayerSource | undefined): { url: string; isLive: boolean } | null {\n if (!src || !src.url) return null\n return { url: src.url, isLive: src.isLive ?? false }\n}\n\n// 切换播放/暂停\nfunction togglePlayback(): void {\n if (player.state.isPlaying) {\n player.pause()\n } else {\n player.resume()\n }\n}\n\n// 切换全屏\nfunction toggleFullscreen(): void {\n if (!containerRef.value) return\n\n if (!isFullscreen.value) {\n if (containerRef.value.requestFullscreen) {\n containerRef.value.requestFullscreen()\n }\n } else {\n if (document.exitFullscreen) {\n document.exitFullscreen()\n }\n }\n}\n\n// 监听全屏变化\nfunction handleFullscreenChange(): void {\n isFullscreen.value = !!document.fullscreenElement\n}\n\n// 暴露的 play 方法(简化版)\nfunction play(): void {\n const parsed = parseSrc(props.src)\n if (parsed) {\n player.play(parsed)\n }\n}\n\n// 监听 src 变化,自动播放\nwatch(() => props.src, (newSrc) => {\n const parsed = parseSrc(newSrc)\n if (parsed && parsed.url) {\n player.play(parsed)\n }\n}, { immediate: true, deep: true })\n\n// 挂载时监听全屏事件\nonMounted(() => {\n document.addEventListener('fullscreenchange', handleFullscreenChange)\n})\n\n// 卸载时移除监听\nonUnmounted(() => {\n document.removeEventListener('fullscreenchange', handleFullscreenChange)\n})\n\n// Expose 方法\ndefineExpose<EcPlayerExpose>({\n play,\n pause: player.pause,\n seek: player.seek\n})\n</script>\n\n<style scoped>\n.gt-player-container {\n width: 100%;\n height: 100%;\n}\n\n.gt-video-wrapper {\n position: relative;\n width: 100%;\n height: 100%;\n background: #000;\n overflow: hidden;\n}\n\n.gt-player-canvas {\n position: absolute;\n top: 50%;\n left: 50%;\n transform: translate(-50%, -50%);\n max-width: 100%;\n max-height: 100%;\n}\n\n.gt-placeholder {\n position: absolute;\n top: 0;\n left: 0;\n width: 100%;\n height: 100%;\n display: flex;\n align-items: center;\n justify-content: center;\n background: #000;\n}\n\n/* 加载中动画 */\n.gt-loading-spinner {\n position: absolute;\n top: 0;\n left: 0;\n right: 0;\n bottom: 0;\n display: flex;\n align-items: center;\n justify-content: center;\n background: rgba(0, 0, 0, 0.5);\n z-index: 10;\n}\n\n.gt-spinner {\n width: 8vmin;\n height: 8vmin;\n border: 0.5vmin solid rgba(255, 255, 255, 0.3);\n border-top-color: #fff;\n border-radius: 50%;\n animation: gt-spin 1s linear infinite;\n}\n\n@keyframes gt-spin {\n to {\n transform: rotate(360deg);\n }\n}\n\n/* 视频控制条 */\n.gt-video-controls {\n position: absolute;\n bottom: 0;\n left: 0;\n right: 0;\n padding: 10px 16px;\n background: linear-gradient(transparent, rgba(0, 0, 0, 0.7));\n opacity: 0;\n transition: opacity 0.3s ease;\n display: flex;\n align-items: center;\n gap: 12px;\n}\n\n.gt-flex-spacer {\n flex: 1;\n}\n\n.gt-video-controls.visible {\n opacity: 1;\n}\n\n.gt-control-btn {\n width: 28px;\n height: 28px;\n border: none;\n border-radius: 50%;\n background: transparent;\n color: white;\n cursor: pointer;\n display: flex;\n align-items: center;\n justify-content: center;\n transition: all 0.2s ease;\n flex-shrink: 0;\n}\n\n.gt-control-btn:hover {\n background: rgba(255, 255, 255, 0.2);\n}\n\n.gt-control-btn svg {\n width: 14px;\n height: 14px;\n}\n\n.gt-progress-container {\n flex: 1;\n position: relative;\n cursor: pointer;\n height: 20px;\n display: flex;\n align-items: center;\n}\n\n.gt-progress-bar {\n width: 100%;\n height: 4px;\n background: rgba(255, 255, 255, 0.2);\n border-radius: 2px;\n position: relative;\n overflow: hidden;\n transition: height 0.2s ease;\n}\n\n.gt-progress-container:hover .gt-progress-bar {\n height: 6px;\n}\n\n.gt-progress-buffered {\n position: absolute;\n top: 0;\n left: 0;\n height: 100%;\n background: rgba(255, 255, 255, 0.4);\n border-radius: 2px;\n transition: width 0.1s;\n}\n\n.gt-progress-played {\n position: absolute;\n top: 0;\n left: 0;\n height: 100%;\n background: #ff2d55;\n border-radius: 2px;\n transition: width 0.1s;\n}\n\n.gt-progress-handle {\n position: absolute;\n right: -6px;\n top: 50%;\n transform: translateY(-50%);\n width: 14px;\n height: 14px;\n background: #ff2d55;\n border-radius: 50%;\n box-shadow: 0 2px 8px rgba(0, 0, 0, 0.3);\n opacity: 0;\n transition: opacity 0.2s, transform 0.2s;\n}\n\n.gt-progress-container:hover .gt-progress-handle {\n opacity: 1;\n transform: translateY(-50%) scale(1.2);\n}\n\n.gt-progress-tooltip {\n position: absolute;\n bottom: calc(100% + 8px);\n transform: translateX(-50%);\n background: rgba(0, 0, 0, 0.85);\n color: white;\n padding: 4px 8px;\n border-radius: 4px;\n font-size: 11px;\n white-space: nowrap;\n pointer-events: none;\n}\n\n.gt-time-display {\n color: white;\n font-size: 12px;\n font-family: -apple-system, BlinkMacSystemFont, 'Segoe UI', Roboto, sans-serif;\n white-space: nowrap;\n flex-shrink: 0;\n}\n\n.gt-time-separator {\n margin: 0 4px;\n opacity: 0.6;\n}\n\n/* 直播指示器 */\n.gt-live-indicator {\n display: flex;\n align-items: center;\n gap: 6px;\n color: white;\n font-size: 12px;\n font-weight: 500;\n}\n\n.gt-live-dot {\n width: 8px;\n height: 8px;\n background: #ff2d55;\n border-radius: 50%;\n animation: gt-live-pulse 1.5s ease-in-out infinite;\n}\n\n.gt-live-text {\n color: #ff2d55;\n}\n\n@keyframes gt-live-pulse {\n 0%, 100% {\n opacity: 1;\n }\n 50% {\n opacity: 0.4;\n }\n}\n\n/* 居中播放按钮 */\n.gt-center-play-btn {\n position: absolute;\n top: 50%;\n left: 50%;\n transform: translate(-50%, -50%);\n width: 56px;\n height: 56px;\n background: rgba(0, 0, 0, 0.5);\n border-radius: 50%;\n display: flex;\n align-items: center;\n justify-content: center;\n cursor: pointer;\n transition: all 0.2s ease;\n}\n\n.gt-center-play-btn:hover {\n background: rgba(0, 0, 0, 0.7);\n transform: translate(-50%, -50%) scale(1.05);\n}\n\n.gt-center-play-btn svg {\n width: 24px;\n height: 24px;\n color: white;\n margin-left: 3px;\n}\n\n/* 环境信息面板 */\n.gt-env-panel {\n position: absolute;\n top: 12px;\n left: 12px;\n background: rgba(0, 0, 0, 0.8);\n border-radius: 6px;\n padding: 8px 10px;\n font-size: 11px;\n font-family: 'SF Mono', 'Monaco', 'Consolas', monospace;\n min-width: 160px;\n max-width: 200px;\n max-height: calc(100% - 24px);\n overflow-y: auto;\n backdrop-filter: blur(10px);\n animation: gt-env-fade-in 0.15s ease;\n z-index: 15;\n}\n\n.gt-env-panel::-webkit-scrollbar {\n width: 4px;\n}\n\n.gt-env-panel::-webkit-scrollbar-track {\n background: transparent;\n}\n\n.gt-env-panel::-webkit-scrollbar-thumb {\n background: rgba(255, 255, 255, 0.3);\n border-radius: 2px;\n}\n\n@keyframes gt-env-fade-in {\n from { opacity: 0; transform: translateY(-4px); }\n to { opacity: 1; transform: translateY(0); }\n}\n\n.gt-env-panel .gt-env-row {\n display: flex;\n justify-content: space-between;\n align-items: center;\n padding: 2px 0;\n color: rgba(255, 255, 255, 0.7);\n}\n\n.gt-env-panel .gt-env-row span:first-child {\n color: rgba(255, 255, 255, 0.5);\n margin-right: 16px;\n}\n\n.gt-env-panel .gt-env-row span:last-child {\n font-variant-numeric: tabular-nums;\n}\n\n.gt-env-panel .gt-env-row .ok { color: #4caf50; }\n.gt-env-panel .gt-env-row .warn { color: #ff9800; }\n.gt-env-panel .gt-env-row .err { color: #f44336; }\n\n.gt-env-divider {\n height: 1px;\n background: rgba(255, 255, 255, 0.1);\n margin: 4px 0;\n}\n</style>\n"],"names":["globalConfig","setLogLevel","coreSetLogLevel","_createElementBlock","_createElementVNode","_unref","_openBlock","_renderSlot","_normalizeClass","_Fragment","_toDisplayString","_normalizeStyle"],"mappings":";;;AA2JO,MAAM,0BAA0B;AAAA,EACrC,KAAK;AAAA,EACL,eAAe;AAAA,IACb,MAAM;AAAA,IACN,YAAY;AAAA,IACZ,MAAM;AAAA,EAAA;AAEV;AAKO,MAAM,yBAAkD;AAAA,EAC7D,kBAAkB;AAAA,EAClB,iBAAiB;AAAA,EACjB,cAAc;AAChB;AAKO,MAAM,sBAAsC;AAAA,EACjD,MAAM;AAAA,EACN,SAAS;AACX;AAKA,IAAI,eAAqC,CAAA;AA2BlC,SAAS,kBAAkB,QAAoC;AACpE,iBAAe,EAAE,GAAG,cAAc,GAAG,OAAA;AACvC;AAKO,SAAS,kBAAwC;AACtD,SAAO,EAAE,GAAG,aAAA;AACd;AAKO,SAAS,gBAAgC;AAC9C,SAAO;AAAA,IACL,MAAM,aAAa,MAAM,QAAQ,oBAAoB;AAAA,IACrD,SAAS,aAAa,MAAM,WAAW,oBAAoB;AAAA,EAAA;AAE/D;AAKO,SAAS,gBAAgB,OAAsB;AACpD,SAAO;AAAA,IACL,KAAK,MAAM,OAAO,wBAAwB;AAAA,IAC1C,eAAe;AAAA,MACb,MAAM,MAAM,eAAe,QAAQ,aAAa,gBAAgB,wBAAwB,cAAc;AAAA,MACtG,YAAY,MAAM,eAAe,cAAc,wBAAwB,cAAc;AAAA,MACrF,MAAM,MAAM,eAAe,QAAQ,wBAAwB,cAAc;AAAA,IAAA;AAAA,EAC3E;AAEJ;AAKO,SAAS,uBAAuB,SAAiD;AACtF,SAAO;AAAA,IACL,kBAAkB,QAAQ,oBAAoB,aAAa,oBAAoB,uBAAuB;AAAA,IACtG,iBAAiB,QAAQ,mBAAmB,aAAa,mBAAmB,uBAAuB;AAAA,IACnG,cAAc,QAAQ,gBAAgB,aAAa,gBAAgB,uBAAuB;AAAA,EAAA;AAE9F;AAQO,SAAS,gBAAgB,gBAAiC;AAC/D,QAAM,aAAa,cAAA;AAGnB,MAAI,kBAAkB,WAAW,MAAM;AACrC,YAAQ,IAAI,+BAA+B,WAAW,IAAI;AAC1D,WAAO,WAAW;AAAA,EACpB;AAEA,MAAI,WAAW,SAAS;AACtB,YAAQ,IAAI,uDAAuD,WAAW,OAAO;AACrF,WAAO,WAAW;AAAA,EACpB;AAGA,UAAQ,IAAI,iEAAiE,WAAW,IAAI;AAC5F,SAAO,WAAW;AACpB;AC7NA,SAAS,aAAa,SAAsE;AAE1F,QAAM,UAAU,YAAY,OAAA;AAC5B,QAAM,WAAW,gBAAgB,QAAQ,aAAa,QAAQ;AAE9D,SAAO;AAAA,IACL;AAAA,IACA,kBAAkB,QAAQ;AAAA,IAC1B,iBAAiB,QAAQ;AAAA,IACzB,cAAc,QAAQ;AAAA,EAAA;AAE1B;AAKO,SAAS,UACd,MAIiB;AACjB,QAAM,YAAY,IAA8B,IAAI;AACpD,QAAM,SAAS,WAAgC,IAAI;AACnD,QAAM,YAAY,IAAI,KAAK;AAC3B,QAAM,iBAAiB,IAAI,EAAE;AAC7B,QAAM,SAAS,IAAI,KAAK;AAGxB,QAAMA,gBAAe,gBAAA;AACrB,QAAM,iBAAiB,SAAkC;AAAA,IACvD,kBAAkBA,cAAa,oBAAoB,uBAAuB;AAAA,IAC1E,iBAAiBA,cAAa,mBAAmB,uBAAuB;AAAA,IACxE,cAAcA,cAAa,gBAAgB,uBAAuB;AAAA,EAAA,CACnE;AAGD,QAAM,QAAQ,SAAwB;AAAA,IACpC,WAAW;AAAA,IACX,UAAU;AAAA,IACV,WAAW;AAAA,IACX,KAAK;AAAA,IACL,YAAY;AAAA,IACZ,SAAS;AAAA,IACT,YAAY;AAAA,IACZ,eAAe;AAAA,IACf,eAAe;AAAA,IACf,cAAc;AAAA,IACd,eAAe;AAAA,IACf,eAAe;AAAA,IACf,aAAa;AAAA,IACb,UAAU;AAAA,EAAA,CACX;AAGD,QAAM,YAA+B;AAAA,IACnC,eAAe,CAAC,YAAY;AAC1B,aAAO,OAAO,OAAO,OAAO;AAG5B,UAAI,QAAQ,cAAc,MAAM;AAC9B,aAAK,MAAM;AAAA,MACb,WAAW,QAAQ,cAAc,SAAS,MAAM,WAAW;AACzD,aAAK,OAAO;AAAA,MACd;AAAA,IACF;AAAA,IACA,SAAS,CAAC,UAAU;AAClB,cAAQ,MAAM,qBAAqB,KAAK;AAAA,IAC1C;AAAA,EAAA;AAIF,iBAAe,KAAK,SAA2D;AAC7E,UAAM,EAAE,KAAK,QAAQ,cAAc,UAAU;AAC7C,QAAI,CAAC,KAAK;AACR,cAAQ,MAAM,4BAA4B;AAC1C;AAAA,IACF;AAGA,QAAI,UAAU,SAAS,OAAO,OAAO;AACnC,cAAQ,IAAI,sDAAsD;AAClE,aAAO,MAAM,QAAA;AACb,aAAO,QAAQ;AAAA,IACjB;AAGA,QAAI,UAAU;AACd,WAAO,CAAC,UAAU,SAAS,UAAU,GAAG;AACtC,YAAM,IAAI,QAAQ,CAAA,YAAW,WAAW,SAAS,GAAG,CAAC;AACrD;AAAA,IACF;AAEA,QAAI,CAAC,UAAU,OAAO;AACpB,cAAQ,MAAM,qCAAqC;AACnD;AAAA,IACF;AAEA,cAAU,QAAQ;AAClB,WAAO,QAAQ;AAEf,QAAI;AAEF,UAAI,OAAO,OAAO;AAChB,eAAO,MAAM,QAAA;AACb,eAAO,QAAQ;AAAA,MACjB;AAGA,YAAM,YAAY;AAClB,YAAM,WAAW;AACjB,YAAM,MAAM;AACZ,YAAM,aAAa;AACnB,YAAM,UAAU;AAChB,YAAM,aAAa;AACnB,YAAM,gBAAgB;AACtB,YAAM,eAAe;AACrB,YAAM,gBAAgB;AACtB,YAAM,gBAAgB;AACtB,YAAM,cAAc;AACpB,YAAM,WAAW;AACjB,qBAAe,QAAQ;AAGvB,YAAM,SAA6D;AAAA,QACjE,GAAG,aAAa,cAAc;AAAA,QAC9B,QAAQ,UAAU;AAAA,QAClB,QAAQ;AAAA,MAAA;AAIV,aAAO,QAAQ,IAAI,aAAa,QAAQ,SAAS;AAGjD,YAAM,OAAO,MAAM,KAAK,KAAK,WAAW;AAGxC,qBAAe,QAAQ,OAAO,MAAM,kBAAA;AAGpC,YAAM,WAAW;AAGjB,YAAM,OAAO,MAAM,KAAA;AAEnB,cAAQ,IAAI,sCAAsC,eAAe,KAAK;AAAA,IACxE,SAAS,OAAY;AACnB,cAAQ,MAAM,8BAA8B,OAAO,WAAW,KAAK;AAAA,IACrE,UAAA;AACE,gBAAU,QAAQ;AAAA,IACpB;AAAA,EACF;AAGA,WAAS,WAAW,SAA8B;AAChD,QAAI,QAAQ,qBAAqB,QAAW;AAC1C,qBAAe,mBAAmB,QAAQ;AAAA,IAC5C;AACA,QAAI,QAAQ,oBAAoB,QAAW;AACzC,qBAAe,kBAAkB,QAAQ;AAAA,IAC3C;AACA,QAAI,QAAQ,iBAAiB,QAAW;AACtC,qBAAe,eAAe,QAAQ;AAAA,IACxC;AACA,YAAQ,IAAI,+BAA+B,cAAc;AAAA,EAC3D;AAGA,WAASC,cAAY,OAAqB;AACxCC,gBAAgB,KAAK;AAAA,EACvB;AAGA,WAAS,QAAc;AACrB,WAAO,OAAO,MAAA;AAAA,EAChB;AAGA,iBAAe,SAAwB;AACrC,QAAI,CAAC,OAAO,MAAO;AACnB,UAAM,OAAO,MAAM,KAAA;AAAA,EACrB;AAGA,iBAAe,KAAK,MAA6B;AAC/C,QAAI,CAAC,OAAO,MAAO;AACnB,UAAM,OAAO,MAAM,KAAK,IAAI;AAAA,EAC9B;AAGA,WAAS,YAAiC;AACxC,WAAO,OAAO;AAAA,EAChB;AAGA,WAAS,WAA0B;AACjC,WAAO,OAAO,OAAO,SAAA,KAAc,EAAE,GAAG,MAAA;AAAA,EAC1C;AAGA,WAAS,iBAAyB;AAChC,WAAO,OAAO,OAAO,eAAA,KAAoB;AAAA,EAC3C;AAGA,WAAS,cAAsB;AAC7B,WAAO,OAAO,OAAO,YAAA,KAAiB;AAAA,EACxC;AAGA,WAAS,UAAgB;AACvB,QAAI,OAAO,OAAO;AAChB,aAAO,MAAM,QAAA;AACb,aAAO,QAAQ;AAAA,IACjB;AAAA,EACF;AAGA,cAAY,MAAM;AAChB,YAAA;AAAA,EACF,CAAC;AAED,SAAO;AAAA,IACL;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IAAA,aACAD;AAAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,EAAA;AAEJ;ACnPO,SAAS,YAAY,QAA8C;AACxE,MAAI,oBAAmC;AACvC,QAAM;AAAA,IACJ;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,EAAA,IACE;AAEJ,QAAM,eAAe,IAAI,IAAI;AAC7B,QAAM,YAAY,IAAmB,IAAI;AACzC,QAAM,gBAAgB,IAAI,CAAC;AAG3B,QAAM,eAAe,SAAS,MAAM;AAClC,QAAI,SAAS,UAAU,EAAG,QAAO;AACjC,WAAQ,YAAY,QAAQ,SAAS,QAAS;AAAA,EAChD,CAAC;AAGD,QAAM,iBAAiB,SAAS,MAAM;AACpC,QAAI,cAAc,UAAU,EAAG,QAAO;AACtC,WAAQ,aAAa,QAAQ,cAAc,QAAS;AAAA,EACtD,CAAC;AAGD,WAAS,kBAAwB;AAC/B,iBAAa,QAAQ;AACrB,QAAI,mBAAmB;AACrB,mBAAa,iBAAiB;AAAA,IAChC;AACA,wBAAoB,OAAO,WAAW,MAAM;AAC1C,UAAI,UAAU,OAAO;AACnB,qBAAa,QAAQ;AAAA,MACvB;AAAA,IACF,GAAG,GAAI;AAAA,EACT;AAGA,WAAS,kBAAwB;AAC/B,QAAI,UAAU,OAAO;AACnB,mBAAa,QAAQ;AAAA,IACvB;AAAA,EACF;AAGA,iBAAe,oBAAoB,OAAkC;AACnE,QAAI,SAAS,UAAU,EAAG;AAE1B,UAAM,SAAS,MAAM;AACrB,UAAM,OAAO,OAAO,sBAAA;AACpB,UAAM,SAAS,MAAM,UAAU,KAAK;AACpC,UAAM,aAAa,SAAS,KAAK;AACjC,UAAM,aAAa,aAAa,SAAS;AAEzC,UAAM,KAAK,UAAU;AAAA,EACvB;AAGA,WAAS,oBAAoB,OAAyB;AACpD,QAAI,SAAS,UAAU,EAAG;AAE1B,UAAM,SAAS,MAAM;AACrB,UAAM,OAAO,OAAO,sBAAA;AACpB,UAAM,SAAS,MAAM,UAAU,KAAK;AACpC,UAAM,aAAa,KAAK,IAAI,GAAG,KAAK,IAAI,GAAG,SAAS,KAAK,KAAK,CAAC;AAE/D,cAAU,QAAQ,aAAa,SAAS;AACxC,kBAAc,QAAQ,aAAa;AAAA,EACrC;AAGA,WAAS,WAAW,IAAoB;AACtC,UAAM,eAAe,KAAK,MAAM,KAAK,GAAI;AACzC,UAAM,QAAQ,KAAK,MAAM,eAAe,IAAI;AAC5C,UAAM,UAAU,KAAK,MAAO,eAAe,OAAQ,EAAE;AACrD,UAAM,UAAU,eAAe;AAE/B,QAAI,QAAQ,GAAG;AACb,aAAO,GAAG,KAAK,IAAI,QAAQ,SAAA,EAAW,SAAS,GAAG,GAAG,CAAC,IAAI,QAAQ,SAAA,EAAW,SAAS,GAAG,GAAG,CAAC;AAAA,IAC/F;AACA,WAAO,GAAG,OAAO,IAAI,QAAQ,WAAW,SAAS,GAAG,GAAG,CAAC;AAAA,EAC1D;AAEA,SAAO;AAAA,IACL;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,EAAA;AAEJ;ACnIO,SAAS,WACd,mBAA4B,OACV;AAClB,QAAM,UAAU,IAAoB,IAAI;AACxC,QAAM,eAAe,IAAI,gBAAgB;AAGzC,QAAM,cAAc,SAAS,MAAM;AACjC,QAAI,CAAC,QAAQ,MAAO,QAAO;AAC3B,UAAM,UAAkC;AAAA,MACtC,cAAc;AAAA,MACd,kBAAkB;AAAA,MAClB,sBAAsB;AAAA,MACtB,sBAAsB;AAAA,MACtB,qBAAqB;AAAA,MACrB,WAAW;AAAA,IAAA;AAEb,WAAO,QAAQ,QAAQ,MAAM,QAAQ,KAAK,QAAQ,MAAM;AAAA,EAC1D,CAAC;AAGD,WAAS,iBAAuB;AAC9B,iBAAa,QAAQ,CAAC,aAAa;AAAA,EACrC;AAGA,WAAS,YAAkB;AACzB,YAAQ,QAAQ,YAAY,OAAA;AAC5B,YAAQ,IAAI,sBAAsB,QAAQ,KAAK;AAAA,EACjD;AAGA,YAAU,MAAM;AACd,cAAA;AAAA,EACF,CAAC;AAED,SAAO;AAAA,IACL;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,EAAA;AAEJ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;ACkHA,UAAM,QAAQ;AAGd,UAAM,OAAO;AAMb,UAAM,YAAY,IAA8B,IAAI;AAGpD,UAAM,eAAe,IAAwB,IAAI;AAGjD,UAAM,eAAe,IAAI,KAAK;AAG9B,UAAM,gBAAgB,SAA0C,OAAO;AAAA,MACrE,MAAM,MAAM,eAAe,QAAQ,wBAAwB,cAAc;AAAA,MACzE,YAAY,MAAM,eAAe,cAAc,wBAAwB,cAAc;AAAA,MACrF,MAAM,MAAM,eAAe,QAAQ,wBAAwB,cAAc;AAAA,IAAA,EACzE;AAGF,UAAM,EAAE,SAAS,cAAc,aAAa,eAAA,IAAmB,WAAW,KAAK;AAG/E,UAAM,SAAS,UAAU,IAAI;AAG7B,UAAM,WAAW,CAAC,OAAO;AACvB,aAAO,UAAU,QAAQ;AAAA,IAC3B,GAAG,EAAE,WAAW,MAAM;AAGtB,UAAM,SAAS,SAAS,MAAM,OAAO,OAAO,KAAK;AAGjD,UAAM,eAAe,SAAS,MAAM,OAAO,MAAM,SAAS;AAC1D,UAAM,cAAc,SAAS,MAAM,OAAO,MAAM,QAAQ;AACxD,UAAM,iBAAiB,SAAS,MAAM,OAAO,MAAM,WAAW;AAC9D,UAAM,cAAc,SAAS,MAAM,OAAO,MAAM,QAAQ;AACxD,UAAM,kBAAkB,SAAS,MAAM,OAAO,MAAM,YAAY;AAChE,UAAM,mBAAmB,SAAS,MAAM,OAAO,MAAM,aAAa;AAElE,UAAM,WAAW,YAAY;AAAA,MAC3B,WAAW;AAAA,MACX,UAAU;AAAA,MACV,aAAa;AAAA,MACb,UAAU;AAAA,MACV,cAAc;AAAA,MACd,eAAe;AAAA,MACf;AAAA,MACA,MAAM,OAAO;AAAA,IAAA,CACd;AAGD,UAAM,kBAAkB,IAAwB,IAAI;AAGpD,aAAS,SAAS,KAA0E;AAC1F,UAAI,CAAC,OAAO,CAAC,IAAI,IAAK,QAAO;AAC7B,aAAO,EAAE,KAAK,IAAI,KAAK,QAAQ,IAAI,UAAU,MAAA;AAAA,IAC/C;AAGA,aAAS,iBAAuB;AAC9B,UAAI,OAAO,MAAM,WAAW;AAC1B,eAAO,MAAA;AAAA,MACT,OAAO;AACL,eAAO,OAAA;AAAA,MACT;AAAA,IACF;AAGA,aAAS,mBAAyB;AAChC,UAAI,CAAC,aAAa,MAAO;AAEzB,UAAI,CAAC,aAAa,OAAO;AACvB,YAAI,aAAa,MAAM,mBAAmB;AACxC,uBAAa,MAAM,kBAAA;AAAA,QACrB;AAAA,MACF,OAAO;AACL,YAAI,SAAS,gBAAgB;AAC3B,mBAAS,eAAA;AAAA,QACX;AAAA,MACF;AAAA,IACF;AAGA,aAAS,yBAA+B;AACtC,mBAAa,QAAQ,CAAC,CAAC,SAAS;AAAA,IAClC;AAGA,aAAS,OAAa;AACpB,YAAM,SAAS,SAAS,MAAM,GAAG;AACjC,UAAI,QAAQ;AACV,eAAO,KAAK,MAAM;AAAA,MACpB;AAAA,IACF;AAGA,UAAM,MAAM,MAAM,KAAK,CAAC,WAAW;AACjC,YAAM,SAAS,SAAS,MAAM;AAC9B,UAAI,UAAU,OAAO,KAAK;AACxB,eAAO,KAAK,MAAM;AAAA,MACpB;AAAA,IACF,GAAG,EAAE,WAAW,MAAM,MAAM,MAAM;AAGlC,cAAU,MAAM;AACd,eAAS,iBAAiB,oBAAoB,sBAAsB;AAAA,IACtE,CAAC;AAGD,gBAAY,MAAM;AAChB,eAAS,oBAAoB,oBAAoB,sBAAsB;AAAA,IACzE,CAAC;AAGD,aAA6B;AAAA,MAC3B;AAAA,MACA,OAAO,OAAO;AAAA,MACd,MAAM,OAAO;AAAA,IAAA,CACd;;0BApTCE,mBA0KM,OAAA;AAAA,QA1KD,OAAM;AAAA,iBAA0B;AAAA,QAAJ,KAAI;AAAA,MAAA;QACnCC,mBAwKM,OAAA;AAAA,UAvKJ,OAAM;AAAA,mBACF;AAAA,UAAJ,KAAI;AAAA,UACH,cAAU,OAAA,CAAA,MAAA,OAAA,CAAA;AAAA,UAAE,IAAA,SAAAC,MAAA,QAAA,EAAS,mBAATA,MAAA,QAAA,EAAS,gBAAe,GAAA,IAAA;AAAA,UACpC,aAAS,OAAA,CAAA,MAAA,OAAA,CAAA;AAAA,UAAE,IAAA,SAAAA,MAAA,QAAA,EAAS,mBAATA,MAAA,QAAA,EAAS,gBAAe,GAAA,IAAA;AAAA,UACnC,cAAU,OAAA,CAAA,MAAA,OAAA,CAAA;AAAA,UAAE,IAAA,SAAAA,MAAA,QAAA,EAAS,mBAATA,MAAA,QAAA,EAAS,gBAAe,GAAA,IAAA;AAAA,QAAA;UAGrCD,mBAA0D,UAAA;AAAA,qBAA9C;AAAA,YAAJ,KAAI;AAAA,YAAY,OAAM;AAAA,UAAA;WAGlBC,MAAA,MAAA,EAAO,MAAM,YAAzBC,aAAAH,mBAEM,OAFN,YAEM;AAAA,YADJI,WAAgC,KAAA,QAAA,eAAA,CAAA,GAAA,QAAA,IAAA;AAAA,UAAA;UAIvBF,MAAA,YAAA,KAAgBA,MAAA,OAAA,KAA3BC,aAAAH,mBA0DM,OA1DN,YA0DM;AAAA,YAzDJC,mBAGM,OAHN,YAGM;AAAA,cAFJ,OAAA,CAAA,MAAA,OAAA,CAAA,IAAAA,mBAAqB,cAAf,YAAQ,EAAA;AAAA,cACdA,mBAA2E,QAAA;AAAA,gBAApE,OAAKI,eAAEH,MAAA,OAAA,EAAQ,gBAAa,SAAA,EAAA;AAAA,cAAA,mBAAmBA,MAAA,WAAA,CAAW,GAAA,CAAA;AAAA,YAAA;wCAEnED,mBAAkC,OAAA,EAA7B,OAAM,iBAAA,GAAgB,MAAA,EAAA;AAAA,YAC3BA,mBAKM,OALN,YAKM;AAAA,cAJJ,OAAA,CAAA,MAAA,OAAA,CAAA,IAAAA,mBAAiB,cAAX,QAAI,EAAA;AAAA,cACVA,mBAEO,QAAA;AAAA,gBAFA,OAAKI,eAAEH,MAAA,OAAA,EAAQ,aAAa,WAAQ,OAAA,KAAA;AAAA,cAAA,mBACtCA,MAAA,OAAA,EAAQ,aAAa,WAAQ,QAAA,IAAA,GAAA,CAAA;AAAA,YAAA;YAGpCD,mBAKM,OALN,YAKM;AAAA,cAJJ,OAAA,CAAA,MAAA,OAAA,CAAA,IAAAA,mBAAkB,cAAZ,SAAK,EAAA;AAAA,cACXA,mBAEO,QAAA;AAAA,gBAFA,OAAKI,eAAEH,MAAA,OAAA,EAAQ,aAAa,QAAK,OAAA,KAAA;AAAA,cAAA,mBACnCA,MAAA,OAAA,EAAQ,aAAa,QAAK,QAAA,IAAA,GAAA,CAAA;AAAA,YAAA;YAGjCD,mBAKM,OALN,YAKM;AAAA,cAJJ,OAAA,EAAA,MAAA,OAAA,EAAA,IAAAA,mBAAmB,cAAb,UAAM,EAAA;AAAA,cACZA,mBAEO,QAAA;AAAA,gBAFA,OAAKI,eAAEH,MAAA,OAAA,EAAQ,aAAa,SAAM,OAAA,KAAA;AAAA,cAAA,mBACpCA,MAAA,OAAA,EAAQ,aAAa,SAAM,QAAA,IAAA,GAAA,CAAA;AAAA,YAAA;YAGlCD,mBAKM,OALN,YAKM;AAAA,cAJJ,OAAA,EAAA,MAAA,OAAA,EAAA,IAAAA,mBAAgB,cAAV,OAAG,EAAA;AAAA,cACTA,mBAEO,QAAA;AAAA,gBAFA,OAAKI,eAAEH,MAAA,OAAA,EAAQ,aAAa,oBAAiB,OAAA,KAAA;AAAA,cAAA,mBAC/CA,MAAA,OAAA,EAAQ,aAAa,oBAAiB,QAAA,IAAA,GAAA,CAAA;AAAA,YAAA;YAG7CD,mBAKM,OALN,YAKM;AAAA,cAJJ,OAAA,EAAA,MAAA,OAAA,EAAA,IAAAA,mBAAoB,cAAd,WAAO,EAAA;AAAA,cACbA,mBAEO,QAAA;AAAA,gBAFA,OAAKI,eAAEH,MAAA,OAAA,EAAQ,aAAa,cAAW,OAAA,KAAA;AAAA,cAAA,mBACzCA,MAAA,OAAA,EAAQ,aAAa,cAAW,QAAA,IAAA,GAAA,CAAA;AAAA,YAAA;YAGvCD,mBAKM,OALN,YAKM;AAAA,cAJJ,OAAA,EAAA,MAAA,OAAA,EAAA,IAAAA,mBAAqB,cAAf,YAAQ,EAAA;AAAA,cACdA,mBAEO,QAAA;AAAA,gBAFA,OAAKI,eAAEH,MAAA,OAAA,EAAQ,aAAa,WAAQ,OAAA,KAAA;AAAA,cAAA,mBACtCA,MAAA,OAAA,EAAQ,aAAa,WAAQ,QAAA,IAAA,GAAA,CAAA;AAAA,YAAA;YAGpCD,mBAKM,OALN,aAKM;AAAA,cAJJ,OAAA,EAAA,MAAA,OAAA,EAAA,IAAAA,mBAAmB,cAAb,UAAM,EAAA;AAAA,cACZA,mBAEO,QAAA;AAAA,gBAFA,OAAKI,eAAEH,MAAA,OAAA,EAAQ,aAAa,iBAAc,OAAA,KAAA;AAAA,cAAA,mBAC5CA,MAAA,OAAA,EAAQ,aAAa,iBAAc,QAAA,IAAA,GAAA,CAAA;AAAA,YAAA;YAG1BA,MAAA,MAAA,EAAO,MAAM,yBAA7BF,mBASWM,UAAA,EAAA,KAAA,EAAA,GAAA;AAAA,0CARTL,mBAAkC,OAAA,EAA7B,OAAM,iBAAA,GAAgB,MAAA,EAAA;AAAA,cACGC,MAAA,MAAA,EAAO,eAAe,SAApDC,aAAAH,mBAAkI,OAAlI,aAAkI;AAAA,gBAAvE,OAAA,EAAA,MAAA,OAAA,EAAA,IAAAC,mBAAmB,cAAb,UAAM,EAAA;AAAA,gBAAOA,mBAA8C,QAAA,MAAAM,gBAArCL,MAAA,MAAA,EAAO,eAAe,KAAK,GAAA,CAAA;AAAA,cAAA;cAClHD,mBAAiF,OAAjF,aAAiF;AAAA,gBAAzD,OAAA,EAAA,MAAA,OAAA,EAAA,IAAAA,mBAAgB,cAAV,OAAG,EAAA;AAAA,gBAAOA,mBAAmC,QAAA,MAAAM,gBAA1BL,MAAA,MAAA,EAAO,MAAM,GAAG,GAAA,CAAA;AAAA,cAAA;cACjED,mBAA+F,OAA/F,aAA+F;AAAA,gBAAvE,OAAA,EAAA,MAAA,OAAA,EAAA,IAAAA,mBAAuB,cAAjB,cAAU,EAAA;AAAA,gBAAOA,mBAA0C,QAAA,MAAAM,gBAAjCL,MAAA,MAAA,EAAO,MAAM,UAAU,GAAA,CAAA;AAAA,cAAA;cAC/ED,mBAA+F,OAA/F,aAA+F;AAAA,gBAAvE,OAAA,EAAA,MAAA,OAAA,EAAA,IAAAA,mBAAuB,cAAjB,cAAU,EAAA;AAAA,gBAAOA,mBAA0C,QAAA,MAAAM,gBAAjCL,MAAA,MAAA,EAAO,MAAM,UAAU,GAAA,CAAA;AAAA,cAAA;cAC/ED,mBAAyF,OAAzF,aAAyF;AAAA,gBAAjE,OAAA,EAAA,MAAA,OAAA,EAAA,IAAAA,mBAAoB,cAAd,WAAO,EAAA;AAAA,gBAAOA,mBAAuC,QAAA,MAAAM,gBAA9BL,MAAA,MAAA,EAAO,MAAM,OAAO,GAAA,CAAA;AAAA,cAAA;cACzED,mBAA+F,OAA/F,aAA+F;AAAA,gBAAvE,OAAA,EAAA,MAAA,OAAA,EAAA,IAAAA,mBAAoB,cAAd,WAAO,EAAA;AAAA,gBAAOA,mBAA6C,QAAA,MAAAM,gBAApCL,MAAA,MAAA,EAAO,MAAM,aAAa,GAAA,CAAA;AAAA,cAAA;cAC/ED,mBAAuG,OAAvG,aAAuG;AAAA,gBAA/E,OAAA,EAAA,MAAA,OAAA,EAAA,IAAAA,mBAAkB,cAAZ,SAAK,EAAA;AAAA,gBAAOA,mBAAuD,8BAA9CC,MAAA,MAAA,EAAO,MAAM,sBAAqB,SAAK,CAAA;AAAA,cAAA;;;UAKxDA,MAAA,MAAA,EAAO,UAAU,SAAvDC,aAAAH,mBAIM,OAJN,aAIM;AAAA,YAHJI,WAEO,4BAFP,MAEO;AAAA,0CADLH,mBAA8B,OAAA,EAAzB,OAAM,gBAAY,MAAA,EAAA;AAAA,YAAA;;UAMnB,cAAA,MAAc,qBADtBD,mBAwEM,OAAA;AAAA;YAtEJ,OAAKK,eAAA,CAAC,qBAAmB,EAAA,SACNH,MAAA,QAAA,EAAS,aAAa,SAAK,CAAKA,MAAA,MAAA,EAAO,MAAM,WAAS,CAAA;AAAA,UAAA;YAEzED,mBAQS,UAAA;AAAA,cARD,OAAM;AAAA,cAAkB,SAAO;AAAA,YAAA;cAC1BC,MAAA,MAAA,EAAO,MAAM,aAAxBC,aAAAH,mBAGM,OAHN,aAGM,CAAA,GAAA,OAAA,EAAA,MAAA,OAAA,EAAA,IAAA;AAAA,gBAFJC,mBAAgD,QAAA;AAAA,kBAA1C,GAAE;AAAA,kBAAI,GAAE;AAAA,kBAAI,OAAM;AAAA,kBAAI,QAAO;AAAA,kBAAK,IAAG;AAAA,gBAAA;gBAC3CA,mBAAiD,QAAA;AAAA,kBAA3C,GAAE;AAAA,kBAAK,GAAE;AAAA,kBAAI,OAAM;AAAA,kBAAI,QAAO;AAAA,kBAAK,IAAG;AAAA,gBAAA;uBAE9CE,aAAAH,mBAEM,OAFN,aAEM,CAAA,GAAA,OAAA,EAAA,MAAA,OAAA,EAAA,IAAA;AAAA,gBADJC,mBAAyB,QAAA,EAAnB,GAAE,gBAAA,GAAe,MAAA,EAAA;AAAA,cAAA;;YAKW,OAAA,SAAtCE,aAAAH,mBAGO,QAHP,aAGO,CAAA,GAAA,OAAA,EAAA,MAAA,OAAA,EAAA,IAAA;AAAA,cAFLC,mBAAiC,QAAA,EAA3B,OAAM,cAAA,GAAa,MAAA,EAAA;AAAA,cACzBA,mBAAoC,QAAA,EAA9B,OAAM,eAAA,GAAe,MAAE,EAAA;AAAA,YAAA,SAI/BE,aAAAH,mBAIO,QAJP,aAIO;AAAA,cAHLC,mBAAwF,QAAxF,aAAwFM,gBAAvDL,MAAA,QAAA,EAAS,WAAWA,MAAA,MAAA,EAAO,MAAM,WAAW,CAAA,GAAA,CAAA;AAAA,cAC7E,OAAA,EAAA,MAAA,OAAA,EAAA,IAAAD,mBAAwC,QAAA,EAAlC,OAAM,oBAAA,GAAoB,KAAC,EAAA;AAAA,cACjCA,mBAAsF,QAAtF,aAAsFM,gBAApDL,MAAA,QAAA,EAAS,WAAWA,MAAA,MAAA,EAAO,MAAM,QAAQ,CAAA,GAAA,CAAA;AAAA,YAAA;aAKpE,OAAA,sBADTF,mBAoBM,OAAA;AAAA;cAlBJ,OAAM;AAAA,cACL,SAAK,OAAA,CAAA,MAAA,OAAA,CAAA;AAAA,cAAE,IAAA,SAAAE,MAAA,QAAA,EAAS,uBAATA,MAAA,QAAA,EAAS,oBAAmB,GAAA,IAAA;AAAA,cACnC,aAAS,OAAA,CAAA,MAAA,OAAA,CAAA;AAAA,cAAE,IAAA,SAAAA,MAAA,QAAA,EAAS,uBAATA,MAAA,QAAA,EAAS,oBAAmB,GAAA,IAAA;AAAA,cACvC,cAAU,OAAA,CAAA,MAAA,OAAA,CAAA,IAAA,CAAA,WAAEA,MAAA,QAAA,EAAS,UAAU,QAAK;AAAA,YAAA;cAErCD,mBAKM,OALN,aAKM;AAAA,gBAJJA,mBAAgG,OAAA;AAAA,kBAA3F,OAAM;AAAA,kBAAwB,OAAKO,eAAA,EAAA,OAAWN,MAAA,QAAA,EAAS,eAAe,QAAK,IAAA,CAAA;AAAA,gBAAA;gBAChFD,mBAEM,OAAA;AAAA,kBAFD,OAAM;AAAA,kBAAsB,OAAKO,eAAA,EAAA,OAAWN,MAAA,QAAA,EAAS,aAAa,QAAK,IAAA,CAAA;AAAA,gBAAA;kBAC1ED,mBAAsC,OAAA,EAAjC,OAAM,qBAAA,GAAoB,MAAA,EAAA;AAAA,gBAAA;;cAK3BC,MAAA,QAAA,EAAS,UAAU,UAAK,qBAFhCF,mBAMM,OAAA;AAAA;gBALJ,OAAM;AAAA,gBAEL,OAAKQ,eAAA,EAAA,MAAUN,MAAA,QAAA,EAAS,cAAc,QAAK,IAAA,CAAA;AAAA,cAAA,GAEzCK,gBAAAL,MAAA,QAAA,EAAS,WAAWA,gBAAS,UAAU,KAAK,CAAA,GAAA,CAAA;uBAKnDC,aAAAH,mBAAyC,OAAzC,WAAyC;AAAA,YAG3B,cAAA,MAAc,qBAA5BA,mBAIS,UAAA;AAAA;cAJyB,OAAM;AAAA,cAAkC,SAAK,OAAA,CAAA,MAAA,OAAA,CAAA;AAAA,2BAAEE,MAAA,cAAA,KAAAA,MAAA,cAAA,EAAA,GAAA,IAAA;AAAA,cAAiB,OAAOA,MAAA,YAAA,IAAY,SAAA;AAAA,YAAA;cACnHD,mBAEM,OAAA;AAAA,gBAFD,SAAQ;AAAA,gBAAY,MAAK;AAAA,cAAA;gBAC5BA,mBAA4G,QAAA,EAAtG,GAAE,oGAAkG;AAAA,cAAA;;YAKhG,cAAA,MAAc,2BAA5BD,mBASS,UAAA;AAAA;cAT+B,OAAM;AAAA,cAAoC,SAAO;AAAA,cAAmB,OAAO,aAAA,QAAY,SAAA;AAAA,YAAA;cAElH,aAAA,SAAXG,aAAAH,mBAEM,OAFN,aAEM,CAAA,GAAA,OAAA,EAAA,MAAA,OAAA,EAAA,IAAA;AAAA,gBADJC,mBAAyF,QAAA,EAAnF,GAAE,gFAAA,GAA+E,MAAA,EAAA;AAAA,cAAA,SAGzFE,aAAAH,mBAEM,OAFN,aAEM,CAAA,GAAA,OAAA,EAAA,MAAA,OAAA,EAAA,IAAA;AAAA,gBADJC,mBAA0F,QAAA,EAApF,GAAE,iFAAA,GAAgF,MAAA,EAAA;AAAA,cAAA;;;UAQtFC,MAAA,MAAA,EAAO,MAAM,aAAaA,MAAA,MAAA,EAAO,MAAM,0BAF/CF,mBAQM,OAAA;AAAA;YAPJ,OAAM;AAAA,YAEL,SAAO;AAAA,UAAA;YAERC,mBAEM,OAAA;AAAA,cAFD,SAAQ;AAAA,cAAY,MAAK;AAAA,YAAA;cAC5BA,mBAAyB,QAAA,EAAnB,GAAE,iBAAe;AAAA,YAAA;;;;;;;;;;;;;;;"}
|
|
1
|
+
{"version":3,"file":"index.js","sources":["../src/types.ts","../src/composables/usePlayer.ts","../src/composables/useControls.ts","../src/composables/useEnvInfo.ts","../src/components/EcPlayer.vue"],"sourcesContent":["/**\n * Vue 组件类型定义\n */\n\nimport type { EcPlayerCoreConfig, EcPlayerState, EnvInfo } from '@give-tech/ec-player'\nexport { LogLevel } from '@give-tech/ec-player'\n\n/**\n * WASM 路径配置\n */\nexport interface WasmPathConfig {\n /**\n * SIMD 版本 WASM 路径(推荐,性能更好)\n * 用于支持 SIMD 的现代浏览器\n */\n simd?: string\n /**\n * 非 SIMD 版本 WASM 路径\n * 用于不支持 SIMD 的旧浏览器作为降级方案\n */\n nonSimd?: string\n}\n\n/**\n * 全局配置\n *\n * 必须在使用 EcPlayer 组件前调用\n *\n * @example\n * ```typescript\n * // main.ts\n * import { configureEcPlayer } from '@give-tech/ec-player-vue'\n *\n * // 配置 SIMD 和非 SIMD 路径,支持自动降级\n * configureEcPlayer({\n * wasm: {\n * simd: '/wasm/decoder-simd.js',\n * nonSimd: '/wasm/decoder.js'\n * }\n * })\n *\n * // 使用 CDN\n * configureEcPlayer({\n * wasm: {\n * simd: 'https://unpkg.com/@give-tech/ec-player@latest/wasm/decoder-simd.js',\n * nonSimd: 'https://unpkg.com/@give-tech/ec-player@latest/wasm/decoder.js'\n * }\n * })\n * ```\n */\nexport interface EcPlayerGlobalConfig {\n /**\n * WASM 路径配置(必填)\n * 支持 SIMD 和非 SIMD 自动降级\n */\n wasm?: WasmPathConfig\n /** 默认是否显示控制条 */\n showControls?: boolean\n /** 默认缓冲目标帧数 */\n targetBufferSize?: number\n /** 默认每批解码帧数 */\n decodeBatchSize?: number\n /** 默认队列上限 */\n maxQueueSize?: number\n}\n\n/**\n * 播放器配置选项\n */\nexport interface PlayerOptions {\n /** 帧缓冲区目标大小 */\n targetBufferSize?: number\n /** 每批解码帧数 */\n decodeBatchSize?: number\n /** NAL/Sample 队列上限 */\n maxQueueSize?: number\n}\n\n/**\n * 视频源配置\n */\nexport interface EcPlayerSource {\n /** 视频 URL */\n url: string\n /** 是否为直播流 */\n isLive?: boolean\n /** 版本号,用于强制重新加载 */\n version?: number\n}\n\n/**\n * 控制条选项\n */\nexport interface EcPlayerControlOption {\n /** 是否显示控制条 */\n show?: boolean\n /** 是否显示全屏按钮 */\n fullscreen?: boolean\n /** 是否显示环境信息按钮 */\n info?: boolean\n}\n\n/**\n * EcPlayer 组件 Props\n */\nexport interface EcPlayerProps {\n /** 视频源 */\n src?: EcPlayerSource\n /** 控制条选项 */\n controlOption?: EcPlayerControlOption\n}\n\n/**\n * EcPlayer 组件 Emits\n */\nexport interface EcPlayerEmits {\n /** 播放时触发 */\n (e: 'play'): void\n /** 暂停时触发 */\n (e: 'pause'): void\n}\n\n/**\n * EcPlayer 组件 Expose 方法\n */\nexport interface EcPlayerExpose {\n /** 播放 */\n play: () => void\n /** 暂停 */\n pause: () => void\n /** 跳转到指定时间(毫秒) */\n seek: (time: number) => Promise<void>\n}\n\n/**\n * 环境信息面板数据\n */\nexport interface EnvPanelData {\n envInfo: EnvInfo | null\n state: Partial<EcPlayerState>\n}\n\n/**\n * 播放器配置(从 Props 转换)\n */\nexport interface PlayerConfigFromProps extends EcPlayerCoreConfig {\n wasmPath: string\n targetBufferSize: number\n decodeBatchSize: number\n maxQueueSize: number\n}\n\n/**\n * 默认 Props 值\n */\nexport const DEFAULT_EC_PLAYER_PROPS = {\n src: undefined as EcPlayerSource | undefined,\n controlOption: {\n show: true,\n fullscreen: true,\n info: true\n }\n}\n\n/**\n * 默认播放器配置\n */\nexport const DEFAULT_PLAYER_OPTIONS: Required<PlayerOptions> = {\n targetBufferSize: 60,\n decodeBatchSize: 2,\n maxQueueSize: 200\n}\n\n/**\n * 默认 WASM 配置\n */\nexport const DEFAULT_WASM_CONFIG: WasmPathConfig = {\n simd: '/wasm/decoder-simd.js',\n nonSimd: '/wasm/decoder.js'\n}\n\n/**\n * 全局配置存储\n */\nlet globalConfig: EcPlayerGlobalConfig = {}\n\n/**\n * 配置 EcPlayer 全局默认值\n *\n * @example\n * ```typescript\n * // main.ts\n * import { configureEcPlayer } from '@give-tech/ec-player-vue'\n *\n * // 配置 SIMD 和非 SIMD 路径,支持自动降级\n * configureEcPlayer({\n * wasm: {\n * simd: '/wasm/decoder-simd.js',\n * nonSimd: '/wasm/decoder.js'\n * }\n * })\n *\n * // 使用 CDN\n * configureEcPlayer({\n * wasm: {\n * simd: 'https://unpkg.com/@give-tech/ec-player@latest/wasm/decoder-simd.js',\n * nonSimd: 'https://unpkg.com/@give-tech/ec-player@latest/wasm/decoder.js'\n * }\n * })\n * ```\n */\nexport function configureEcPlayer(config: EcPlayerGlobalConfig): void {\n globalConfig = { ...globalConfig, ...config }\n}\n\n/**\n * 获取全局配置\n */\nexport function getGlobalConfig(): EcPlayerGlobalConfig {\n return { ...globalConfig }\n}\n\n/**\n * 获取 WASM 路径配置\n */\nexport function getWasmConfig(): WasmPathConfig {\n return {\n simd: globalConfig.wasm?.simd ?? DEFAULT_WASM_CONFIG.simd,\n nonSimd: globalConfig.wasm?.nonSimd ?? DEFAULT_WASM_CONFIG.nonSimd\n }\n}\n\n/**\n * 获取合并后的配置(props > 全局配置 > 默认值)\n */\nexport function getMergedConfig(props: EcPlayerProps) {\n return {\n src: props.src ?? DEFAULT_EC_PLAYER_PROPS.src,\n controlOption: {\n show: props.controlOption?.show ?? globalConfig.showControls ?? DEFAULT_EC_PLAYER_PROPS.controlOption.show,\n fullscreen: props.controlOption?.fullscreen ?? DEFAULT_EC_PLAYER_PROPS.controlOption.fullscreen,\n info: props.controlOption?.info ?? DEFAULT_EC_PLAYER_PROPS.controlOption.info\n }\n }\n}\n\n/**\n * 获取合并后的播放器配置(options > 全局配置 > 默认值)\n */\nexport function getMergedPlayerOptions(options: PlayerOptions): Required<PlayerOptions> {\n return {\n targetBufferSize: options.targetBufferSize ?? globalConfig.targetBufferSize ?? DEFAULT_PLAYER_OPTIONS.targetBufferSize,\n decodeBatchSize: options.decodeBatchSize ?? globalConfig.decodeBatchSize ?? DEFAULT_PLAYER_OPTIONS.decodeBatchSize,\n maxQueueSize: options.maxQueueSize ?? globalConfig.maxQueueSize ?? DEFAULT_PLAYER_OPTIONS.maxQueueSize\n }\n}\n\n/**\n * 根据环境能力选择合适的 WASM 路径\n *\n * @param hasSimdSupport 是否支持 SIMD\n * @returns 实际使用的 WASM 路径\n */\nexport function resolveWasmPath(hasSimdSupport: boolean): string {\n const wasmConfig = getWasmConfig()\n\n // 根据 SIMD 支持情况选择\n if (hasSimdSupport && wasmConfig.simd) {\n console.log('[EcPlayer] Using SIMD WASM:', wasmConfig.simd)\n return wasmConfig.simd\n }\n\n if (wasmConfig.nonSimd) {\n console.log('[EcPlayer] SIMD not supported, using non-SIMD WASM:', wasmConfig.nonSimd)\n return wasmConfig.nonSimd\n }\n\n // 降级到 SIMD 版本(兜底)\n console.log('[EcPlayer] No non-SIMD path configured, falling back to SIMD:', wasmConfig.simd)\n return wasmConfig.simd!\n}\n","/**\n * 播放器核心逻辑\n */\n\nimport { ref, shallowRef, reactive, onUnmounted, type Ref } from 'vue'\nimport {\n EcPlayerCore,\n EnvDetector,\n setLogLevel as coreSetLogLevel,\n type EcPlayerCoreConfig,\n type EcPlayerState,\n type EcPlayerCallbacks\n} from '@give-tech/ec-player'\nimport type { EcPlayerProps, PlayerOptions } from '../types'\nimport { resolveWasmPath, DEFAULT_PLAYER_OPTIONS, getGlobalConfig } from '../types'\n\n/**\n * 播放器逻辑返回值\n */\nexport interface UsePlayerReturn {\n /** Canvas 元素引用 */\n canvasRef: Ref<HTMLCanvasElement | null>\n /** 播放器实例 */\n player: Ref<EcPlayerCore | null>\n /** 响应式状态 */\n state: EcPlayerState\n /** 是否正在加载 */\n isLoading: Ref<boolean>\n /** 检测到的格式 */\n detectedFormat: Ref<string>\n /** 是否为直播流 */\n isLive: Ref<boolean>\n /** 播放 */\n play: (options: { url: string; isLive?: boolean }) => Promise<void>\n /** 设置配置 */\n setOptions: (options: PlayerOptions) => void\n /** 设置日志级别 */\n setLogLevel: (level: number) => void\n /** 暂停 */\n pause: () => void\n /** 恢复播放 */\n resume: () => Promise<void>\n /** 跳转 */\n seek: (time: number) => Promise<void>\n /** 获取播放器实例 */\n getPlayer: () => EcPlayerCore | null\n /** 获取状态 */\n getState: () => EcPlayerState\n /** 获取当前时间 */\n getCurrentTime: () => number\n /** 获取总时长 */\n getDuration: () => number\n /** 容器尺寸变化时调用 */\n resize: () => void\n /** 销毁播放器 */\n destroy: () => void\n}\n\n/**\n * 从配置选项创建播放器配置\n */\nfunction createConfig(options: Required<PlayerOptions>): Omit<EcPlayerCoreConfig, 'isLive'> {\n // 检测 SIMD 支持\n const envInfo = EnvDetector.detect()\n const wasmPath = resolveWasmPath(envInfo.capabilities.wasmSimd)\n\n return {\n wasmPath,\n targetBufferSize: options.targetBufferSize,\n decodeBatchSize: options.decodeBatchSize,\n maxQueueSize: options.maxQueueSize\n }\n}\n\n/**\n * 播放器逻辑 Hook\n */\nexport function usePlayer(\n emit: {\n (e: 'play'): void\n (e: 'pause'): void\n }\n): UsePlayerReturn {\n const canvasRef = ref<HTMLCanvasElement | null>(null)\n const player = shallowRef<EcPlayerCore | null>(null)\n const isLoading = ref(false)\n const detectedFormat = ref('')\n const isLive = ref(false) // 跟踪当前是否为直播流\n\n // 当前播放器配置(初始化时合并全局配置和默认值)\n const globalConfig = getGlobalConfig()\n const currentOptions = reactive<Required<PlayerOptions>>({\n targetBufferSize: globalConfig.targetBufferSize ?? DEFAULT_PLAYER_OPTIONS.targetBufferSize,\n decodeBatchSize: globalConfig.decodeBatchSize ?? DEFAULT_PLAYER_OPTIONS.decodeBatchSize,\n maxQueueSize: globalConfig.maxQueueSize ?? DEFAULT_PLAYER_OPTIONS.maxQueueSize\n })\n\n // 响应式状态\n const state = reactive<EcPlayerState>({\n isPlaying: false,\n isLoaded: false,\n isLoading: false,\n fps: 0,\n resolution: '-',\n decoded: 0,\n downloaded: 0,\n droppedFrames: 0,\n isPrefetching: false,\n segmentIndex: 0,\n totalSegments: 0,\n downloadSpeed: 0,\n currentTime: 0,\n duration: 0\n })\n\n // 创建回调\n const callbacks: EcPlayerCallbacks = {\n onStateChange: (partial) => {\n Object.assign(state, partial)\n\n // 派发 play/pause 事件\n if (partial.isPlaying === true) {\n emit('play')\n } else if (partial.isPlaying === false && state.isPlaying) {\n emit('pause')\n }\n },\n onError: (error) => {\n console.error('[EcPlayer] Error:', error)\n }\n }\n\n // 播放(加载并播放)\n async function play(options: { url: string; isLive?: boolean }): Promise<void> {\n const { url, isLive: isLiveParam = false } = options\n if (!url) {\n console.error('[EcPlayer] URL is required')\n return\n }\n\n // 如果正在加载中,先销毁当前播放器\n if (isLoading.value && player.value) {\n console.log('[EcPlayer] Aborting current load to start new one...')\n player.value.destroy()\n player.value = null\n }\n\n // 等待 canvas 准备好\n let retries = 10\n while (!canvasRef.value && retries > 0) {\n await new Promise(resolve => setTimeout(resolve, 100))\n retries--\n }\n\n if (!canvasRef.value) {\n console.error('[EcPlayer] Canvas element not found')\n return\n }\n\n isLoading.value = true\n isLive.value = isLiveParam\n\n try {\n // 销毁旧播放器\n if (player.value) {\n player.value.destroy()\n player.value = null\n }\n\n // 重置状态\n state.isPlaying = false\n state.isLoaded = false\n state.fps = 0\n state.resolution = '-'\n state.decoded = 0\n state.downloaded = 0\n state.droppedFrames = 0\n state.segmentIndex = 0\n state.totalSegments = 0\n state.downloadSpeed = 0\n state.currentTime = 0\n state.duration = 0\n detectedFormat.value = ''\n\n // 创建配置\n const config: EcPlayerCoreConfig & { canvas: HTMLCanvasElement } = {\n ...createConfig(currentOptions),\n canvas: canvasRef.value,\n isLive: isLiveParam\n }\n\n // 创建播放器\n player.value = new EcPlayerCore(config, callbacks)\n\n // 加载视频\n await player.value.load(url, isLiveParam)\n\n // 获取检测到的格式\n detectedFormat.value = player.value.getDetectedFormat()\n\n // 标记加载完成\n state.isLoaded = true\n\n // 开始播放\n await player.value.play()\n\n console.log('[EcPlayer] Playing stream, format:', detectedFormat.value)\n } catch (error: any) {\n console.error('[EcPlayer] Failed to play:', error?.message || error)\n } finally {\n isLoading.value = false\n }\n }\n\n // 设置配置\n function setOptions(options: PlayerOptions): void {\n if (options.targetBufferSize !== undefined) {\n currentOptions.targetBufferSize = options.targetBufferSize\n }\n if (options.decodeBatchSize !== undefined) {\n currentOptions.decodeBatchSize = options.decodeBatchSize\n }\n if (options.maxQueueSize !== undefined) {\n currentOptions.maxQueueSize = options.maxQueueSize\n }\n console.log('[EcPlayer] Options updated:', currentOptions)\n }\n\n // 设置日志级别\n function setLogLevel(level: number): void {\n coreSetLogLevel(level)\n }\n\n // 暂停\n function pause(): void {\n player.value?.pause()\n }\n\n // 恢复播放\n async function resume(): Promise<void> {\n if (!player.value) return\n await player.value.play()\n }\n\n // 跳转\n async function seek(time: number): Promise<void> {\n if (!player.value) return\n await player.value.seek(time)\n }\n\n // 获取播放器实例\n function getPlayer(): EcPlayerCore | null {\n return player.value\n }\n\n // 获取状态\n function getState(): EcPlayerState {\n return player.value?.getState() ?? { ...state }\n }\n\n // 获取当前时间\n function getCurrentTime(): number {\n return player.value?.getCurrentTime() ?? 0\n }\n\n // 获取总时长\n function getDuration(): number {\n return player.value?.getDuration() ?? 0\n }\n\n // 销毁播放器\n function destroy(): void {\n if (player.value) {\n player.value.destroy()\n player.value = null\n }\n }\n\n // 容器尺寸变化时调用\n function resize(): void {\n player.value?.resize()\n }\n\n // 组件卸载时销毁\n onUnmounted(() => {\n destroy()\n })\n\n return {\n canvasRef,\n player,\n state,\n isLoading,\n detectedFormat,\n isLive,\n play,\n setOptions,\n setLogLevel,\n pause,\n resume,\n seek,\n getPlayer,\n getState,\n getCurrentTime,\n getDuration,\n resize,\n destroy\n }\n}\n","/**\n * 播放器控制条逻辑\n */\n\nimport { ref, computed, type Ref } from 'vue'\n\n/**\n * 控制条逻辑参数\n */\nexport interface UseControlsParams {\n /** 是否正在播放 */\n isPlaying: Ref<boolean>\n /** 是否已加载 */\n isLoaded: Ref<boolean>\n /** 当前时间(毫秒) */\n currentTime: Ref<number>\n /** 总时长(毫秒) */\n duration: Ref<number>\n /** 分片索引 */\n segmentIndex: Ref<number>\n /** 总分片数 */\n totalSegments: Ref<number>\n /** 是否为直播流 */\n isLive: Ref<boolean>\n /** 跳转方法 */\n seek: (time: number) => Promise<void>\n}\n\n/**\n * 控制条逻辑返回值\n */\nexport interface UseControlsReturn {\n /** 是否显示控制条 */\n showControls: Ref<boolean>\n /** 进度条 hover 时间 */\n hoverTime: Ref<number | null>\n /** 进度条 hover 位置 */\n hoverPosition: Ref<number>\n /** 播放进度百分比 */\n playProgress: Ref<number>\n /** 缓冲进度百分比 */\n bufferProgress: Ref<number>\n /** 显示控制条 */\n showControlsBar: () => void\n /** 隐藏控制条 */\n hideControlsBar: () => void\n /** 处理进度条点击 */\n handleProgressClick: (event: MouseEvent) => Promise<void>\n /** 处理进度条悬停 */\n handleProgressHover: (event: MouseEvent) => void\n /** 格式化时间 */\n formatTime: (ms: number) => string\n}\n\n/**\n * 控制条逻辑 Hook\n */\nexport function useControls(params: UseControlsParams): UseControlsReturn {\n let hideControlsTimer: number | null = null\n const {\n isPlaying,\n isLoaded,\n currentTime,\n duration,\n segmentIndex,\n totalSegments,\n isLive,\n seek\n } = params\n\n const showControls = ref(true)\n const hoverTime = ref<number | null>(null)\n const hoverPosition = ref(0)\n\n // 计算播放进度\n const playProgress = computed(() => {\n if (duration.value === 0) return 0\n return (currentTime.value / duration.value) * 100\n })\n\n // 计算缓冲进度\n const bufferProgress = computed(() => {\n if (totalSegments.value === 0) return 0\n return (segmentIndex.value / totalSegments.value) * 100\n })\n\n // 显示控制条\n function showControlsBar(): void {\n showControls.value = true\n if (hideControlsTimer) {\n clearTimeout(hideControlsTimer)\n }\n hideControlsTimer = window.setTimeout(() => {\n if (isPlaying.value) {\n showControls.value = false\n }\n }, 3000)\n }\n\n // 隐藏控制条\n function hideControlsBar(): void {\n if (isPlaying.value) {\n showControls.value = false\n }\n }\n\n // 处理进度条点击\n async function handleProgressClick(event: MouseEvent): Promise<void> {\n if (duration.value === 0) return\n\n const target = event.currentTarget as HTMLElement\n const rect = target.getBoundingClientRect()\n const clickX = event.clientX - rect.left\n const percentage = clickX / rect.width\n const targetTime = percentage * duration.value\n\n await seek(targetTime)\n }\n\n // 处理进度条悬停\n function handleProgressHover(event: MouseEvent): void {\n if (duration.value === 0) return\n\n const target = event.currentTarget as HTMLElement\n const rect = target.getBoundingClientRect()\n const hoverX = event.clientX - rect.left\n const percentage = Math.max(0, Math.min(1, hoverX / rect.width))\n\n hoverTime.value = percentage * duration.value\n hoverPosition.value = percentage * 100\n }\n\n // 格式化时间\n function formatTime(ms: number): string {\n const totalSeconds = Math.floor(ms / 1000)\n const hours = Math.floor(totalSeconds / 3600)\n const minutes = Math.floor((totalSeconds % 3600) / 60)\n const seconds = totalSeconds % 60\n\n if (hours > 0) {\n return `${hours}:${minutes.toString().padStart(2, '0')}:${seconds.toString().padStart(2, '0')}`\n }\n return `${minutes}:${seconds.toString().padStart(2, '0')}`\n }\n\n return {\n showControls,\n hoverTime,\n hoverPosition,\n playProgress,\n bufferProgress,\n showControlsBar,\n hideControlsBar,\n handleProgressClick,\n handleProgressHover,\n formatTime\n }\n}\n","/**\n * 环境信息逻辑\n */\n\nimport { ref, computed, onMounted, type Ref } from 'vue'\nimport { EnvDetector, type EnvInfo } from '@give-tech/ec-player'\n\n/**\n * 环境信息逻辑返回值\n */\nexport interface UseEnvInfoReturn {\n /** 环境信息 */\n envInfo: Ref<EnvInfo | null>\n /** 是否显示环境面板 */\n showEnvPanel: Ref<boolean>\n /** 环境类型文本 */\n envTypeText: Ref<string>\n /** 切换环境面板显示 */\n toggleEnvPanel: () => void\n /** 检测环境 */\n detectEnv: () => void\n}\n\n/**\n * 环境信息逻辑 Hook\n */\nexport function useEnvInfo(\n initialShowPanel: boolean = false\n): UseEnvInfoReturn {\n const envInfo = ref<EnvInfo | null>(null)\n const showEnvPanel = ref(initialShowPanel)\n\n // 环境类型文本\n const envTypeText = computed(() => {\n if (!envInfo.value) return '未知'\n const typeMap: Record<string, string> = {\n 'pc-browser': 'PC 浏览器',\n 'mobile-browser': '移动端浏览器',\n 'wechat-miniprogram': '微信小程序',\n 'alipay-miniprogram': '支付宝小程序',\n 'other-miniprogram': '其他小程序',\n 'unknown': '未知',\n }\n return typeMap[envInfo.value.platform] || envInfo.value.platform\n })\n\n // 切换环境面板显示\n function toggleEnvPanel(): void {\n showEnvPanel.value = !showEnvPanel.value\n }\n\n // 检测环境\n function detectEnv(): void {\n envInfo.value = EnvDetector.detect()\n console.log('[EcPlayer] 环境检测结果:', envInfo.value)\n }\n\n // 组件挂载时检测环境\n onMounted(() => {\n detectEnv()\n })\n\n return {\n envInfo,\n showEnvPanel,\n envTypeText,\n toggleEnvPanel,\n detectEnv\n }\n}\n","<template>\n <div class=\"gt-player-container\" ref=\"containerRef\">\n <div\n class=\"gt-video-wrapper\"\n ref=\"videoWrapperRef\"\n @mouseenter=\"controls.showControlsBar\"\n @mousemove=\"controls.showControlsBar\"\n @mouseleave=\"controls.hideControlsBar\"\n >\n <!-- Canvas 视频渲染 -->\n <canvas ref=\"canvasRef\" class=\"gt-player-canvas\"></canvas>\n\n <!-- 封面/占位内容(未加载时显示) -->\n <div v-if=\"!player.state.isLoaded\" class=\"gt-placeholder\">\n <slot name=\"placeholder\"></slot>\n </div>\n\n <!-- 环境信息面板 -->\n <div v-if=\"showEnvPanel && envInfo\" class=\"gt-env-panel\">\n <div class=\"gt-env-row\">\n <span>platform</span>\n <span :class=\"envInfo.isMiniProgram ? 'warn' : ''\">{{ envTypeText }}</span>\n </div>\n <div class=\"gt-env-divider\"></div>\n <div class=\"gt-env-row\">\n <span>SIMD</span>\n <span :class=\"envInfo.capabilities.wasmSimd ? 'ok' : 'err'\">\n {{ envInfo.capabilities.wasmSimd ? 'Yes' : 'No' }}\n </span>\n </div>\n <div class=\"gt-env-row\">\n <span>WebGL</span>\n <span :class=\"envInfo.capabilities.webGL ? 'ok' : 'err'\">\n {{ envInfo.capabilities.webGL ? 'Yes' : 'No' }}\n </span>\n </div>\n <div class=\"gt-env-row\">\n <span>WebGL2</span>\n <span :class=\"envInfo.capabilities.webGL2 ? 'ok' : 'err'\">\n {{ envInfo.capabilities.webGL2 ? 'Yes' : 'No' }}\n </span>\n </div>\n <div class=\"gt-env-row\">\n <span>SAB</span>\n <span :class=\"envInfo.capabilities.sharedArrayBuffer ? 'ok' : 'err'\">\n {{ envInfo.capabilities.sharedArrayBuffer ? 'Yes' : 'No' }}\n </span>\n </div>\n <div class=\"gt-env-row\">\n <span>Threads</span>\n <span :class=\"envInfo.capabilities.wasmThreads ? 'ok' : 'err'\">\n {{ envInfo.capabilities.wasmThreads ? 'Yes' : 'No' }}\n </span>\n </div>\n <div class=\"gt-env-row\">\n <span>WebAudio</span>\n <span :class=\"envInfo.capabilities.webAudio ? 'ok' : 'err'\">\n {{ envInfo.capabilities.webAudio ? 'Yes' : 'No' }}\n </span>\n </div>\n <div class=\"gt-env-row\">\n <span>Stream</span>\n <span :class=\"envInfo.capabilities.readableStream ? 'ok' : 'err'\">\n {{ envInfo.capabilities.readableStream ? 'Yes' : 'No' }}\n </span>\n </div>\n <template v-if=\"player.state.isLoaded\">\n <div class=\"gt-env-divider\"></div>\n <div class=\"gt-env-row\" v-if=\"player.detectedFormat.value\"><span>Format</span><span>{{ player.detectedFormat.value }}</span></div>\n <div class=\"gt-env-row\"><span>FPS</span><span>{{ player.state.fps }}</span></div>\n <div class=\"gt-env-row\"><span>Resolution</span><span>{{ player.state.resolution }}</span></div>\n <div class=\"gt-env-row\"><span>downloaded</span><span>{{ player.state.downloaded }}</span></div>\n <div class=\"gt-env-row\"><span>decoded</span><span>{{ player.state.decoded }}</span></div>\n <div class=\"gt-env-row\"><span>Dropped</span><span>{{ player.state.droppedFrames }}</span></div>\n <div class=\"gt-env-row\"><span>Speed</span><span>{{ player.state.downloadSpeed || 0 }} KB/s</span></div>\n </template>\n </div>\n\n <!-- 加载中动画 -->\n <div class=\"gt-loading-spinner\" v-if=\"player.isLoading.value\">\n <slot name=\"loading\">\n <div class=\"gt-spinner\"></div>\n </slot>\n </div>\n\n <!-- 视频控制条 -->\n <div\n v-if=\"controlOption.show\"\n class=\"gt-video-controls\"\n :class=\"{ visible: controls.showControls.value || !player.state.isPlaying }\"\n >\n <button class=\"gt-control-btn\" @click=\"togglePlayback\">\n <svg v-if=\"player.state.isPlaying\" viewBox=\"0 0 24 24\" fill=\"currentColor\">\n <rect x=\"6\" y=\"4\" width=\"4\" height=\"16\" rx=\"1\"/>\n <rect x=\"14\" y=\"4\" width=\"4\" height=\"16\" rx=\"1\"/>\n </svg>\n <svg v-else viewBox=\"0 0 24 24\" fill=\"currentColor\">\n <path d=\"M8 5v14l11-7z\"/>\n </svg>\n </button>\n\n <!-- 直播标识 -->\n <span class=\"gt-live-indicator\" v-if=\"isLive\">\n <span class=\"gt-live-dot\"></span>\n <span class=\"gt-live-text\">实时</span>\n </span>\n\n <!-- 点播时间显示 -->\n <span class=\"gt-time-display\" v-else>\n <span class=\"gt-time-current\">{{ controls.formatTime(player.state.currentTime) }}</span>\n <span class=\"gt-time-separator\">/</span>\n <span class=\"gt-time-duration\">{{ controls.formatTime(player.state.duration) }}</span>\n </span>\n\n <!-- 进度条 (仅点播) -->\n <div\n v-if=\"!isLive\"\n class=\"gt-progress-container\"\n @click=\"controls.handleProgressClick\"\n @mousemove=\"controls.handleProgressHover\"\n @mouseleave=\"controls.hoverTime.value = null\"\n >\n <div class=\"gt-progress-bar\">\n <div class=\"gt-progress-buffered\" :style=\"{ width: controls.bufferProgress.value + '%' }\"></div>\n <div class=\"gt-progress-played\" :style=\"{ width: controls.playProgress.value + '%' }\">\n <div class=\"gt-progress-handle\"></div>\n </div>\n </div>\n <div\n class=\"gt-progress-tooltip\"\n v-if=\"controls.hoverTime.value !== null\"\n :style=\"{ left: controls.hoverPosition.value + '%' }\"\n >\n {{ controls.formatTime(controls.hoverTime.value) }}\n </div>\n </div>\n\n <!-- 直播流占位符 -->\n <div class=\"gt-flex-spacer\" v-else></div>\n\n <!-- 环境信息按钮 -->\n <button v-if=\"controlOption.info\" class=\"gt-control-btn gt-env-info-btn\" @click=\"toggleEnvPanel\" :title=\"showEnvPanel ? '隐藏信息' : '显示信息'\">\n <svg viewBox=\"0 0 24 24\" fill=\"currentColor\">\n <path d=\"M12 2C6.48 2 2 6.48 2 12s4.48 10 10 10 10-4.48 10-10S17.52 2 12 2zm1 15h-2v-6h2v6zm0-8h-2V7h2v2z\"/>\n </svg>\n </button>\n\n <!-- 全屏按钮 -->\n <button v-if=\"controlOption.fullscreen\" class=\"gt-control-btn gt-fullscreen-btn\" @click=\"toggleFullscreen\" :title=\"isFullscreen ? '退出全屏' : '全屏'\">\n <!-- 退出全屏图标 -->\n <svg v-if=\"isFullscreen\" viewBox=\"0 0 24 24\" fill=\"currentColor\">\n <path d=\"M5 16h3v3h2v-5H5v2zm3-8H5v2h5V5H8v3zm6 11h2v-3h3v-2h-5v5zm2-11V5h-2v5h5V8h-3z\"/>\n </svg>\n <!-- 全屏图标 -->\n <svg v-else viewBox=\"0 0 24 24\" fill=\"currentColor\">\n <path d=\"M7 14H5v5h5v-2H7v-3zm-2-4h2V7h3V5H5v5zm12 7h-3v2h5v-5h-2v3zM14 5v2h3v3h2V5h-5z\"/>\n </svg>\n </button>\n </div>\n\n <!-- 大播放按钮(居中) -->\n <div\n class=\"gt-center-play-btn\"\n v-if=\"player.state.isLoaded && !player.state.isPlaying\"\n @click=\"togglePlayback\"\n >\n <svg viewBox=\"0 0 24 24\" fill=\"currentColor\">\n <path d=\"M8 5v14l11-7z\"/>\n </svg>\n </div>\n </div>\n </div>\n</template>\n\n<script setup lang=\"ts\">\nimport { computed, ref, watch, onMounted, onUnmounted } from 'vue'\nimport { usePlayer } from '../composables/usePlayer'\nimport { useControls } from '../composables/useControls'\nimport { useEnvInfo } from '../composables/useEnvInfo'\nimport type { EcPlayerProps, EcPlayerExpose, EcPlayerSource, EcPlayerControlOption } from '../types'\nimport { DEFAULT_EC_PLAYER_PROPS } from '../types'\n\n// Props\nconst props = withDefaults(defineProps<EcPlayerProps>(), DEFAULT_EC_PLAYER_PROPS)\n\n// Emits\nconst emit = defineEmits<{\n (e: 'play'): void\n (e: 'pause'): void\n}>()\n\n// Canvas ref(本地)\nconst canvasRef = ref<HTMLCanvasElement | null>(null)\n\n// 容器引用(用于全屏)\nconst containerRef = ref<HTMLElement | null>(null)\n\n// 全屏状态\nconst isFullscreen = ref(false)\n\n// 解析 controlOption\nconst controlOption = computed<Required<EcPlayerControlOption>>(() => ({\n show: props.controlOption?.show ?? DEFAULT_EC_PLAYER_PROPS.controlOption.show,\n fullscreen: props.controlOption?.fullscreen ?? DEFAULT_EC_PLAYER_PROPS.controlOption.fullscreen,\n info: props.controlOption?.info ?? DEFAULT_EC_PLAYER_PROPS.controlOption.info\n}))\n\n// 环境信息逻辑\nconst { envInfo, showEnvPanel, envTypeText, toggleEnvPanel } = useEnvInfo(false)\n\n// 播放器逻辑\nconst player = usePlayer(emit)\n\n// 同步 canvas ref 到 player\nwatch(canvasRef, (el) => {\n player.canvasRef.value = el\n}, { immediate: true })\n\n// isLive 计算属性(用于模板)\nconst isLive = computed(() => player.isLive.value)\n\n// 控制条逻辑\nconst isPlayingRef = computed(() => player.state.isPlaying)\nconst isLoadedRef = computed(() => player.state.isLoaded)\nconst currentTimeRef = computed(() => player.state.currentTime)\nconst durationRef = computed(() => player.state.duration)\nconst segmentIndexRef = computed(() => player.state.segmentIndex)\nconst totalSegmentsRef = computed(() => player.state.totalSegments)\n\nconst controls = useControls({\n isPlaying: isPlayingRef,\n isLoaded: isLoadedRef,\n currentTime: currentTimeRef,\n duration: durationRef,\n segmentIndex: segmentIndexRef,\n totalSegments: totalSegmentsRef,\n isLive,\n seek: player.seek\n})\n\n// 视频包装器引用\nconst videoWrapperRef = ref<HTMLElement | null>(null)\n\n// 解析 src\nfunction parseSrc(src: EcPlayerSource | undefined): { url: string; isLive: boolean } | null {\n if (!src || !src.url) return null\n return { url: src.url, isLive: src.isLive ?? false }\n}\n\n// 切换播放/暂停\nfunction togglePlayback(): void {\n if (player.state.isPlaying) {\n player.pause()\n } else {\n player.resume()\n }\n}\n\n// 切换全屏\nfunction toggleFullscreen(): void {\n if (!containerRef.value) return\n\n if (!isFullscreen.value) {\n if (containerRef.value.requestFullscreen) {\n containerRef.value.requestFullscreen()\n }\n } else {\n if (document.exitFullscreen) {\n document.exitFullscreen()\n }\n }\n}\n\n// 监听全屏变化\nfunction handleFullscreenChange(): void {\n isFullscreen.value = !!document.fullscreenElement\n}\n\n// 暴露的 play 方法(简化版)\nfunction play(): void {\n const parsed = parseSrc(props.src)\n if (parsed) {\n player.play(parsed)\n }\n}\n\n// 监听 src 变化,自动播放\nwatch(() => props.src, (newSrc) => {\n const parsed = parseSrc(newSrc)\n if (parsed && parsed.url) {\n player.play(parsed)\n }\n}, { immediate: true, deep: true })\n\n// 挂载时监听全屏事件和尺寸变化\nlet resizeObserver: ResizeObserver | null = null\n\nonMounted(() => {\n document.addEventListener('fullscreenchange', handleFullscreenChange)\n\n // 监听容器尺寸变化\n if (containerRef.value) {\n resizeObserver = new ResizeObserver(() => {\n player.resize()\n })\n resizeObserver.observe(containerRef.value)\n }\n})\n\n// 卸载时移除监听\nonUnmounted(() => {\n document.removeEventListener('fullscreenchange', handleFullscreenChange)\n resizeObserver?.disconnect()\n resizeObserver = null\n})\n\n// Expose 方法\ndefineExpose<EcPlayerExpose>({\n play,\n pause: player.pause,\n seek: player.seek\n})\n</script>\n\n<style scoped>\n.gt-player-container {\n width: 100%;\n height: 100%;\n}\n\n.gt-video-wrapper {\n position: relative;\n width: 100%;\n height: 100%;\n background: #000;\n overflow: hidden;\n}\n\n.gt-player-canvas {\n position: absolute;\n top: 50%;\n left: 50%;\n transform: translate(-50%, -50%);\n}\n\n.gt-placeholder {\n position: absolute;\n top: 0;\n left: 0;\n width: 100%;\n height: 100%;\n display: flex;\n align-items: center;\n justify-content: center;\n background: #000;\n}\n\n/* 加载中动画 */\n.gt-loading-spinner {\n position: absolute;\n top: 0;\n left: 0;\n right: 0;\n bottom: 0;\n display: flex;\n align-items: center;\n justify-content: center;\n background: rgba(0, 0, 0, 0.5);\n z-index: 10;\n}\n\n.gt-spinner {\n width: 8vmin;\n height: 8vmin;\n border: 0.5vmin solid rgba(255, 255, 255, 0.3);\n border-top-color: #fff;\n border-radius: 50%;\n animation: gt-spin 1s linear infinite;\n}\n\n@keyframes gt-spin {\n to {\n transform: rotate(360deg);\n }\n}\n\n/* 视频控制条 */\n.gt-video-controls {\n position: absolute;\n bottom: 0;\n left: 0;\n right: 0;\n padding: 10px 16px;\n background: linear-gradient(transparent, rgba(0, 0, 0, 0.7));\n opacity: 0;\n transition: opacity 0.3s ease;\n display: flex;\n align-items: center;\n gap: 12px;\n}\n\n.gt-flex-spacer {\n flex: 1;\n}\n\n.gt-video-controls.visible {\n opacity: 1;\n}\n\n.gt-control-btn {\n width: 28px;\n height: 28px;\n border: none;\n border-radius: 50%;\n background: transparent;\n color: white;\n cursor: pointer;\n display: flex;\n align-items: center;\n justify-content: center;\n transition: all 0.2s ease;\n flex-shrink: 0;\n}\n\n.gt-control-btn:hover {\n background: rgba(255, 255, 255, 0.2);\n}\n\n.gt-control-btn svg {\n width: 14px;\n height: 14px;\n}\n\n.gt-progress-container {\n flex: 1;\n position: relative;\n cursor: pointer;\n height: 20px;\n display: flex;\n align-items: center;\n}\n\n.gt-progress-bar {\n width: 100%;\n height: 4px;\n background: rgba(255, 255, 255, 0.2);\n border-radius: 2px;\n position: relative;\n overflow: hidden;\n transition: height 0.2s ease;\n}\n\n.gt-progress-container:hover .gt-progress-bar {\n height: 6px;\n}\n\n.gt-progress-buffered {\n position: absolute;\n top: 0;\n left: 0;\n height: 100%;\n background: rgba(255, 255, 255, 0.4);\n border-radius: 2px;\n transition: width 0.1s;\n}\n\n.gt-progress-played {\n position: absolute;\n top: 0;\n left: 0;\n height: 100%;\n background: #ff2d55;\n border-radius: 2px;\n transition: width 0.1s;\n}\n\n.gt-progress-handle {\n position: absolute;\n right: -6px;\n top: 50%;\n transform: translateY(-50%);\n width: 14px;\n height: 14px;\n background: #ff2d55;\n border-radius: 50%;\n box-shadow: 0 2px 8px rgba(0, 0, 0, 0.3);\n opacity: 0;\n transition: opacity 0.2s, transform 0.2s;\n}\n\n.gt-progress-container:hover .gt-progress-handle {\n opacity: 1;\n transform: translateY(-50%) scale(1.2);\n}\n\n.gt-progress-tooltip {\n position: absolute;\n bottom: calc(100% + 8px);\n transform: translateX(-50%);\n background: rgba(0, 0, 0, 0.85);\n color: white;\n padding: 4px 8px;\n border-radius: 4px;\n font-size: 11px;\n white-space: nowrap;\n pointer-events: none;\n}\n\n.gt-time-display {\n color: white;\n font-size: 12px;\n font-family: -apple-system, BlinkMacSystemFont, 'Segoe UI', Roboto, sans-serif;\n white-space: nowrap;\n flex-shrink: 0;\n}\n\n.gt-time-separator {\n margin: 0 4px;\n opacity: 0.6;\n}\n\n/* 直播指示器 */\n.gt-live-indicator {\n display: flex;\n align-items: center;\n gap: 6px;\n color: white;\n font-size: 12px;\n font-weight: 500;\n}\n\n.gt-live-dot {\n width: 8px;\n height: 8px;\n background: #ff2d55;\n border-radius: 50%;\n animation: gt-live-pulse 1.5s ease-in-out infinite;\n}\n\n.gt-live-text {\n color: #ff2d55;\n}\n\n@keyframes gt-live-pulse {\n 0%, 100% {\n opacity: 1;\n }\n 50% {\n opacity: 0.4;\n }\n}\n\n/* 居中播放按钮 */\n.gt-center-play-btn {\n position: absolute;\n top: 50%;\n left: 50%;\n transform: translate(-50%, -50%);\n width: 56px;\n height: 56px;\n background: rgba(0, 0, 0, 0.5);\n border-radius: 50%;\n display: flex;\n align-items: center;\n justify-content: center;\n cursor: pointer;\n transition: all 0.2s ease;\n}\n\n.gt-center-play-btn:hover {\n background: rgba(0, 0, 0, 0.7);\n transform: translate(-50%, -50%) scale(1.05);\n}\n\n.gt-center-play-btn svg {\n width: 24px;\n height: 24px;\n color: white;\n margin-left: 3px;\n}\n\n/* 环境信息面板 */\n.gt-env-panel {\n position: absolute;\n top: 12px;\n left: 12px;\n background: rgba(0, 0, 0, 0.8);\n border-radius: 6px;\n padding: 8px 10px;\n font-size: 11px;\n font-family: 'SF Mono', 'Monaco', 'Consolas', monospace;\n min-width: 160px;\n max-width: 200px;\n max-height: calc(100% - 24px);\n overflow-y: auto;\n backdrop-filter: blur(10px);\n animation: gt-env-fade-in 0.15s ease;\n z-index: 15;\n}\n\n.gt-env-panel::-webkit-scrollbar {\n width: 4px;\n}\n\n.gt-env-panel::-webkit-scrollbar-track {\n background: transparent;\n}\n\n.gt-env-panel::-webkit-scrollbar-thumb {\n background: rgba(255, 255, 255, 0.3);\n border-radius: 2px;\n}\n\n@keyframes gt-env-fade-in {\n from { opacity: 0; transform: translateY(-4px); }\n to { opacity: 1; transform: translateY(0); }\n}\n\n.gt-env-panel .gt-env-row {\n display: flex;\n justify-content: space-between;\n align-items: center;\n padding: 2px 0;\n color: rgba(255, 255, 255, 0.7);\n}\n\n.gt-env-panel .gt-env-row span:first-child {\n color: rgba(255, 255, 255, 0.5);\n margin-right: 16px;\n}\n\n.gt-env-panel .gt-env-row span:last-child {\n font-variant-numeric: tabular-nums;\n}\n\n.gt-env-panel .gt-env-row .ok { color: #4caf50; }\n.gt-env-panel .gt-env-row .warn { color: #ff9800; }\n.gt-env-panel .gt-env-row .err { color: #f44336; }\n\n.gt-env-divider {\n height: 1px;\n background: rgba(255, 255, 255, 0.1);\n margin: 4px 0;\n}\n</style>\n"],"names":["globalConfig","setLogLevel","coreSetLogLevel","_createElementBlock","_createElementVNode","_unref","_openBlock","_renderSlot","_normalizeClass","_Fragment","_toDisplayString","_normalizeStyle"],"mappings":"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"}
|