@maas/vue-equipment 0.20.1 → 0.21.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/nuxt/module.json +1 -1
- package/dist/nuxt/module.mjs +1 -1
- package/dist/plugins/MagicDrawer/src/composables/useDrawerApi.d.ts +2 -2
- package/dist/plugins/MagicPlayer/index.d.ts +3 -3
- package/dist/plugins/MagicPlayer/index.mjs +6 -3
- package/dist/plugins/MagicPlayer/src/components/MagicPlayer.vue +24 -18
- package/dist/plugins/MagicPlayer/src/components/MagicPlayer.vue.d.ts +8 -5
- package/dist/plugins/MagicPlayer/src/components/MagicPlayerControls.vue +20 -9
- package/dist/plugins/MagicPlayer/src/components/MagicPlayerMuxPopover.vue +2 -4
- package/dist/plugins/MagicPlayer/src/components/MagicPlayerOverlay.vue +29 -25
- package/dist/plugins/MagicPlayer/src/components/MagicPlayerOverlay.vue.d.ts +1 -0
- package/dist/plugins/MagicPlayer/src/components/MagicPlayerPoster.vue +27 -0
- package/dist/plugins/MagicPlayer/src/components/MagicPlayerPoster.vue.d.ts +21 -0
- package/dist/plugins/MagicPlayer/src/components/MagicPlayerTimeline.vue +10 -7
- package/dist/plugins/MagicPlayer/src/composables/private/usePlayerControlsApi.d.ts +34 -0
- package/dist/plugins/MagicPlayer/src/composables/private/usePlayerControlsApi.mjs +297 -0
- package/dist/plugins/MagicPlayer/src/composables/private/{useMediaApi.d.ts → usePlayerMediaApi.d.ts} +11 -7
- package/dist/plugins/MagicPlayer/src/composables/private/usePlayerMediaApi.mjs +263 -0
- package/dist/plugins/MagicPlayer/src/composables/private/usePlayerRuntime.d.ts +12 -0
- package/dist/plugins/MagicPlayer/src/composables/private/usePlayerRuntime.mjs +70 -0
- package/dist/plugins/MagicPlayer/src/composables/private/usePlayerStateEmitter.d.ts +15 -0
- package/dist/plugins/MagicPlayer/src/composables/private/usePlayerStateEmitter.mjs +9 -0
- package/dist/plugins/MagicPlayer/src/composables/private/usePlayerVideoApi.d.ts +22 -0
- package/dist/plugins/MagicPlayer/src/composables/private/usePlayerVideoApi.mjs +142 -0
- package/dist/plugins/MagicPlayer/src/composables/usePlayerApi.d.ts +63 -5
- package/dist/plugins/MagicPlayer/src/composables/usePlayerApi.mjs +12 -65
- package/dist/plugins/MagicPlayer/src/types/index.d.ts +12 -25
- package/package.json +1 -1
- package/dist/plugins/MagicPlayer/src/composables/private/useControlsApi.d.ts +0 -17
- package/dist/plugins/MagicPlayer/src/composables/private/useControlsApi.mjs +0 -131
- package/dist/plugins/MagicPlayer/src/composables/private/useMediaApi.mjs +0 -122
- package/dist/plugins/MagicPlayer/src/composables/private/usePlayerInternalApi.d.ts +0 -18
- package/dist/plugins/MagicPlayer/src/composables/private/usePlayerInternalApi.mjs +0 -63
- package/dist/plugins/MagicPlayer/src/composables/private/usePlayerStore.d.ts +0 -20
- package/dist/plugins/MagicPlayer/src/composables/private/usePlayerStore.mjs +0 -42
- package/dist/plugins/MagicPlayer/src/composables/private/useRuntimeSourceProvider.d.ts +0 -6
- package/dist/plugins/MagicPlayer/src/composables/private/useRuntimeSourceProvider.mjs +0 -48
- package/dist/plugins/MagicPlayer/src/utils/index.d.ts +0 -1
- package/dist/plugins/MagicPlayer/src/utils/index.mjs +0 -8
|
@@ -0,0 +1,297 @@
|
|
|
1
|
+
import { ref, computed, watch, toValue } from "vue";
|
|
2
|
+
import {
|
|
3
|
+
useResizeObserver,
|
|
4
|
+
useEventListener,
|
|
5
|
+
defaultWindow
|
|
6
|
+
} from "@vueuse/core";
|
|
7
|
+
import { clampValue, mapValue } from "@maas/vue-equipment/utils";
|
|
8
|
+
import { usePlayerMediaApi } from "./usePlayerMediaApi.mjs";
|
|
9
|
+
import { usePlayerVideoApi } from "./usePlayerVideoApi.mjs";
|
|
10
|
+
import { usePlayerStateEmitter } from "./usePlayerStateEmitter.mjs";
|
|
11
|
+
export function usePlayerControlsApi(args) {
|
|
12
|
+
const resumePlay = ref(false);
|
|
13
|
+
const barRect = ref(void 0);
|
|
14
|
+
const trackRect = ref(void 0);
|
|
15
|
+
const popoverRect = ref(void 0);
|
|
16
|
+
const { trackRef, barRef, popoverRef } = args;
|
|
17
|
+
const { buffered, duration, playing, currentTime } = usePlayerMediaApi({
|
|
18
|
+
id: toValue(args.id)
|
|
19
|
+
});
|
|
20
|
+
const { play, pause, seek } = usePlayerVideoApi({
|
|
21
|
+
id: toValue(args.id)
|
|
22
|
+
});
|
|
23
|
+
const dragging = ref(false);
|
|
24
|
+
const mouseEntered = ref(false);
|
|
25
|
+
const seekedTime = ref(0);
|
|
26
|
+
const seekedPercentage = ref(0);
|
|
27
|
+
const scrubbedPercentage = ref(0);
|
|
28
|
+
const thumbPercentage = ref(0);
|
|
29
|
+
const popoverOffsetX = ref(0);
|
|
30
|
+
const bufferedPercentage = computed(() => {
|
|
31
|
+
if (!buffered)
|
|
32
|
+
return 0;
|
|
33
|
+
const endBuffer = buffered.value?.length > 0 ? buffered.value[0][1] : 0;
|
|
34
|
+
const percentage = endBuffer / duration.value * 100;
|
|
35
|
+
return clampValue(percentage, 0, thumbPercentage.value);
|
|
36
|
+
});
|
|
37
|
+
function getPopoverOffsetX() {
|
|
38
|
+
if (!trackRect.value || !popoverRect.value || !barRect.value) {
|
|
39
|
+
return 0;
|
|
40
|
+
} else {
|
|
41
|
+
const trackFactor = barRect.value.width / trackRect.value.width;
|
|
42
|
+
const offsetXPercentage = Math.abs(trackRect.value.x - barRect.value.x) / barRect.value.width * 100;
|
|
43
|
+
const popoverWidthPercentage = popoverRect.value.width / barRect.value.width * 100;
|
|
44
|
+
const maxPercentage = 100 - popoverWidthPercentage;
|
|
45
|
+
const percentage = seekedPercentage.value / trackFactor + offsetXPercentage - popoverWidthPercentage / 2;
|
|
46
|
+
popoverOffsetX.value = clampValue(percentage, 0, maxPercentage);
|
|
47
|
+
}
|
|
48
|
+
}
|
|
49
|
+
function getTimelineTrackSize() {
|
|
50
|
+
if (!toValue(trackRef)) {
|
|
51
|
+
return;
|
|
52
|
+
}
|
|
53
|
+
trackRect.value = toValue(trackRef).getBoundingClientRect();
|
|
54
|
+
thumbPercentage.value = 100 - trackRect.value.height / trackRect.value.width * 100;
|
|
55
|
+
}
|
|
56
|
+
function getPopoverSizes() {
|
|
57
|
+
if (!toValue(barRef) || !toValue(popoverRef)) {
|
|
58
|
+
return;
|
|
59
|
+
}
|
|
60
|
+
barRect.value = toValue(barRef).getBoundingClientRect();
|
|
61
|
+
popoverRect.value = toValue(popoverRef).getBoundingClientRect();
|
|
62
|
+
}
|
|
63
|
+
function seekToTrackPosition(absX) {
|
|
64
|
+
if (!trackRect.value) {
|
|
65
|
+
throw new Error("trackRect is undefined");
|
|
66
|
+
}
|
|
67
|
+
const relX = absX - trackRect.value.x - trackRect.value.height / 2;
|
|
68
|
+
const percentage = Math.round(relX / trackRect.value.width * 100);
|
|
69
|
+
seekedPercentage.value = clampValue(percentage, 0, thumbPercentage.value);
|
|
70
|
+
seekedTime.value = duration.value * mapValue(seekedPercentage.value, 0, thumbPercentage.value, 0, 100) / 100;
|
|
71
|
+
if (dragging.value) {
|
|
72
|
+
scrubbedPercentage.value = seekedPercentage.value;
|
|
73
|
+
seek(seekedTime.value);
|
|
74
|
+
}
|
|
75
|
+
getPopoverOffsetX();
|
|
76
|
+
}
|
|
77
|
+
function onMouseenter() {
|
|
78
|
+
getTimelineTrackSize();
|
|
79
|
+
getPopoverSizes();
|
|
80
|
+
mouseEntered.value = true;
|
|
81
|
+
}
|
|
82
|
+
function onMouseleave() {
|
|
83
|
+
mouseEntered.value = false;
|
|
84
|
+
dragging.value = false;
|
|
85
|
+
seekedTime.value = 0;
|
|
86
|
+
}
|
|
87
|
+
function onPointerdown(e) {
|
|
88
|
+
dragging.value = true;
|
|
89
|
+
resumePlay.value = playing.value;
|
|
90
|
+
pause();
|
|
91
|
+
const x = e instanceof MouseEvent ? e.pageX : e.touches[0].pageX;
|
|
92
|
+
seekToTrackPosition(x);
|
|
93
|
+
}
|
|
94
|
+
function onPointerup() {
|
|
95
|
+
dragging.value = false;
|
|
96
|
+
if (resumePlay.value) {
|
|
97
|
+
play();
|
|
98
|
+
}
|
|
99
|
+
}
|
|
100
|
+
function onPointermove(e) {
|
|
101
|
+
const x = e instanceof MouseEvent ? e.pageX : e.touches[0].pageX;
|
|
102
|
+
seekToTrackPosition(x);
|
|
103
|
+
}
|
|
104
|
+
watch(() => trackRef, getTimelineTrackSize);
|
|
105
|
+
watch(() => popoverRef, getPopoverSizes);
|
|
106
|
+
watch(() => barRef, getPopoverSizes);
|
|
107
|
+
watch(currentTime, (value) => {
|
|
108
|
+
const percentage = value / duration?.value * 100;
|
|
109
|
+
scrubbedPercentage.value = mapValue(
|
|
110
|
+
percentage,
|
|
111
|
+
0,
|
|
112
|
+
100,
|
|
113
|
+
0,
|
|
114
|
+
thumbPercentage.value
|
|
115
|
+
);
|
|
116
|
+
});
|
|
117
|
+
useResizeObserver(trackRef, getTimelineTrackSize);
|
|
118
|
+
useResizeObserver(popoverRef, getPopoverSizes);
|
|
119
|
+
useEventListener(
|
|
120
|
+
defaultWindow,
|
|
121
|
+
"resize",
|
|
122
|
+
() => {
|
|
123
|
+
getTimelineTrackSize;
|
|
124
|
+
getPopoverSizes;
|
|
125
|
+
},
|
|
126
|
+
{
|
|
127
|
+
passive: true
|
|
128
|
+
}
|
|
129
|
+
);
|
|
130
|
+
const emitter = usePlayerStateEmitter();
|
|
131
|
+
emitter.on("update", (payload) => {
|
|
132
|
+
if (payload.id !== toValue(args.id))
|
|
133
|
+
return;
|
|
134
|
+
if (payload.api === "controls") {
|
|
135
|
+
switch (payload.key) {
|
|
136
|
+
case "dragging": {
|
|
137
|
+
dragging.value = payload.value;
|
|
138
|
+
break;
|
|
139
|
+
}
|
|
140
|
+
case "mouseEntered": {
|
|
141
|
+
mouseEntered.value = payload.value;
|
|
142
|
+
break;
|
|
143
|
+
}
|
|
144
|
+
case "seekedTime": {
|
|
145
|
+
seekedTime.value = payload.value;
|
|
146
|
+
break;
|
|
147
|
+
}
|
|
148
|
+
case "seekedPercentage": {
|
|
149
|
+
seekedPercentage.value = payload.value;
|
|
150
|
+
break;
|
|
151
|
+
}
|
|
152
|
+
case "scrubbedPercentage": {
|
|
153
|
+
scrubbedPercentage.value = payload.value;
|
|
154
|
+
break;
|
|
155
|
+
}
|
|
156
|
+
case "thumbPercentage": {
|
|
157
|
+
thumbPercentage.value = payload.value;
|
|
158
|
+
break;
|
|
159
|
+
}
|
|
160
|
+
case "popoverOffsetX": {
|
|
161
|
+
popoverOffsetX.value = payload.value;
|
|
162
|
+
break;
|
|
163
|
+
}
|
|
164
|
+
case "barRect": {
|
|
165
|
+
barRect.value = payload.value;
|
|
166
|
+
break;
|
|
167
|
+
}
|
|
168
|
+
case "trackRect": {
|
|
169
|
+
trackRect.value = payload.value;
|
|
170
|
+
break;
|
|
171
|
+
}
|
|
172
|
+
case "popoverRect": {
|
|
173
|
+
popoverRect.value = payload.value;
|
|
174
|
+
break;
|
|
175
|
+
}
|
|
176
|
+
}
|
|
177
|
+
}
|
|
178
|
+
});
|
|
179
|
+
watch(dragging, (value) => {
|
|
180
|
+
emitter.emit("update", {
|
|
181
|
+
id: toValue(args.id),
|
|
182
|
+
api: "controls",
|
|
183
|
+
key: "dragging",
|
|
184
|
+
value
|
|
185
|
+
});
|
|
186
|
+
});
|
|
187
|
+
watch(mouseEntered, (value) => {
|
|
188
|
+
emitter.emit("update", {
|
|
189
|
+
id: toValue(args.id),
|
|
190
|
+
api: "controls",
|
|
191
|
+
key: "mouseEntered",
|
|
192
|
+
value
|
|
193
|
+
});
|
|
194
|
+
});
|
|
195
|
+
watch(seekedTime, (value) => {
|
|
196
|
+
emitter.emit("update", {
|
|
197
|
+
id: toValue(args.id),
|
|
198
|
+
api: "controls",
|
|
199
|
+
key: "seekedTime",
|
|
200
|
+
value
|
|
201
|
+
});
|
|
202
|
+
});
|
|
203
|
+
watch(seekedPercentage, (value) => {
|
|
204
|
+
emitter.emit("update", {
|
|
205
|
+
id: toValue(args.id),
|
|
206
|
+
api: "controls",
|
|
207
|
+
key: "seekedPercentage",
|
|
208
|
+
value
|
|
209
|
+
});
|
|
210
|
+
});
|
|
211
|
+
watch(scrubbedPercentage, (value) => {
|
|
212
|
+
emitter.emit("update", {
|
|
213
|
+
id: toValue(args.id),
|
|
214
|
+
api: "controls",
|
|
215
|
+
key: "scrubbedPercentage",
|
|
216
|
+
value
|
|
217
|
+
});
|
|
218
|
+
});
|
|
219
|
+
watch(bufferedPercentage, (value) => {
|
|
220
|
+
emitter.emit("update", {
|
|
221
|
+
id: toValue(args.id),
|
|
222
|
+
api: "controls",
|
|
223
|
+
key: "bufferedPercentage",
|
|
224
|
+
value
|
|
225
|
+
});
|
|
226
|
+
});
|
|
227
|
+
watch(thumbPercentage, (value) => {
|
|
228
|
+
emitter.emit("update", {
|
|
229
|
+
id: toValue(args.id),
|
|
230
|
+
api: "controls",
|
|
231
|
+
key: "thumbPercentage",
|
|
232
|
+
value
|
|
233
|
+
});
|
|
234
|
+
});
|
|
235
|
+
watch(popoverOffsetX, (value) => {
|
|
236
|
+
emitter.emit("update", {
|
|
237
|
+
id: toValue(args.id),
|
|
238
|
+
api: "controls",
|
|
239
|
+
key: "popoverOffsetX",
|
|
240
|
+
value
|
|
241
|
+
});
|
|
242
|
+
});
|
|
243
|
+
watch(resumePlay, (value) => {
|
|
244
|
+
emitter.emit("update", {
|
|
245
|
+
id: toValue(args.id),
|
|
246
|
+
api: "controls",
|
|
247
|
+
key: "resumePlay",
|
|
248
|
+
value
|
|
249
|
+
});
|
|
250
|
+
});
|
|
251
|
+
watch(barRect, (value) => {
|
|
252
|
+
if (!value)
|
|
253
|
+
return;
|
|
254
|
+
emitter.emit("update", {
|
|
255
|
+
id: toValue(args.id),
|
|
256
|
+
api: "controls",
|
|
257
|
+
key: "barRect",
|
|
258
|
+
value
|
|
259
|
+
});
|
|
260
|
+
});
|
|
261
|
+
watch(trackRect, (value) => {
|
|
262
|
+
if (!value)
|
|
263
|
+
return;
|
|
264
|
+
emitter.emit("update", {
|
|
265
|
+
id: toValue(args.id),
|
|
266
|
+
api: "controls",
|
|
267
|
+
key: "trackRect",
|
|
268
|
+
value
|
|
269
|
+
});
|
|
270
|
+
});
|
|
271
|
+
watch(popoverRect, (value) => {
|
|
272
|
+
if (!value)
|
|
273
|
+
return;
|
|
274
|
+
emitter.emit("update", {
|
|
275
|
+
id: toValue(args.id),
|
|
276
|
+
api: "controls",
|
|
277
|
+
key: "popoverRect",
|
|
278
|
+
value
|
|
279
|
+
});
|
|
280
|
+
});
|
|
281
|
+
return {
|
|
282
|
+
mouseEntered,
|
|
283
|
+
dragging,
|
|
284
|
+
seekedTime,
|
|
285
|
+
seekedPercentage,
|
|
286
|
+
scrubbedPercentage,
|
|
287
|
+
bufferedPercentage,
|
|
288
|
+
thumbPercentage,
|
|
289
|
+
popoverOffsetX,
|
|
290
|
+
onMouseenter,
|
|
291
|
+
onMouseleave,
|
|
292
|
+
onPointerdown,
|
|
293
|
+
onPointerup,
|
|
294
|
+
onPointermove,
|
|
295
|
+
trackRect
|
|
296
|
+
};
|
|
297
|
+
}
|
package/dist/plugins/MagicPlayer/src/composables/private/{useMediaApi.d.ts → usePlayerMediaApi.d.ts}
RENAMED
|
@@ -1,15 +1,19 @@
|
|
|
1
|
-
import type
|
|
2
|
-
export
|
|
1
|
+
import { type MaybeRef } from 'vue';
|
|
2
|
+
export type UsePlayerMediaApiArgs = {
|
|
3
|
+
id: MaybeRef<string>;
|
|
4
|
+
mediaRef?: MaybeRef<HTMLMediaElement | undefined>;
|
|
5
|
+
};
|
|
6
|
+
export declare function usePlayerMediaApi(args: UsePlayerMediaApiArgs): {
|
|
3
7
|
currentTime: import("vue").Ref<number>;
|
|
4
8
|
duration: import("vue").Ref<number>;
|
|
5
|
-
waiting: import("vue").Ref<boolean>;
|
|
6
9
|
seeking: import("vue").Ref<boolean>;
|
|
10
|
+
volume: import("vue").Ref<number>;
|
|
11
|
+
rate: import("vue").Ref<number>;
|
|
12
|
+
waiting: import("vue").Ref<boolean>;
|
|
7
13
|
ended: import("vue").Ref<boolean>;
|
|
14
|
+
playing: import("vue").Ref<boolean>;
|
|
8
15
|
stalled: import("vue").Ref<boolean>;
|
|
9
16
|
buffered: import("vue").Ref<[number, number][]>;
|
|
10
|
-
playing: import("vue").Ref<boolean>;
|
|
11
|
-
rate: import("vue").Ref<number>;
|
|
12
|
-
volume: import("vue").Ref<number>;
|
|
13
17
|
muted: import("vue").Ref<boolean>;
|
|
14
18
|
};
|
|
15
|
-
export type
|
|
19
|
+
export type UsePlayerMediaApiReturn = ReturnType<typeof usePlayerMediaApi>;
|
|
@@ -0,0 +1,263 @@
|
|
|
1
|
+
import { ref, watch, unref, toValue } from "vue";
|
|
2
|
+
import { useEventListener, watchIgnorable } from "@vueuse/core";
|
|
3
|
+
import { usePlayerStateEmitter } from "./usePlayerStateEmitter.mjs";
|
|
4
|
+
export function usePlayerMediaApi(args) {
|
|
5
|
+
const currentTime = ref(0);
|
|
6
|
+
const duration = ref(0);
|
|
7
|
+
const seeking = ref(false);
|
|
8
|
+
const volume = ref(1);
|
|
9
|
+
const rate = ref(1);
|
|
10
|
+
const waiting = ref(false);
|
|
11
|
+
const ended = ref(false);
|
|
12
|
+
const playing = ref(false);
|
|
13
|
+
const stalled = ref(false);
|
|
14
|
+
const buffered = ref([]);
|
|
15
|
+
const muted = ref(false);
|
|
16
|
+
const { mediaRef } = args;
|
|
17
|
+
function timeRangeToArray(timeRanges) {
|
|
18
|
+
let ranges = [];
|
|
19
|
+
for (let i = 0; i < timeRanges.length; ++i)
|
|
20
|
+
ranges = [...ranges, [timeRanges.start(i), timeRanges.end(i)]];
|
|
21
|
+
return ranges;
|
|
22
|
+
}
|
|
23
|
+
watch(volume, () => {
|
|
24
|
+
const el = toValue(mediaRef);
|
|
25
|
+
if (!el)
|
|
26
|
+
return;
|
|
27
|
+
el.volume = volume.value;
|
|
28
|
+
});
|
|
29
|
+
watch(muted, () => {
|
|
30
|
+
const el = toValue(mediaRef);
|
|
31
|
+
if (!el)
|
|
32
|
+
return;
|
|
33
|
+
el.muted = muted.value;
|
|
34
|
+
});
|
|
35
|
+
watch(rate, () => {
|
|
36
|
+
const el = toValue(mediaRef);
|
|
37
|
+
if (!el)
|
|
38
|
+
return;
|
|
39
|
+
el.playbackRate = rate.value;
|
|
40
|
+
});
|
|
41
|
+
if (toValue(mediaRef)) {
|
|
42
|
+
watch([mediaRef], () => {
|
|
43
|
+
const el = toValue(mediaRef);
|
|
44
|
+
if (!el)
|
|
45
|
+
return;
|
|
46
|
+
el.volume = volume.value;
|
|
47
|
+
el.muted = muted.value;
|
|
48
|
+
el.playbackRate = rate.value;
|
|
49
|
+
});
|
|
50
|
+
}
|
|
51
|
+
const { ignoreUpdates: ignoreCurrentTimeUpdates } = watchIgnorable(
|
|
52
|
+
currentTime,
|
|
53
|
+
(time) => {
|
|
54
|
+
const el = toValue(mediaRef);
|
|
55
|
+
if (!el)
|
|
56
|
+
return;
|
|
57
|
+
el.currentTime = unref(time);
|
|
58
|
+
}
|
|
59
|
+
);
|
|
60
|
+
const { ignoreUpdates: ignorePlayingUpdates } = watchIgnorable(
|
|
61
|
+
playing,
|
|
62
|
+
(isPlaying) => {
|
|
63
|
+
const el = toValue(mediaRef);
|
|
64
|
+
if (!el)
|
|
65
|
+
return;
|
|
66
|
+
isPlaying ? el.play() : el.pause();
|
|
67
|
+
}
|
|
68
|
+
);
|
|
69
|
+
useEventListener(mediaRef, "timeupdate", () => {
|
|
70
|
+
ignoreCurrentTimeUpdates(
|
|
71
|
+
() => currentTime.value = toValue(mediaRef).currentTime
|
|
72
|
+
);
|
|
73
|
+
});
|
|
74
|
+
useEventListener(mediaRef, "durationchange", () => {
|
|
75
|
+
duration.value = toValue(mediaRef).duration;
|
|
76
|
+
});
|
|
77
|
+
useEventListener(mediaRef, "progress", () => {
|
|
78
|
+
buffered.value = timeRangeToArray(toValue(mediaRef).buffered);
|
|
79
|
+
});
|
|
80
|
+
useEventListener(mediaRef, "seeking", () => {
|
|
81
|
+
seeking.value = true;
|
|
82
|
+
});
|
|
83
|
+
useEventListener(mediaRef, "seeked", () => {
|
|
84
|
+
seeking.value = false;
|
|
85
|
+
});
|
|
86
|
+
useEventListener(mediaRef, ["waiting", "loadstart"], () => {
|
|
87
|
+
waiting.value = true;
|
|
88
|
+
ignorePlayingUpdates(() => playing.value = false);
|
|
89
|
+
});
|
|
90
|
+
useEventListener(mediaRef, "loadeddata", () => {
|
|
91
|
+
waiting.value = false;
|
|
92
|
+
});
|
|
93
|
+
useEventListener(mediaRef, "playing", () => {
|
|
94
|
+
waiting.value = false;
|
|
95
|
+
ended.value = false;
|
|
96
|
+
ignorePlayingUpdates(() => playing.value = true);
|
|
97
|
+
});
|
|
98
|
+
useEventListener(mediaRef, "ratechange", () => {
|
|
99
|
+
rate.value = toValue(mediaRef).playbackRate;
|
|
100
|
+
});
|
|
101
|
+
useEventListener(mediaRef, "stalled", () => {
|
|
102
|
+
stalled.value = true;
|
|
103
|
+
});
|
|
104
|
+
useEventListener(mediaRef, "ended", () => {
|
|
105
|
+
ended.value = true;
|
|
106
|
+
});
|
|
107
|
+
useEventListener(mediaRef, "pause", () => {
|
|
108
|
+
playing.value = false;
|
|
109
|
+
});
|
|
110
|
+
useEventListener(mediaRef, "play", () => {
|
|
111
|
+
playing.value = true;
|
|
112
|
+
});
|
|
113
|
+
useEventListener(mediaRef, "volumechange", () => {
|
|
114
|
+
const el = toValue(mediaRef);
|
|
115
|
+
if (!el)
|
|
116
|
+
return;
|
|
117
|
+
volume.value = el.volume;
|
|
118
|
+
muted.value = el.muted;
|
|
119
|
+
});
|
|
120
|
+
const emitter = usePlayerStateEmitter();
|
|
121
|
+
emitter.on("update", (payload) => {
|
|
122
|
+
if (payload.id !== toValue(args.id))
|
|
123
|
+
return;
|
|
124
|
+
if (payload.api === "media") {
|
|
125
|
+
switch (payload.key) {
|
|
126
|
+
case "currentTime":
|
|
127
|
+
currentTime.value = payload.value;
|
|
128
|
+
break;
|
|
129
|
+
case "duration":
|
|
130
|
+
duration.value = payload.value;
|
|
131
|
+
break;
|
|
132
|
+
case "seeking":
|
|
133
|
+
seeking.value = payload.value;
|
|
134
|
+
break;
|
|
135
|
+
case "volume":
|
|
136
|
+
volume.value = payload.value;
|
|
137
|
+
break;
|
|
138
|
+
case "rate":
|
|
139
|
+
rate.value = payload.value;
|
|
140
|
+
break;
|
|
141
|
+
case "waiting":
|
|
142
|
+
waiting.value = payload.value;
|
|
143
|
+
break;
|
|
144
|
+
case "ended":
|
|
145
|
+
ended.value = payload.value;
|
|
146
|
+
break;
|
|
147
|
+
case "playing":
|
|
148
|
+
playing.value = payload.value;
|
|
149
|
+
break;
|
|
150
|
+
case "stalled":
|
|
151
|
+
stalled.value = payload.value;
|
|
152
|
+
break;
|
|
153
|
+
case "buffered":
|
|
154
|
+
buffered.value = payload.value;
|
|
155
|
+
break;
|
|
156
|
+
case "muted":
|
|
157
|
+
muted.value = payload.value;
|
|
158
|
+
break;
|
|
159
|
+
}
|
|
160
|
+
}
|
|
161
|
+
});
|
|
162
|
+
watch(currentTime, (value) => {
|
|
163
|
+
emitter.emit("update", {
|
|
164
|
+
id: toValue(args.id),
|
|
165
|
+
api: "media",
|
|
166
|
+
key: "currentTime",
|
|
167
|
+
value
|
|
168
|
+
});
|
|
169
|
+
});
|
|
170
|
+
watch(duration, (value) => {
|
|
171
|
+
emitter.emit("update", {
|
|
172
|
+
id: toValue(args.id),
|
|
173
|
+
api: "media",
|
|
174
|
+
key: "duration",
|
|
175
|
+
value
|
|
176
|
+
});
|
|
177
|
+
});
|
|
178
|
+
watch(seeking, (value) => {
|
|
179
|
+
emitter.emit("update", {
|
|
180
|
+
id: toValue(args.id),
|
|
181
|
+
api: "media",
|
|
182
|
+
key: "seeking",
|
|
183
|
+
value
|
|
184
|
+
});
|
|
185
|
+
});
|
|
186
|
+
watch(volume, (value) => {
|
|
187
|
+
emitter.emit("update", {
|
|
188
|
+
id: toValue(args.id),
|
|
189
|
+
api: "media",
|
|
190
|
+
key: "volume",
|
|
191
|
+
value
|
|
192
|
+
});
|
|
193
|
+
});
|
|
194
|
+
watch(rate, (value) => {
|
|
195
|
+
emitter.emit("update", {
|
|
196
|
+
id: toValue(args.id),
|
|
197
|
+
api: "media",
|
|
198
|
+
key: "rate",
|
|
199
|
+
value
|
|
200
|
+
});
|
|
201
|
+
});
|
|
202
|
+
watch(waiting, (value) => {
|
|
203
|
+
emitter.emit("update", {
|
|
204
|
+
id: toValue(args.id),
|
|
205
|
+
api: "media",
|
|
206
|
+
key: "waiting",
|
|
207
|
+
value
|
|
208
|
+
});
|
|
209
|
+
});
|
|
210
|
+
watch(ended, (value) => {
|
|
211
|
+
emitter.emit("update", {
|
|
212
|
+
id: toValue(args.id),
|
|
213
|
+
api: "media",
|
|
214
|
+
key: "ended",
|
|
215
|
+
value
|
|
216
|
+
});
|
|
217
|
+
});
|
|
218
|
+
watch(playing, (value) => {
|
|
219
|
+
emitter.emit("update", {
|
|
220
|
+
id: toValue(args.id),
|
|
221
|
+
api: "media",
|
|
222
|
+
key: "playing",
|
|
223
|
+
value
|
|
224
|
+
});
|
|
225
|
+
});
|
|
226
|
+
watch(stalled, (value) => {
|
|
227
|
+
emitter.emit("update", {
|
|
228
|
+
id: toValue(args.id),
|
|
229
|
+
api: "media",
|
|
230
|
+
key: "stalled",
|
|
231
|
+
value
|
|
232
|
+
});
|
|
233
|
+
});
|
|
234
|
+
watch(buffered, (value) => {
|
|
235
|
+
emitter.emit("update", {
|
|
236
|
+
id: toValue(args.id),
|
|
237
|
+
api: "media",
|
|
238
|
+
key: "buffered",
|
|
239
|
+
value
|
|
240
|
+
});
|
|
241
|
+
});
|
|
242
|
+
watch(muted, (value) => {
|
|
243
|
+
emitter.emit("update", {
|
|
244
|
+
id: toValue(args.id),
|
|
245
|
+
api: "media",
|
|
246
|
+
key: "muted",
|
|
247
|
+
value
|
|
248
|
+
});
|
|
249
|
+
});
|
|
250
|
+
return {
|
|
251
|
+
currentTime,
|
|
252
|
+
duration,
|
|
253
|
+
seeking,
|
|
254
|
+
volume,
|
|
255
|
+
rate,
|
|
256
|
+
waiting,
|
|
257
|
+
ended,
|
|
258
|
+
playing,
|
|
259
|
+
stalled,
|
|
260
|
+
buffered,
|
|
261
|
+
muted
|
|
262
|
+
};
|
|
263
|
+
}
|
|
@@ -0,0 +1,12 @@
|
|
|
1
|
+
import { type MaybeRef } from 'vue';
|
|
2
|
+
import type { SourceType } from '../../types.js';
|
|
3
|
+
export type UsePlayerRuntimeArgs = {
|
|
4
|
+
id: MaybeRef<string>;
|
|
5
|
+
mediaRef?: MaybeRef<HTMLVideoElement | undefined>;
|
|
6
|
+
srcType?: SourceType;
|
|
7
|
+
src?: string;
|
|
8
|
+
};
|
|
9
|
+
export declare function usePlayerRuntime(args: UsePlayerRuntimeArgs): {
|
|
10
|
+
loaded: import("vue").Ref<boolean>;
|
|
11
|
+
};
|
|
12
|
+
export type UsePlayerRuntimeReturn = ReturnType<typeof usePlayerRuntime>;
|
|
@@ -0,0 +1,70 @@
|
|
|
1
|
+
import { ref, watch, onMounted, onUnmounted, toValue } from "vue";
|
|
2
|
+
import { usePlayerStateEmitter } from "./usePlayerStateEmitter.mjs";
|
|
3
|
+
export function usePlayerRuntime(args) {
|
|
4
|
+
let hls;
|
|
5
|
+
const loaded = ref(false);
|
|
6
|
+
const { mediaRef, srcType, src } = args;
|
|
7
|
+
const useNative = () => {
|
|
8
|
+
const el = toValue(mediaRef);
|
|
9
|
+
if (!el || !src)
|
|
10
|
+
return;
|
|
11
|
+
el.src = src;
|
|
12
|
+
el.addEventListener(
|
|
13
|
+
"loadeddata",
|
|
14
|
+
() => {
|
|
15
|
+
loaded.value = true;
|
|
16
|
+
},
|
|
17
|
+
{ once: true }
|
|
18
|
+
);
|
|
19
|
+
el.load();
|
|
20
|
+
};
|
|
21
|
+
const useHlsJS = async () => {
|
|
22
|
+
const el = toValue(mediaRef);
|
|
23
|
+
if (!el)
|
|
24
|
+
return;
|
|
25
|
+
const { default: Hls } = await import("hls.js");
|
|
26
|
+
hls = new Hls();
|
|
27
|
+
if (!Hls.isSupported()) {
|
|
28
|
+
useNative();
|
|
29
|
+
} else if (src) {
|
|
30
|
+
hls.loadSource(src);
|
|
31
|
+
hls.attachMedia(el);
|
|
32
|
+
hls.on(Hls.Events.FRAG_LOADED, () => {
|
|
33
|
+
loaded.value = true;
|
|
34
|
+
});
|
|
35
|
+
}
|
|
36
|
+
};
|
|
37
|
+
onMounted(() => {
|
|
38
|
+
if (srcType === "native") {
|
|
39
|
+
useNative();
|
|
40
|
+
} else if (srcType === "hls") {
|
|
41
|
+
useHlsJS();
|
|
42
|
+
}
|
|
43
|
+
});
|
|
44
|
+
onUnmounted(() => {
|
|
45
|
+
hls?.destroy();
|
|
46
|
+
});
|
|
47
|
+
const emitter = usePlayerStateEmitter();
|
|
48
|
+
emitter.on("update", (payload) => {
|
|
49
|
+
if (payload.id !== toValue(args.id))
|
|
50
|
+
return;
|
|
51
|
+
if (payload.api === "runtime") {
|
|
52
|
+
switch (payload.key) {
|
|
53
|
+
case "loaded":
|
|
54
|
+
loaded.value = payload.value;
|
|
55
|
+
break;
|
|
56
|
+
}
|
|
57
|
+
}
|
|
58
|
+
});
|
|
59
|
+
watch(loaded, (value) => {
|
|
60
|
+
emitter.emit("update", {
|
|
61
|
+
id: toValue(args.id),
|
|
62
|
+
api: "runtime",
|
|
63
|
+
key: "loaded",
|
|
64
|
+
value
|
|
65
|
+
});
|
|
66
|
+
});
|
|
67
|
+
return {
|
|
68
|
+
loaded
|
|
69
|
+
};
|
|
70
|
+
}
|
|
@@ -0,0 +1,15 @@
|
|
|
1
|
+
import type { PlayerPrivateEvents } from '../../types.js';
|
|
2
|
+
export declare function usePlayerStateEmitter(): {
|
|
3
|
+
on: {
|
|
4
|
+
<Key extends "update">(type: Key, handler: import("mitt").Handler<PlayerPrivateEvents[Key]>): void;
|
|
5
|
+
(type: "*", handler: import("mitt").WildcardHandler<PlayerPrivateEvents>): void;
|
|
6
|
+
};
|
|
7
|
+
off: {
|
|
8
|
+
<Key_1 extends "update">(type: Key_1, handler?: import("mitt").Handler<PlayerPrivateEvents[Key_1]> | undefined): void;
|
|
9
|
+
(type: "*", handler: import("mitt").WildcardHandler<PlayerPrivateEvents>): void;
|
|
10
|
+
};
|
|
11
|
+
emit: {
|
|
12
|
+
<Key_2 extends "update">(type: Key_2, event: PlayerPrivateEvents[Key_2]): void;
|
|
13
|
+
<Key_3 extends "update">(type: undefined extends PlayerPrivateEvents[Key_3] ? Key_3 : never): void;
|
|
14
|
+
};
|
|
15
|
+
};
|