@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,327 @@
|
|
|
1
|
+
import { EventBus } from '../events/event-system'
|
|
2
|
+
import type {
|
|
3
|
+
Plugin,
|
|
4
|
+
PluginFactory,
|
|
5
|
+
PluginConfig,
|
|
6
|
+
PluginRegistry as IPluginRegistry,
|
|
7
|
+
PluginContext,
|
|
8
|
+
PluginLogger,
|
|
9
|
+
PluginEvents,
|
|
10
|
+
PluginPriority
|
|
11
|
+
} from './types'
|
|
12
|
+
import {
|
|
13
|
+
PluginError,
|
|
14
|
+
PluginDependencyError,
|
|
15
|
+
PluginConflictError
|
|
16
|
+
} from './types'
|
|
17
|
+
|
|
18
|
+
// Plugin registry implementation
|
|
19
|
+
export class PluginRegistry implements IPluginRegistry {
|
|
20
|
+
private plugins = new Map<string, Plugin>()
|
|
21
|
+
private pluginConfigs = new Map<string, PluginConfig>()
|
|
22
|
+
private enabledPlugins = new Set<string>()
|
|
23
|
+
private eventBus = new EventBus()
|
|
24
|
+
private logger: PluginLogger
|
|
25
|
+
|
|
26
|
+
constructor(logger: PluginLogger) {
|
|
27
|
+
this.logger = logger
|
|
28
|
+
}
|
|
29
|
+
|
|
30
|
+
// Register a plugin factory
|
|
31
|
+
async register(factory: PluginFactory, config: PluginConfig = {}): Promise<void> {
|
|
32
|
+
try {
|
|
33
|
+
const plugin = factory(config)
|
|
34
|
+
const { name, dependencies = [], conflicts = [] } = plugin.metadata
|
|
35
|
+
|
|
36
|
+
// Check if plugin already exists
|
|
37
|
+
if (this.plugins.has(name)) {
|
|
38
|
+
throw new PluginError(name, 'initialize', 'Plugin already registered')
|
|
39
|
+
}
|
|
40
|
+
|
|
41
|
+
// Validate dependencies
|
|
42
|
+
const missingDependencies = dependencies.filter(dep => !this.plugins.has(dep))
|
|
43
|
+
if (missingDependencies.length > 0) {
|
|
44
|
+
throw new PluginDependencyError(name, missingDependencies)
|
|
45
|
+
}
|
|
46
|
+
|
|
47
|
+
// Check for conflicts with enabled plugins
|
|
48
|
+
const activeConflicts = conflicts.filter(conflict => this.enabledPlugins.has(conflict))
|
|
49
|
+
if (activeConflicts.length > 0) {
|
|
50
|
+
throw new PluginConflictError(name, activeConflicts)
|
|
51
|
+
}
|
|
52
|
+
|
|
53
|
+
// Store plugin and configuration
|
|
54
|
+
this.plugins.set(name, plugin)
|
|
55
|
+
this.pluginConfigs.set(name, config)
|
|
56
|
+
|
|
57
|
+
this.logger.info(`Plugin '${name}' registered successfully`)
|
|
58
|
+
;(this.eventBus as any).emit('plugin:registered', { name, plugin })
|
|
59
|
+
|
|
60
|
+
} catch (error) {
|
|
61
|
+
const pluginName = factory({}).metadata.name
|
|
62
|
+
this.logger.error(`Failed to register plugin '${pluginName}'`, error)
|
|
63
|
+
;(this.eventBus as any).emit('plugin:error', { name: pluginName, error: error as Error })
|
|
64
|
+
throw error
|
|
65
|
+
}
|
|
66
|
+
}
|
|
67
|
+
|
|
68
|
+
// Unregister a plugin
|
|
69
|
+
async unregister(name: string): Promise<void> {
|
|
70
|
+
const plugin = this.plugins.get(name)
|
|
71
|
+
if (!plugin) {
|
|
72
|
+
throw new PluginError(name, 'destroy', 'Plugin not found')
|
|
73
|
+
}
|
|
74
|
+
|
|
75
|
+
try {
|
|
76
|
+
// Disable plugin if enabled
|
|
77
|
+
if (this.enabledPlugins.has(name)) {
|
|
78
|
+
await this.disable(name)
|
|
79
|
+
}
|
|
80
|
+
|
|
81
|
+
// Remove from registry
|
|
82
|
+
this.plugins.delete(name)
|
|
83
|
+
this.pluginConfigs.delete(name)
|
|
84
|
+
|
|
85
|
+
this.logger.info(`Plugin '${name}' unregistered successfully`)
|
|
86
|
+
} catch (error) {
|
|
87
|
+
this.logger.error(`Failed to unregister plugin '${name}'`, error)
|
|
88
|
+
throw error
|
|
89
|
+
}
|
|
90
|
+
}
|
|
91
|
+
|
|
92
|
+
// Get a plugin by name
|
|
93
|
+
get(name: string): Plugin | undefined {
|
|
94
|
+
return this.plugins.get(name)
|
|
95
|
+
}
|
|
96
|
+
|
|
97
|
+
// Get all plugins sorted by priority
|
|
98
|
+
getAll(): Plugin[] {
|
|
99
|
+
return Array.from(this.plugins.values()).sort(this.sortByPriority)
|
|
100
|
+
}
|
|
101
|
+
|
|
102
|
+
// Check if plugin is enabled
|
|
103
|
+
isEnabled(name: string): boolean {
|
|
104
|
+
return this.enabledPlugins.has(name)
|
|
105
|
+
}
|
|
106
|
+
|
|
107
|
+
// Enable a plugin
|
|
108
|
+
async enable(name: string): Promise<void> {
|
|
109
|
+
const plugin = this.plugins.get(name)
|
|
110
|
+
if (!plugin) {
|
|
111
|
+
throw new PluginError(name, 'activate', 'Plugin not found')
|
|
112
|
+
}
|
|
113
|
+
|
|
114
|
+
if (this.enabledPlugins.has(name)) {
|
|
115
|
+
this.logger.warn(`Plugin '${name}' is already enabled`)
|
|
116
|
+
return
|
|
117
|
+
}
|
|
118
|
+
|
|
119
|
+
try {
|
|
120
|
+
const context = this.createPluginContext(name)
|
|
121
|
+
const config = this.pluginConfigs.get(name)
|
|
122
|
+
|
|
123
|
+
// Initialize plugin
|
|
124
|
+
await plugin.initialize(context, config)
|
|
125
|
+
|
|
126
|
+
// Activate plugin
|
|
127
|
+
await plugin.activate(context)
|
|
128
|
+
|
|
129
|
+
this.enabledPlugins.add(name)
|
|
130
|
+
this.logger.info(`Plugin '${name}' enabled successfully`)
|
|
131
|
+
;(this.eventBus as any).emit('plugin:enabled', { name, plugin })
|
|
132
|
+
|
|
133
|
+
} catch (error) {
|
|
134
|
+
this.logger.error(`Failed to enable plugin '${name}'`, error)
|
|
135
|
+
;(this.eventBus as any).emit('plugin:error', { name, error: error as Error })
|
|
136
|
+
throw error
|
|
137
|
+
}
|
|
138
|
+
}
|
|
139
|
+
|
|
140
|
+
// Disable a plugin
|
|
141
|
+
async disable(name: string): Promise<void> {
|
|
142
|
+
const plugin = this.plugins.get(name)
|
|
143
|
+
if (!plugin) {
|
|
144
|
+
throw new PluginError(name, 'deactivate', 'Plugin not found')
|
|
145
|
+
}
|
|
146
|
+
|
|
147
|
+
if (!this.enabledPlugins.has(name)) {
|
|
148
|
+
this.logger.warn(`Plugin '${name}' is already disabled`)
|
|
149
|
+
return
|
|
150
|
+
}
|
|
151
|
+
|
|
152
|
+
try {
|
|
153
|
+
const context = this.createPluginContext(name)
|
|
154
|
+
|
|
155
|
+
// Deactivate plugin
|
|
156
|
+
await plugin.deactivate(context)
|
|
157
|
+
|
|
158
|
+
// Destroy plugin resources
|
|
159
|
+
await plugin.destroy(context)
|
|
160
|
+
|
|
161
|
+
this.enabledPlugins.delete(name)
|
|
162
|
+
this.logger.info(`Plugin '${name}' disabled successfully`)
|
|
163
|
+
;(this.eventBus as any).emit('plugin:disabled', { name, plugin })
|
|
164
|
+
|
|
165
|
+
} catch (error) {
|
|
166
|
+
this.logger.error(`Failed to disable plugin '${name}'`, error)
|
|
167
|
+
;(this.eventBus as any).emit('plugin:error', { name, error: error as Error })
|
|
168
|
+
throw error
|
|
169
|
+
}
|
|
170
|
+
}
|
|
171
|
+
|
|
172
|
+
// Configure a plugin
|
|
173
|
+
async configure(name: string, config: PluginConfig): Promise<void> {
|
|
174
|
+
const plugin = this.plugins.get(name)
|
|
175
|
+
if (!plugin) {
|
|
176
|
+
throw new PluginError(name, 'initialize', 'Plugin not found')
|
|
177
|
+
}
|
|
178
|
+
|
|
179
|
+
try {
|
|
180
|
+
// Update stored configuration
|
|
181
|
+
this.pluginConfigs.set(name, { ...this.pluginConfigs.get(name), ...config })
|
|
182
|
+
|
|
183
|
+
// If plugin has configure method, call it
|
|
184
|
+
if (plugin.configure) {
|
|
185
|
+
await plugin.configure(config)
|
|
186
|
+
}
|
|
187
|
+
|
|
188
|
+
this.logger.info(`Plugin '${name}' configured successfully`)
|
|
189
|
+
;(this.eventBus as any).emit('plugin:configured', { name, config })
|
|
190
|
+
|
|
191
|
+
} catch (error) {
|
|
192
|
+
this.logger.error(`Failed to configure plugin '${name}'`, error)
|
|
193
|
+
;(this.eventBus as any).emit('plugin:error', { name, error: error as Error })
|
|
194
|
+
throw error
|
|
195
|
+
}
|
|
196
|
+
}
|
|
197
|
+
|
|
198
|
+
// Enable multiple plugins with dependency resolution
|
|
199
|
+
async enablePlugins(names: string[]): Promise<void> {
|
|
200
|
+
const resolved = this.resolveDependencies(names)
|
|
201
|
+
|
|
202
|
+
for (const name of resolved) {
|
|
203
|
+
if (!this.enabledPlugins.has(name)) {
|
|
204
|
+
await this.enable(name)
|
|
205
|
+
}
|
|
206
|
+
}
|
|
207
|
+
}
|
|
208
|
+
|
|
209
|
+
// Disable multiple plugins
|
|
210
|
+
async disablePlugins(names: string[]): Promise<void> {
|
|
211
|
+
// Disable in reverse order to handle dependencies
|
|
212
|
+
const reversed = [...names].reverse()
|
|
213
|
+
|
|
214
|
+
for (const name of reversed) {
|
|
215
|
+
if (this.enabledPlugins.has(name)) {
|
|
216
|
+
await this.disable(name)
|
|
217
|
+
}
|
|
218
|
+
}
|
|
219
|
+
}
|
|
220
|
+
|
|
221
|
+
// Get enabled plugins
|
|
222
|
+
getEnabledPlugins(): Plugin[] {
|
|
223
|
+
return Array.from(this.enabledPlugins)
|
|
224
|
+
.map(name => this.plugins.get(name)!)
|
|
225
|
+
.filter(Boolean)
|
|
226
|
+
.sort(this.sortByPriority)
|
|
227
|
+
}
|
|
228
|
+
|
|
229
|
+
// Health check for all enabled plugins
|
|
230
|
+
async healthCheck(): Promise<{ name: string; healthy: boolean; error?: Error }[]> {
|
|
231
|
+
const results = []
|
|
232
|
+
|
|
233
|
+
for (const name of this.enabledPlugins) {
|
|
234
|
+
const plugin = this.plugins.get(name)!
|
|
235
|
+
try {
|
|
236
|
+
const healthy = plugin.healthCheck ? await plugin.healthCheck() : true
|
|
237
|
+
results.push({ name, healthy })
|
|
238
|
+
} catch (error) {
|
|
239
|
+
results.push({ name, healthy: false, error: error as Error })
|
|
240
|
+
}
|
|
241
|
+
}
|
|
242
|
+
|
|
243
|
+
return results
|
|
244
|
+
}
|
|
245
|
+
|
|
246
|
+
// Event handling
|
|
247
|
+
on<K extends keyof PluginEvents>(
|
|
248
|
+
event: K,
|
|
249
|
+
listener: (data: PluginEvents[K]) => void
|
|
250
|
+
): () => void {
|
|
251
|
+
(this.eventBus as any).on(event, listener)
|
|
252
|
+
return () => (this.eventBus as any).off(event, listener)
|
|
253
|
+
}
|
|
254
|
+
|
|
255
|
+
// Create plugin context (will be implemented when we have the full context)
|
|
256
|
+
private createPluginContext(pluginName: string): PluginContext {
|
|
257
|
+
// This will be implemented when we integrate with the media player
|
|
258
|
+
// For now, return a minimal context
|
|
259
|
+
return {
|
|
260
|
+
state: {} as any,
|
|
261
|
+
controls: {} as any,
|
|
262
|
+
plugins: this,
|
|
263
|
+
emit: (event: string, data?: any) => (this.eventBus as any).emit(event, data),
|
|
264
|
+
on: (event: string, handler: (data: any) => void) => {
|
|
265
|
+
(this.eventBus as any).on(event, handler)
|
|
266
|
+
return () => (this.eventBus as any).off(event, handler)
|
|
267
|
+
},
|
|
268
|
+
element: null,
|
|
269
|
+
logger: this.createPluginLogger(pluginName)
|
|
270
|
+
}
|
|
271
|
+
}
|
|
272
|
+
|
|
273
|
+
// Create plugin-specific logger
|
|
274
|
+
private createPluginLogger(pluginName: string): PluginLogger {
|
|
275
|
+
return {
|
|
276
|
+
info: (message: string, data?: any) => this.logger.info(`[${pluginName}] ${message}`, data),
|
|
277
|
+
warn: (message: string, data?: any) => this.logger.warn(`[${pluginName}] ${message}`, data),
|
|
278
|
+
error: (message: string, data?: any) => this.logger.error(`[${pluginName}] ${message}`, data),
|
|
279
|
+
debug: (message: string, data?: any) => this.logger.debug(`[${pluginName}] ${message}`, data)
|
|
280
|
+
}
|
|
281
|
+
}
|
|
282
|
+
|
|
283
|
+
// Resolve plugin dependencies
|
|
284
|
+
private resolveDependencies(names: string[]): string[] {
|
|
285
|
+
const resolved: string[] = []
|
|
286
|
+
const visiting = new Set<string>()
|
|
287
|
+
|
|
288
|
+
const visit = (name: string) => {
|
|
289
|
+
if (resolved.includes(name)) return
|
|
290
|
+
if (visiting.has(name)) {
|
|
291
|
+
throw new PluginError(name, 'initialize', 'Circular dependency detected')
|
|
292
|
+
}
|
|
293
|
+
|
|
294
|
+
visiting.add(name)
|
|
295
|
+
|
|
296
|
+
const plugin = this.plugins.get(name)
|
|
297
|
+
if (!plugin) {
|
|
298
|
+
throw new PluginError(name, 'initialize', 'Plugin not found')
|
|
299
|
+
}
|
|
300
|
+
|
|
301
|
+
// Visit dependencies first
|
|
302
|
+
for (const dep of plugin.metadata.dependencies || []) {
|
|
303
|
+
visit(dep)
|
|
304
|
+
}
|
|
305
|
+
|
|
306
|
+
visiting.delete(name)
|
|
307
|
+
resolved.push(name)
|
|
308
|
+
}
|
|
309
|
+
|
|
310
|
+
for (const name of names) {
|
|
311
|
+
visit(name)
|
|
312
|
+
}
|
|
313
|
+
|
|
314
|
+
return resolved
|
|
315
|
+
}
|
|
316
|
+
|
|
317
|
+
// Sort plugins by priority
|
|
318
|
+
private sortByPriority(a: Plugin, b: Plugin): number {
|
|
319
|
+
const priorityOrder: Record<PluginPriority, number> = {
|
|
320
|
+
high: 3,
|
|
321
|
+
medium: 2,
|
|
322
|
+
low: 1
|
|
323
|
+
}
|
|
324
|
+
|
|
325
|
+
return priorityOrder[b.metadata.priority] - priorityOrder[a.metadata.priority]
|
|
326
|
+
}
|
|
327
|
+
}
|
|
@@ -0,0 +1,159 @@
|
|
|
1
|
+
// TODO: Import proper types when integrated
|
|
2
|
+
export interface MediaState {
|
|
3
|
+
isPlaying: boolean
|
|
4
|
+
currentTime: number
|
|
5
|
+
duration: number
|
|
6
|
+
volume: number
|
|
7
|
+
isMuted: boolean
|
|
8
|
+
}
|
|
9
|
+
|
|
10
|
+
export interface MediaPlayerControls {
|
|
11
|
+
play(): void
|
|
12
|
+
pause(): void
|
|
13
|
+
seek(time: number): void
|
|
14
|
+
setVolume(volume: number): void
|
|
15
|
+
}
|
|
16
|
+
|
|
17
|
+
// Plugin lifecycle phases
|
|
18
|
+
export type PluginPhase = 'initialize' | 'activate' | 'deactivate' | 'destroy'
|
|
19
|
+
|
|
20
|
+
// Plugin categories for organization
|
|
21
|
+
export type PluginCategory =
|
|
22
|
+
| 'controls'
|
|
23
|
+
| 'analytics'
|
|
24
|
+
| 'streaming'
|
|
25
|
+
| 'subtitle'
|
|
26
|
+
| 'quality'
|
|
27
|
+
| 'ui'
|
|
28
|
+
| 'accessibility'
|
|
29
|
+
| 'performance'
|
|
30
|
+
|
|
31
|
+
// Plugin priority for execution order
|
|
32
|
+
export type PluginPriority = 'high' | 'medium' | 'low'
|
|
33
|
+
|
|
34
|
+
// Plugin configuration interface
|
|
35
|
+
export interface PluginConfig {
|
|
36
|
+
[key: string]: any
|
|
37
|
+
}
|
|
38
|
+
|
|
39
|
+
// Plugin context provided to each plugin
|
|
40
|
+
export interface PluginContext {
|
|
41
|
+
// Core media player state and controls
|
|
42
|
+
state: MediaState
|
|
43
|
+
controls: MediaPlayerControls
|
|
44
|
+
|
|
45
|
+
// Plugin management
|
|
46
|
+
plugins: PluginRegistry
|
|
47
|
+
|
|
48
|
+
// Event system
|
|
49
|
+
emit: (event: string, data?: any) => void
|
|
50
|
+
on: (event: string, handler: (data: any) => void) => () => void
|
|
51
|
+
|
|
52
|
+
// Utilities
|
|
53
|
+
element: HTMLElement | null
|
|
54
|
+
logger: PluginLogger
|
|
55
|
+
}
|
|
56
|
+
|
|
57
|
+
// Plugin metadata
|
|
58
|
+
export interface PluginMetadata {
|
|
59
|
+
name: string
|
|
60
|
+
version: string
|
|
61
|
+
description: string
|
|
62
|
+
author?: string
|
|
63
|
+
category: PluginCategory
|
|
64
|
+
priority: PluginPriority
|
|
65
|
+
dependencies?: string[]
|
|
66
|
+
conflicts?: string[]
|
|
67
|
+
}
|
|
68
|
+
|
|
69
|
+
// Plugin interface that all plugins must implement
|
|
70
|
+
export interface Plugin {
|
|
71
|
+
metadata: PluginMetadata
|
|
72
|
+
|
|
73
|
+
// Plugin lifecycle methods
|
|
74
|
+
initialize(context: PluginContext, config?: PluginConfig): Promise<void> | void
|
|
75
|
+
activate(context: PluginContext): Promise<void> | void
|
|
76
|
+
deactivate(context: PluginContext): Promise<void> | void
|
|
77
|
+
destroy(context: PluginContext): Promise<void> | void
|
|
78
|
+
|
|
79
|
+
// Configuration handling
|
|
80
|
+
configure?(config: PluginConfig): Promise<void> | void
|
|
81
|
+
|
|
82
|
+
// Health check for plugin status
|
|
83
|
+
healthCheck?(): Promise<boolean> | boolean
|
|
84
|
+
}
|
|
85
|
+
|
|
86
|
+
// Plugin factory function type
|
|
87
|
+
export type PluginFactory<T extends Plugin = Plugin> = (config?: PluginConfig) => T
|
|
88
|
+
|
|
89
|
+
// Plugin registry interface
|
|
90
|
+
export interface PluginRegistry {
|
|
91
|
+
register(factory: PluginFactory, config?: PluginConfig): Promise<void>
|
|
92
|
+
unregister(name: string): Promise<void>
|
|
93
|
+
get(name: string): Plugin | undefined
|
|
94
|
+
getAll(): Plugin[]
|
|
95
|
+
isEnabled(name: string): boolean
|
|
96
|
+
enable(name: string): Promise<void>
|
|
97
|
+
disable(name: string): Promise<void>
|
|
98
|
+
configure(name: string, config: PluginConfig): Promise<void>
|
|
99
|
+
}
|
|
100
|
+
|
|
101
|
+
// Plugin logger interface
|
|
102
|
+
export interface PluginLogger {
|
|
103
|
+
info(message: string, data?: any): void
|
|
104
|
+
warn(message: string, data?: any): void
|
|
105
|
+
error(message: string, data?: any): void
|
|
106
|
+
debug(message: string, data?: any): void
|
|
107
|
+
}
|
|
108
|
+
|
|
109
|
+
// Plugin event types
|
|
110
|
+
export interface PluginEvents {
|
|
111
|
+
'plugin:registered': { name: string; plugin: Plugin }
|
|
112
|
+
'plugin:enabled': { name: string; plugin: Plugin }
|
|
113
|
+
'plugin:disabled': { name: string; plugin: Plugin }
|
|
114
|
+
'plugin:error': { name: string; error: Error }
|
|
115
|
+
'plugin:configured': { name: string; config: PluginConfig }
|
|
116
|
+
}
|
|
117
|
+
|
|
118
|
+
// Plugin error types
|
|
119
|
+
export class PluginError extends Error {
|
|
120
|
+
constructor(
|
|
121
|
+
public pluginName: string,
|
|
122
|
+
public phase: PluginPhase,
|
|
123
|
+
message: string,
|
|
124
|
+
public originalError?: Error
|
|
125
|
+
) {
|
|
126
|
+
super(`Plugin '${pluginName}' failed during ${phase}: ${message}`)
|
|
127
|
+
this.name = 'PluginError'
|
|
128
|
+
}
|
|
129
|
+
}
|
|
130
|
+
|
|
131
|
+
// Plugin dependency error
|
|
132
|
+
export class PluginDependencyError extends PluginError {
|
|
133
|
+
constructor(
|
|
134
|
+
pluginName: string,
|
|
135
|
+
public missingDependencies: string[]
|
|
136
|
+
) {
|
|
137
|
+
super(
|
|
138
|
+
pluginName,
|
|
139
|
+
'initialize',
|
|
140
|
+
`Missing dependencies: ${missingDependencies.join(', ')}`
|
|
141
|
+
)
|
|
142
|
+
this.name = 'PluginDependencyError'
|
|
143
|
+
}
|
|
144
|
+
}
|
|
145
|
+
|
|
146
|
+
// Plugin conflict error
|
|
147
|
+
export class PluginConflictError extends PluginError {
|
|
148
|
+
constructor(
|
|
149
|
+
pluginName: string,
|
|
150
|
+
public conflictingPlugins: string[]
|
|
151
|
+
) {
|
|
152
|
+
super(
|
|
153
|
+
pluginName,
|
|
154
|
+
'activate',
|
|
155
|
+
`Conflicts with active plugins: ${conflictingPlugins.join(', ')}`
|
|
156
|
+
)
|
|
157
|
+
this.name = 'PluginConflictError'
|
|
158
|
+
}
|
|
159
|
+
}
|