@therealtinhtute/baroiplayer 1.0.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/LICENSE +21 -0
- package/README.md +384 -0
- package/dist/context/media.js +2 -0
- package/dist/context/media.js.map +1 -0
- package/dist/context/media.mjs +15 -0
- package/dist/context/media.mjs.map +1 -0
- package/dist/context/store.js +2 -0
- package/dist/context/store.js.map +1 -0
- package/dist/context/store.mjs +5 -0
- package/dist/context/store.mjs.map +1 -0
- package/dist/context-BMteAJDN.js +1140 -0
- package/dist/context-BMteAJDN.js.map +1 -0
- package/dist/context-DCJ_scmO.cjs +23 -0
- package/dist/context-DCJ_scmO.cjs.map +1 -0
- package/dist/core-events-B5W_j8yU.js +480 -0
- package/dist/core-events-B5W_j8yU.js.map +1 -0
- package/dist/core-events-CN0-Vhhq.cjs +2 -0
- package/dist/core-events-CN0-Vhhq.cjs.map +1 -0
- package/dist/core-plugins-Bq9KLany.js +696 -0
- package/dist/core-plugins-Bq9KLany.js.map +1 -0
- package/dist/core-plugins-CPDSHMiQ.cjs +2 -0
- package/dist/core-plugins-CPDSHMiQ.cjs.map +1 -0
- package/dist/core.js +37 -0
- package/dist/core.js.map +1 -0
- package/dist/core.mjs +1217 -0
- package/dist/core.mjs.map +1 -0
- package/dist/enhanced-components-DHv0MFvG.js +1073 -0
- package/dist/enhanced-components-DHv0MFvG.js.map +1 -0
- package/dist/enhanced-components-DTIObgB7.cjs +2 -0
- package/dist/enhanced-components-DTIObgB7.cjs.map +1 -0
- package/dist/hooks-C_r8wexn.cjs +4 -0
- package/dist/hooks-C_r8wexn.cjs.map +1 -0
- package/dist/hooks-Da2wVXlF.js +1630 -0
- package/dist/hooks-Da2wVXlF.js.map +1 -0
- package/dist/index.css +1 -0
- package/dist/index.js +112 -0
- package/dist/index.js.map +1 -0
- package/dist/index.mjs +6126 -0
- package/dist/index.mjs.map +1 -0
- package/dist/minimal-components-DSq5sQpy.js +2002 -0
- package/dist/minimal-components-DSq5sQpy.js.map +1 -0
- package/dist/minimal-components-DflWiihN.cjs +2 -0
- package/dist/minimal-components-DflWiihN.cjs.map +1 -0
- package/dist/minimal-components.css +1 -0
- package/dist/mona-loading.gif +0 -0
- package/dist/performance-monitor-CUW6f5ll.cjs +2 -0
- package/dist/performance-monitor-CUW6f5ll.cjs.map +1 -0
- package/dist/performance-monitor-rMW1RgV3.js +302 -0
- package/dist/performance-monitor-rMW1RgV3.js.map +1 -0
- package/dist/utils-BnscpYYd.js +2798 -0
- package/dist/utils-BnscpYYd.js.map +1 -0
- package/dist/utils-D_czS_0K.cjs +9 -0
- package/dist/utils-D_czS_0K.cjs.map +1 -0
- package/dist/utils.js +2 -0
- package/dist/utils.js.map +1 -0
- package/dist/utils.mjs +7 -0
- package/dist/utils.mjs.map +1 -0
- package/package.json +114 -0
- package/src/adapters/videojs-adapter.tsx +470 -0
- package/src/assets/mona-loading.gif +0 -0
- package/src/components/AnimateLoading.tsx +115 -0
- package/src/components/LoadingState.tsx +248 -0
- package/src/components/accessibility/keyboard-help-overlay.tsx +213 -0
- package/src/components/audio-player.tsx +85 -0
- package/src/components/basic/index.ts +37 -0
- package/src/components/enhanced/advanced-features.tsx +316 -0
- package/src/components/enhanced/debug-panel.tsx +422 -0
- package/src/components/enhanced/enhanced-controls.tsx +600 -0
- package/src/components/enhanced/enhanced-media-player.tsx +509 -0
- package/src/components/enhanced/error-handling.tsx +345 -0
- package/src/components/enhanced/index.ts +39 -0
- package/src/components/enhanced/media-player-enhanced.tsx +349 -0
- package/src/components/examples/basic-video-player.tsx +55 -0
- package/src/components/examples/custom-controls-example.tsx +63 -0
- package/src/components/examples/enhanced-controls-example.tsx +114 -0
- package/src/components/examples/enhanced-media-player-example.tsx +293 -0
- package/src/components/examples/loading-states-demo.tsx +142 -0
- package/src/components/examples/react-19-demo.tsx +381 -0
- package/src/components/examples/volume-orientation-demo.tsx +114 -0
- package/src/components/icon-demo.tsx +209 -0
- package/src/components/icons/index.tsx +166 -0
- package/src/components/icons/svg-icons/ArrowLeftIcon.tsx +18 -0
- package/src/components/icons/svg-icons/ArrowRightIcon.tsx +18 -0
- package/src/components/icons/svg-icons/AudioIcon.tsx +22 -0
- package/src/components/icons/svg-icons/BackwardIcon.tsx +12 -0
- package/src/components/icons/svg-icons/CameraIcon.tsx +19 -0
- package/src/components/icons/svg-icons/CheckIcon.tsx +19 -0
- package/src/components/icons/svg-icons/EnablePiPIcon.tsx +17 -0
- package/src/components/icons/svg-icons/ForwardIcon.tsx +12 -0
- package/src/components/icons/svg-icons/FullscreenEnterIcon.tsx +23 -0
- package/src/components/icons/svg-icons/FullscreenExitIcon.tsx +23 -0
- package/src/components/icons/svg-icons/LoadingIcon.tsx +32 -0
- package/src/components/icons/svg-icons/PauseIcon.tsx +23 -0
- package/src/components/icons/svg-icons/PlayIcon.tsx +21 -0
- package/src/components/icons/svg-icons/PlaybackSpeedIcon.tsx +23 -0
- package/src/components/icons/svg-icons/QualityIcon.tsx +21 -0
- package/src/components/icons/svg-icons/SettingsIcon.tsx +12 -0
- package/src/components/icons/svg-icons/SliderIcon.tsx +21 -0
- package/src/components/icons/svg-icons/SubtitleIcon.tsx +21 -0
- package/src/components/icons/svg-icons/SubtitleOffIcon.tsx +25 -0
- package/src/components/icons/svg-icons/UnPiPIcon.tsx +17 -0
- package/src/components/icons/svg-icons/VolumeMutedIcon.tsx +16 -0
- package/src/components/icons/svg-icons/VolumeOneIcon.tsx +22 -0
- package/src/components/icons/svg-icons/VolumeThreeIcon.tsx +16 -0
- package/src/components/icons/svg-icons/VolumeTwoIcon.tsx +16 -0
- package/src/components/legacy.tsx +93 -0
- package/src/components/media-metadata-display.tsx +100 -0
- package/src/components/media-player-audio.tsx +39 -0
- package/src/components/media-player-controls.tsx +226 -0
- package/src/components/media-player-error.tsx +163 -0
- package/src/components/media-player-fullscreen.tsx +109 -0
- package/src/components/media-player-hls.tsx +111 -0
- package/src/components/media-player-loading.tsx +76 -0
- package/src/components/media-player-play.tsx +75 -0
- package/src/components/media-player-root.tsx +340 -0
- package/src/components/media-player-seek.tsx +168 -0
- package/src/components/media-player-time.tsx +99 -0
- package/src/components/media-player-tooltip.tsx +58 -0
- package/src/components/media-player-video.tsx +39 -0
- package/src/components/media-player-volume.tsx +155 -0
- package/src/components/media-player.tsx +257 -0
- package/src/components/media-suspense.tsx +362 -0
- package/src/components/player-settings-form.tsx +163 -0
- package/src/components/react-player-wrapper.tsx +651 -0
- package/src/components/simple-video-player.tsx +60 -0
- package/src/components/ui/enhanced-seek-bar.tsx +235 -0
- package/src/components/ui/fullscreen-button.tsx +60 -0
- package/src/components/ui/media-resource-preloader.tsx +395 -0
- package/src/components/ui/play-button.tsx +107 -0
- package/src/components/ui/seek-bar.tsx +161 -0
- package/src/components/ui/time-display.tsx +40 -0
- package/src/components/ui/volume-control.tsx +143 -0
- package/src/components/unified/base-media-player.tsx +246 -0
- package/src/components/unified/media-player.tsx +75 -0
- package/src/components/variants/minimal/AccessibleMinimalPlayer.tsx +561 -0
- package/src/components/variants/minimal/EnhancedMinimalMediaPlayer.tsx +552 -0
- package/src/components/variants/minimal/MinimalControls.tsx +142 -0
- package/src/components/variants/minimal/MinimalLoading.tsx +32 -0
- package/src/components/variants/minimal/MinimalMediaPlayer.tsx +315 -0
- package/src/components/variants/minimal/MinimalOverlay.tsx +64 -0
- package/src/components/variants/minimal/MinimalPlayButton.tsx +65 -0
- package/src/components/variants/minimal/MinimalSeekBar.tsx +150 -0
- package/src/components/variants/minimal/MinimalVolumeControl.tsx +80 -0
- package/src/components/variants/minimal/SimpleMinimalPlayer.tsx +210 -0
- package/src/components/variants/minimal/components/CenterPlayButton.tsx +22 -0
- package/src/components/variants/minimal/components/ControlBar.tsx +146 -0
- package/src/components/variants/minimal/components/EnhancedSettingsMenu.tsx +361 -0
- package/src/components/variants/minimal/components/PlaybackControls.tsx +51 -0
- package/src/components/variants/minimal/components/RightControls.tsx +173 -0
- package/src/components/variants/minimal/components/SeekBar.tsx +131 -0
- package/src/components/variants/minimal/components/SettingsDropdown.tsx +70 -0
- package/src/components/variants/minimal/components/SubtitleDisplay.tsx +21 -0
- package/src/components/variants/minimal/components/TimeDisplay.tsx +18 -0
- package/src/components/variants/minimal/components/VideoElement.tsx +40 -0
- package/src/components/variants/minimal/components/VolumeControl.tsx +217 -0
- package/src/components/variants/minimal/index.ts +23 -0
- package/src/components/video-player.tsx +100 -0
- package/src/context/error-handling.ts +394 -0
- package/src/context/media-context.tsx +208 -0
- package/src/context/media-provider.tsx +265 -0
- package/src/context/media-store.ts +379 -0
- package/src/context/persistence.ts +453 -0
- package/src/core/events/event-system.ts +442 -0
- package/src/core/events/hooks.ts +302 -0
- package/src/core/events/index.ts +22 -0
- package/src/core/events/middleware.ts +269 -0
- package/src/core/index.ts +22 -0
- package/src/core/optimization/bundle-optimizer.tsx +308 -0
- package/src/core/performance/cicd.ts +96 -0
- package/src/core/performance/index.ts +38 -0
- package/src/core/performance/media-loading-optimizer.ts +538 -0
- package/src/core/performance/performance-budgets.ts +432 -0
- package/src/core/performance/performance-monitor.tsx +476 -0
- package/src/core/performance/performance-testing.ts +459 -0
- package/src/core/plugins/base-plugin.ts +224 -0
- package/src/core/plugins/enhanced-plugin-system.ts +411 -0
- package/src/core/plugins/examples/analytics-plugin.ts +242 -0
- package/src/core/plugins/index.ts +39 -0
- package/src/core/plugins/registry.ts +327 -0
- package/src/core/plugins/types.ts +159 -0
- package/src/core/plugins/utils.ts +316 -0
- package/src/core/progressive-loading.tsx +322 -0
- package/src/core/providers/enhanced-hls-provider.ts +339 -0
- package/src/core/providers/service-provider.tsx +168 -0
- package/src/core/utils.tsx +38 -0
- package/src/features/media-session/media-session-manager.ts +429 -0
- package/src/features/picture-in-picture/pip-manager.ts +429 -0
- package/src/features/playlist/playlist-manager.ts +606 -0
- package/src/features/subtitles/subtitle-manager.ts +441 -0
- package/src/features/subtitles/subtitle-parser.ts +280 -0
- package/src/features/thumbnails/thumbnail-generator.ts +519 -0
- package/src/hooks/accessibility/index.ts +27 -0
- package/src/hooks/accessibility/use-accessibility-preferences.ts +188 -0
- package/src/hooks/accessibility/use-focus-management.ts +176 -0
- package/src/hooks/accessibility/use-keyboard-shortcuts.ts +144 -0
- package/src/hooks/accessibility/use-screen-reader.ts +182 -0
- package/src/hooks/core/index.ts +47 -0
- package/src/hooks/legacy.ts +27 -0
- package/src/hooks/use-enhanced-media-player.ts +468 -0
- package/src/hooks/use-intelligent-preloading.ts +358 -0
- package/src/hooks/use-keyboard-controls.ts +115 -0
- package/src/hooks/use-media-actions.ts +175 -0
- package/src/hooks/use-media-metadata.ts +89 -0
- package/src/hooks/use-media-optimistic.ts +270 -0
- package/src/hooks/use-media-player.ts +312 -0
- package/src/hooks/use-media-state.ts +190 -0
- package/src/hooks/use-memory-optimization.ts +358 -0
- package/src/hooks/use-optimistic-controls.ts +92 -0
- package/src/hooks/use-optimized-media.ts +263 -0
- package/src/hooks/use-touch-gestures.ts +417 -0
- package/src/hooks/useEnhancedSubtitles.ts +258 -0
- package/src/hooks/useKeyboardShortcuts.ts +74 -0
- package/src/hooks/useMediaControls.ts +52 -0
- package/src/hooks/useScreenshot.ts +57 -0
- package/src/hooks/useSubtitles.ts +91 -0
- package/src/hooks/useVideoPlayer.ts +232 -0
- package/src/icons/components/FullscreenIcon.tsx +37 -0
- package/src/icons/components/SettingsIcon.tsx +38 -0
- package/src/icons/components/animated/LoadingIcon.tsx +43 -0
- package/src/icons/components/animated/PlayPauseIcon.tsx +50 -0
- package/src/icons/components/media/PauseIcon.tsx +39 -0
- package/src/icons/components/media/PlayIcon.tsx +38 -0
- package/src/icons/components/volume/VolumeIcon.tsx +39 -0
- package/src/icons/components/volume/VolumeOffIcon.tsx +39 -0
- package/src/icons/index.ts +56 -0
- package/src/icons/provider.tsx +64 -0
- package/src/icons/types.ts +40 -0
- package/src/index-enhanced.ts +35 -0
- package/src/index-legacy.ts +326 -0
- package/src/index.css +102 -0
- package/src/index.ts +216 -0
- package/src/lib/deprecation.ts +51 -0
- package/src/lib/format-time.ts +37 -0
- package/src/lib/index.ts +3 -0
- package/src/lib/utils.ts +6 -0
- package/src/styles/globals.css +462 -0
- package/src/styles/minimal-player.css +589 -0
- package/src/styles/pixel-art.css +46 -0
- package/src/styles/videojs.css +100 -0
- package/src/test/setup.ts +79 -0
- package/src/types/events.ts +47 -0
- package/src/types/formats.ts +95 -0
- package/src/types/index.ts +190 -0
- package/src/types/videojs-plugins.d.ts +14 -0
|
@@ -0,0 +1,442 @@
|
|
|
1
|
+
// Event system types
|
|
2
|
+
export interface MediaPlayerEvent {
|
|
3
|
+
type: string
|
|
4
|
+
timestamp: number
|
|
5
|
+
target?: string
|
|
6
|
+
detail?: any
|
|
7
|
+
bubbles?: boolean
|
|
8
|
+
cancelable?: boolean
|
|
9
|
+
defaultPrevented?: boolean
|
|
10
|
+
}
|
|
11
|
+
|
|
12
|
+
export type EventHandler<T = any> = (event: MediaPlayerEvent & { detail: T }) => void
|
|
13
|
+
export type EventUnsubscriber = () => void
|
|
14
|
+
|
|
15
|
+
export interface EventOptions {
|
|
16
|
+
once?: boolean
|
|
17
|
+
passive?: boolean
|
|
18
|
+
priority?: 'high' | 'normal' | 'low'
|
|
19
|
+
filter?: (event: MediaPlayerEvent) => boolean
|
|
20
|
+
}
|
|
21
|
+
|
|
22
|
+
// Event categories for organization
|
|
23
|
+
export type EventCategory =
|
|
24
|
+
| 'media' // Media playback events
|
|
25
|
+
| 'user' // User interaction events
|
|
26
|
+
| 'system' // System/internal events
|
|
27
|
+
| 'plugin' // Plugin events
|
|
28
|
+
| 'error' // Error events
|
|
29
|
+
| 'performance' // Performance events
|
|
30
|
+
|
|
31
|
+
// Standard media events
|
|
32
|
+
export interface MediaEvents {
|
|
33
|
+
// Playback events
|
|
34
|
+
'media:loadstart': { src: string }
|
|
35
|
+
'media:loadeddata': { duration: number }
|
|
36
|
+
'media:canplay': {}
|
|
37
|
+
'media:canplaythrough': {}
|
|
38
|
+
'media:play': { currentTime: number }
|
|
39
|
+
'media:pause': { currentTime: number }
|
|
40
|
+
'media:ended': { duration: number }
|
|
41
|
+
'media:seeking': { currentTime: number, targetTime: number }
|
|
42
|
+
'media:seeked': { currentTime: number, previousTime: number }
|
|
43
|
+
'media:timeupdate': { currentTime: number, duration: number }
|
|
44
|
+
'media:durationchange': { duration: number }
|
|
45
|
+
'media:volumechange': { volume: number, muted: boolean }
|
|
46
|
+
'media:ratechange': { playbackRate: number }
|
|
47
|
+
|
|
48
|
+
// Loading events
|
|
49
|
+
'media:loadedmetadata': { src: string }
|
|
50
|
+
'media:progress': { buffered: TimeRanges }
|
|
51
|
+
'media:suspend': {}
|
|
52
|
+
'media:abort': {}
|
|
53
|
+
'media:error': { error: Error }
|
|
54
|
+
'media:stalled': {}
|
|
55
|
+
'media:waiting': {}
|
|
56
|
+
|
|
57
|
+
// User interaction events
|
|
58
|
+
'user:click': { x: number, y: number, element: string }
|
|
59
|
+
'user:hover': { element: string }
|
|
60
|
+
'user:focus': { element: string }
|
|
61
|
+
'user:keyboard': { key: string, code: string, altKey: boolean, ctrlKey: boolean, shiftKey: boolean }
|
|
62
|
+
'user:gesture': { type: string, data: any }
|
|
63
|
+
|
|
64
|
+
// System events
|
|
65
|
+
'system:ready': {}
|
|
66
|
+
'system:resize': { width: number, height: number }
|
|
67
|
+
'system:fullscreen': { isFullscreen: boolean }
|
|
68
|
+
'system:pip': { isPictureInPicture: boolean }
|
|
69
|
+
'system:visibility': { isVisible: boolean }
|
|
70
|
+
|
|
71
|
+
// Plugin events
|
|
72
|
+
'plugin:loaded': { name: string }
|
|
73
|
+
'plugin:enabled': { name: string }
|
|
74
|
+
'plugin:disabled': { name: string }
|
|
75
|
+
'plugin:error': { name: string, error: Error }
|
|
76
|
+
|
|
77
|
+
// Performance events
|
|
78
|
+
'performance:fps': { fps: number }
|
|
79
|
+
'performance:memory': { used: number, total: number }
|
|
80
|
+
'performance:load': { loadTime: number }
|
|
81
|
+
}
|
|
82
|
+
|
|
83
|
+
// Event bus implementation
|
|
84
|
+
export class EventBus {
|
|
85
|
+
private listeners = new Map<string, Array<{
|
|
86
|
+
handler: EventHandler
|
|
87
|
+
options: EventOptions
|
|
88
|
+
id: string
|
|
89
|
+
}>>()
|
|
90
|
+
|
|
91
|
+
private eventQueue: MediaPlayerEvent[] = []
|
|
92
|
+
private isProcessing = false
|
|
93
|
+
private middlewares: Array<(event: MediaPlayerEvent) => MediaPlayerEvent | null> = []
|
|
94
|
+
private eventHistory: MediaPlayerEvent[] = []
|
|
95
|
+
private maxHistorySize = 1000
|
|
96
|
+
|
|
97
|
+
// Subscribe to events
|
|
98
|
+
on<K extends keyof MediaEvents>(
|
|
99
|
+
type: K,
|
|
100
|
+
handler: EventHandler<MediaEvents[K]>,
|
|
101
|
+
options: EventOptions = {}
|
|
102
|
+
): EventUnsubscriber {
|
|
103
|
+
return this.addEventListener(type, handler as EventHandler, options)
|
|
104
|
+
}
|
|
105
|
+
|
|
106
|
+
// Subscribe to events (one-time)
|
|
107
|
+
once<K extends keyof MediaEvents>(
|
|
108
|
+
type: K,
|
|
109
|
+
handler: EventHandler<MediaEvents[K]>,
|
|
110
|
+
options: EventOptions = {}
|
|
111
|
+
): EventUnsubscriber {
|
|
112
|
+
return this.addEventListener(type, handler as EventHandler, { ...options, once: true })
|
|
113
|
+
}
|
|
114
|
+
|
|
115
|
+
// Subscribe to events with wildcard support
|
|
116
|
+
addEventListener(
|
|
117
|
+
type: string,
|
|
118
|
+
handler: EventHandler,
|
|
119
|
+
options: EventOptions = {}
|
|
120
|
+
): EventUnsubscriber {
|
|
121
|
+
const id = this.generateId()
|
|
122
|
+
const listener = { handler, options, id }
|
|
123
|
+
|
|
124
|
+
if (!this.listeners.has(type)) {
|
|
125
|
+
this.listeners.set(type, [])
|
|
126
|
+
}
|
|
127
|
+
|
|
128
|
+
const listeners = this.listeners.get(type)!
|
|
129
|
+
|
|
130
|
+
// Insert based on priority
|
|
131
|
+
const priority = options.priority || 'normal'
|
|
132
|
+
const priorityValue = { high: 2, normal: 1, low: 0 }[priority]
|
|
133
|
+
|
|
134
|
+
let insertIndex = listeners.length
|
|
135
|
+
for (let i = 0; i < listeners.length; i++) {
|
|
136
|
+
const listener = listeners[i]
|
|
137
|
+
if (!listener) continue
|
|
138
|
+
const listenerPriority = listener.options.priority || 'normal'
|
|
139
|
+
if (priorityValue > { high: 2, normal: 1, low: 0 }[listenerPriority]) {
|
|
140
|
+
insertIndex = i
|
|
141
|
+
break
|
|
142
|
+
}
|
|
143
|
+
}
|
|
144
|
+
|
|
145
|
+
listeners.splice(insertIndex, 0, listener)
|
|
146
|
+
|
|
147
|
+
// Return unsubscriber
|
|
148
|
+
return () => {
|
|
149
|
+
const index = listeners.findIndex(l => l.id === id)
|
|
150
|
+
if (index !== -1) {
|
|
151
|
+
listeners.splice(index, 1)
|
|
152
|
+
}
|
|
153
|
+
if (listeners.length === 0) {
|
|
154
|
+
this.listeners.delete(type)
|
|
155
|
+
}
|
|
156
|
+
}
|
|
157
|
+
}
|
|
158
|
+
|
|
159
|
+
// Remove event listener
|
|
160
|
+
removeEventListener(type: string, handler?: EventHandler): void {
|
|
161
|
+
const listeners = this.listeners.get(type)
|
|
162
|
+
if (!listeners) return
|
|
163
|
+
|
|
164
|
+
if (handler) {
|
|
165
|
+
const index = listeners.findIndex(l => l.handler === handler)
|
|
166
|
+
if (index !== -1) {
|
|
167
|
+
listeners.splice(index, 1)
|
|
168
|
+
}
|
|
169
|
+
} else {
|
|
170
|
+
this.listeners.delete(type)
|
|
171
|
+
}
|
|
172
|
+
|
|
173
|
+
if (listeners && listeners.length === 0) {
|
|
174
|
+
this.listeners.delete(type)
|
|
175
|
+
}
|
|
176
|
+
}
|
|
177
|
+
|
|
178
|
+
// Emit events
|
|
179
|
+
emit<K extends keyof MediaEvents>(
|
|
180
|
+
type: K,
|
|
181
|
+
detail?: MediaEvents[K],
|
|
182
|
+
options?: Partial<MediaPlayerEvent>
|
|
183
|
+
): boolean {
|
|
184
|
+
const event: MediaPlayerEvent = {
|
|
185
|
+
type,
|
|
186
|
+
timestamp: Date.now(),
|
|
187
|
+
detail,
|
|
188
|
+
bubbles: true,
|
|
189
|
+
cancelable: true,
|
|
190
|
+
defaultPrevented: false,
|
|
191
|
+
...options
|
|
192
|
+
}
|
|
193
|
+
|
|
194
|
+
return this.dispatchEvent(event)
|
|
195
|
+
}
|
|
196
|
+
|
|
197
|
+
// Dispatch event
|
|
198
|
+
dispatchEvent(event: MediaPlayerEvent): boolean {
|
|
199
|
+
// Apply middlewares
|
|
200
|
+
let processedEvent: MediaPlayerEvent | null = event
|
|
201
|
+
for (const middleware of this.middlewares) {
|
|
202
|
+
processedEvent = middleware(processedEvent)
|
|
203
|
+
if (!processedEvent) {
|
|
204
|
+
return false // Event was cancelled by middleware
|
|
205
|
+
}
|
|
206
|
+
}
|
|
207
|
+
|
|
208
|
+
// Add to history
|
|
209
|
+
this.addToHistory(processedEvent)
|
|
210
|
+
|
|
211
|
+
// Queue event for processing
|
|
212
|
+
this.eventQueue.push(processedEvent)
|
|
213
|
+
|
|
214
|
+
if (!this.isProcessing) {
|
|
215
|
+
this.processEventQueue()
|
|
216
|
+
}
|
|
217
|
+
|
|
218
|
+
return !processedEvent.defaultPrevented
|
|
219
|
+
}
|
|
220
|
+
|
|
221
|
+
// Process event queue with React 19 concurrent scheduling
|
|
222
|
+
private processEventQueue(): void {
|
|
223
|
+
if (this.isProcessing) return
|
|
224
|
+
|
|
225
|
+
this.isProcessing = true
|
|
226
|
+
|
|
227
|
+
// Use scheduler for non-blocking event processing
|
|
228
|
+
const schedule = (typeof window !== 'undefined' && 'scheduler' in window)
|
|
229
|
+
? (window as any).scheduler.postTask
|
|
230
|
+
: (cb: () => void) => setTimeout(cb, 0)
|
|
231
|
+
|
|
232
|
+
const processNext = () => {
|
|
233
|
+
if (this.eventQueue.length === 0) {
|
|
234
|
+
this.isProcessing = false
|
|
235
|
+
return
|
|
236
|
+
}
|
|
237
|
+
|
|
238
|
+
const batchSize = Math.min(this.eventQueue.length, 5) // Process max 5 events per frame
|
|
239
|
+
const events = this.eventQueue.splice(0, batchSize)
|
|
240
|
+
|
|
241
|
+
// Process events in parallel using Promise.all
|
|
242
|
+
Promise.all(events.map(event => this.processEvent(event).catch(console.error)))
|
|
243
|
+
.then(() => {
|
|
244
|
+
// Schedule next batch in next frame
|
|
245
|
+
schedule(processNext)
|
|
246
|
+
})
|
|
247
|
+
.catch(() => {
|
|
248
|
+
this.isProcessing = false
|
|
249
|
+
})
|
|
250
|
+
}
|
|
251
|
+
|
|
252
|
+
schedule(processNext)
|
|
253
|
+
}
|
|
254
|
+
|
|
255
|
+
// Process individual event
|
|
256
|
+
private async processEvent(event: MediaPlayerEvent): Promise<void> {
|
|
257
|
+
const { type } = event
|
|
258
|
+
|
|
259
|
+
// Get exact matches
|
|
260
|
+
const exactListeners = this.listeners.get(type) || []
|
|
261
|
+
|
|
262
|
+
// Get wildcard matches
|
|
263
|
+
const wildcardListeners: typeof exactListeners = []
|
|
264
|
+
for (const [pattern, listeners] of this.listeners.entries()) {
|
|
265
|
+
if (pattern.includes('*') && this.matchPattern(type, pattern)) {
|
|
266
|
+
wildcardListeners.push(...listeners)
|
|
267
|
+
}
|
|
268
|
+
}
|
|
269
|
+
|
|
270
|
+
// Combine and sort by priority
|
|
271
|
+
const allListeners = [...exactListeners, ...wildcardListeners]
|
|
272
|
+
.sort((a, b) => {
|
|
273
|
+
const priorityA = { high: 2, normal: 1, low: 0 }[a.options.priority || 'normal']
|
|
274
|
+
const priorityB = { high: 2, normal: 1, low: 0 }[b.options.priority || 'normal']
|
|
275
|
+
return priorityB - priorityA
|
|
276
|
+
})
|
|
277
|
+
|
|
278
|
+
// Execute listeners
|
|
279
|
+
const listenersToRemove: string[] = []
|
|
280
|
+
|
|
281
|
+
for (const listener of allListeners) {
|
|
282
|
+
// Apply filter if present
|
|
283
|
+
if (listener.options.filter && !listener.options.filter(event)) {
|
|
284
|
+
continue
|
|
285
|
+
}
|
|
286
|
+
|
|
287
|
+
try {
|
|
288
|
+
// Execute handler
|
|
289
|
+
await Promise.resolve(listener.handler(event as any))
|
|
290
|
+
|
|
291
|
+
// Mark for removal if once
|
|
292
|
+
if (listener.options.once) {
|
|
293
|
+
listenersToRemove.push(listener.id)
|
|
294
|
+
}
|
|
295
|
+
|
|
296
|
+
// Stop propagation if event was cancelled
|
|
297
|
+
if (event.defaultPrevented && !event.bubbles) {
|
|
298
|
+
break
|
|
299
|
+
}
|
|
300
|
+
} catch (error) {
|
|
301
|
+
console.error(`Error in event handler for ${type}:`, error)
|
|
302
|
+
|
|
303
|
+
// Log error instead
|
|
304
|
+
console.error(`Event handler error for ${type}:`, error)
|
|
305
|
+
}
|
|
306
|
+
}
|
|
307
|
+
|
|
308
|
+
// Remove one-time listeners
|
|
309
|
+
for (const id of listenersToRemove) {
|
|
310
|
+
for (const [eventType, listeners] of this.listeners.entries()) {
|
|
311
|
+
const index = listeners.findIndex(l => l.id === id)
|
|
312
|
+
if (index !== -1) {
|
|
313
|
+
listeners.splice(index, 1)
|
|
314
|
+
if (listeners.length === 0) {
|
|
315
|
+
this.listeners.delete(eventType)
|
|
316
|
+
}
|
|
317
|
+
break
|
|
318
|
+
}
|
|
319
|
+
}
|
|
320
|
+
}
|
|
321
|
+
}
|
|
322
|
+
|
|
323
|
+
// Add middleware
|
|
324
|
+
use(middleware: (event: MediaPlayerEvent) => MediaPlayerEvent | null): () => void {
|
|
325
|
+
this.middlewares.push(middleware)
|
|
326
|
+
return () => {
|
|
327
|
+
const index = this.middlewares.indexOf(middleware)
|
|
328
|
+
if (index !== -1) {
|
|
329
|
+
this.middlewares.splice(index, 1)
|
|
330
|
+
}
|
|
331
|
+
}
|
|
332
|
+
}
|
|
333
|
+
|
|
334
|
+
// Event history management
|
|
335
|
+
private addToHistory(event: MediaPlayerEvent): void {
|
|
336
|
+
this.eventHistory.push(event)
|
|
337
|
+
if (this.eventHistory.length > this.maxHistorySize) {
|
|
338
|
+
this.eventHistory.shift()
|
|
339
|
+
}
|
|
340
|
+
}
|
|
341
|
+
|
|
342
|
+
// Get event history
|
|
343
|
+
getHistory(filter?: (event: MediaPlayerEvent) => boolean): MediaPlayerEvent[] {
|
|
344
|
+
return filter ? this.eventHistory.filter(filter) : [...this.eventHistory]
|
|
345
|
+
}
|
|
346
|
+
|
|
347
|
+
// Clear event history
|
|
348
|
+
clearHistory(): void {
|
|
349
|
+
this.eventHistory = []
|
|
350
|
+
}
|
|
351
|
+
|
|
352
|
+
// Pattern matching for wildcards
|
|
353
|
+
private matchPattern(eventType: string, pattern: string): boolean {
|
|
354
|
+
const regex = new RegExp(
|
|
355
|
+
'^' + pattern.replace(/\*/g, '.*').replace(/\?/g, '.') + '$'
|
|
356
|
+
)
|
|
357
|
+
return regex.test(eventType)
|
|
358
|
+
}
|
|
359
|
+
|
|
360
|
+
// Generate unique ID
|
|
361
|
+
private generateId(): string {
|
|
362
|
+
return `event_${Date.now()}_${Math.random().toString(36).substr(2, 9)}`
|
|
363
|
+
}
|
|
364
|
+
|
|
365
|
+
// Get listener count
|
|
366
|
+
getListenerCount(type?: string): number {
|
|
367
|
+
if (type) {
|
|
368
|
+
return this.listeners.get(type)?.length || 0
|
|
369
|
+
}
|
|
370
|
+
return Array.from(this.listeners.values()).reduce((sum, listeners) => sum + listeners.length, 0)
|
|
371
|
+
}
|
|
372
|
+
|
|
373
|
+
// Get all event types
|
|
374
|
+
getEventTypes(): string[] {
|
|
375
|
+
return Array.from(this.listeners.keys())
|
|
376
|
+
}
|
|
377
|
+
|
|
378
|
+
// Clear all listeners
|
|
379
|
+
removeAllListeners(type?: string): void {
|
|
380
|
+
if (type) {
|
|
381
|
+
this.listeners.delete(type)
|
|
382
|
+
} else {
|
|
383
|
+
this.listeners.clear()
|
|
384
|
+
}
|
|
385
|
+
}
|
|
386
|
+
|
|
387
|
+
// Destroy event bus
|
|
388
|
+
destroy(): void {
|
|
389
|
+
this.listeners.clear()
|
|
390
|
+
this.eventQueue = []
|
|
391
|
+
this.middlewares = []
|
|
392
|
+
this.eventHistory = []
|
|
393
|
+
this.isProcessing = false
|
|
394
|
+
}
|
|
395
|
+
}
|
|
396
|
+
|
|
397
|
+
// Default event bus instance
|
|
398
|
+
export const defaultEventBus = new EventBus()
|
|
399
|
+
|
|
400
|
+
// Event delegation helper
|
|
401
|
+
export class EventDelegator {
|
|
402
|
+
private eventBus: EventBus
|
|
403
|
+
private element: HTMLElement
|
|
404
|
+
private delegatedEvents = new Set<string>()
|
|
405
|
+
|
|
406
|
+
constructor(eventBus: EventBus, element: HTMLElement) {
|
|
407
|
+
this.eventBus = eventBus
|
|
408
|
+
this.element = element
|
|
409
|
+
}
|
|
410
|
+
|
|
411
|
+
// Delegate DOM events to event bus
|
|
412
|
+
delegate(domEvent: string, mediaEvent?: string): void {
|
|
413
|
+
if (this.delegatedEvents.has(domEvent)) return
|
|
414
|
+
|
|
415
|
+
const handler = (e: Event) => {
|
|
416
|
+
this.eventBus.emit(mediaEvent || `dom:${domEvent}` as any, {
|
|
417
|
+
originalEvent: e,
|
|
418
|
+
target: (e.target as HTMLElement)?.tagName.toLowerCase(),
|
|
419
|
+
currentTarget: (e.currentTarget as HTMLElement)?.tagName.toLowerCase()
|
|
420
|
+
})
|
|
421
|
+
}
|
|
422
|
+
|
|
423
|
+
this.element.addEventListener(domEvent, handler, { passive: true })
|
|
424
|
+
this.delegatedEvents.add(domEvent)
|
|
425
|
+
}
|
|
426
|
+
|
|
427
|
+
// Setup common delegations
|
|
428
|
+
setupCommonDelegations(): void {
|
|
429
|
+
this.delegate('click', 'user:click')
|
|
430
|
+
this.delegate('mouseenter', 'user:hover')
|
|
431
|
+
this.delegate('mouseleave', 'user:hover')
|
|
432
|
+
this.delegate('focus', 'user:focus')
|
|
433
|
+
this.delegate('blur', 'user:focus')
|
|
434
|
+
this.delegate('keydown', 'user:keyboard')
|
|
435
|
+
this.delegate('keyup', 'user:keyboard')
|
|
436
|
+
}
|
|
437
|
+
|
|
438
|
+
destroy(): void {
|
|
439
|
+
this.delegatedEvents.clear()
|
|
440
|
+
}
|
|
441
|
+
}
|
|
442
|
+
|