@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.
Files changed (244) hide show
  1. package/LICENSE +21 -0
  2. package/README.md +384 -0
  3. package/dist/context/media.js +2 -0
  4. package/dist/context/media.js.map +1 -0
  5. package/dist/context/media.mjs +15 -0
  6. package/dist/context/media.mjs.map +1 -0
  7. package/dist/context/store.js +2 -0
  8. package/dist/context/store.js.map +1 -0
  9. package/dist/context/store.mjs +5 -0
  10. package/dist/context/store.mjs.map +1 -0
  11. package/dist/context-BMteAJDN.js +1140 -0
  12. package/dist/context-BMteAJDN.js.map +1 -0
  13. package/dist/context-DCJ_scmO.cjs +23 -0
  14. package/dist/context-DCJ_scmO.cjs.map +1 -0
  15. package/dist/core-events-B5W_j8yU.js +480 -0
  16. package/dist/core-events-B5W_j8yU.js.map +1 -0
  17. package/dist/core-events-CN0-Vhhq.cjs +2 -0
  18. package/dist/core-events-CN0-Vhhq.cjs.map +1 -0
  19. package/dist/core-plugins-Bq9KLany.js +696 -0
  20. package/dist/core-plugins-Bq9KLany.js.map +1 -0
  21. package/dist/core-plugins-CPDSHMiQ.cjs +2 -0
  22. package/dist/core-plugins-CPDSHMiQ.cjs.map +1 -0
  23. package/dist/core.js +37 -0
  24. package/dist/core.js.map +1 -0
  25. package/dist/core.mjs +1217 -0
  26. package/dist/core.mjs.map +1 -0
  27. package/dist/enhanced-components-DHv0MFvG.js +1073 -0
  28. package/dist/enhanced-components-DHv0MFvG.js.map +1 -0
  29. package/dist/enhanced-components-DTIObgB7.cjs +2 -0
  30. package/dist/enhanced-components-DTIObgB7.cjs.map +1 -0
  31. package/dist/hooks-C_r8wexn.cjs +4 -0
  32. package/dist/hooks-C_r8wexn.cjs.map +1 -0
  33. package/dist/hooks-Da2wVXlF.js +1630 -0
  34. package/dist/hooks-Da2wVXlF.js.map +1 -0
  35. package/dist/index.css +1 -0
  36. package/dist/index.js +112 -0
  37. package/dist/index.js.map +1 -0
  38. package/dist/index.mjs +6126 -0
  39. package/dist/index.mjs.map +1 -0
  40. package/dist/minimal-components-DSq5sQpy.js +2002 -0
  41. package/dist/minimal-components-DSq5sQpy.js.map +1 -0
  42. package/dist/minimal-components-DflWiihN.cjs +2 -0
  43. package/dist/minimal-components-DflWiihN.cjs.map +1 -0
  44. package/dist/minimal-components.css +1 -0
  45. package/dist/mona-loading.gif +0 -0
  46. package/dist/performance-monitor-CUW6f5ll.cjs +2 -0
  47. package/dist/performance-monitor-CUW6f5ll.cjs.map +1 -0
  48. package/dist/performance-monitor-rMW1RgV3.js +302 -0
  49. package/dist/performance-monitor-rMW1RgV3.js.map +1 -0
  50. package/dist/utils-BnscpYYd.js +2798 -0
  51. package/dist/utils-BnscpYYd.js.map +1 -0
  52. package/dist/utils-D_czS_0K.cjs +9 -0
  53. package/dist/utils-D_czS_0K.cjs.map +1 -0
  54. package/dist/utils.js +2 -0
  55. package/dist/utils.js.map +1 -0
  56. package/dist/utils.mjs +7 -0
  57. package/dist/utils.mjs.map +1 -0
  58. package/package.json +114 -0
  59. package/src/adapters/videojs-adapter.tsx +470 -0
  60. package/src/assets/mona-loading.gif +0 -0
  61. package/src/components/AnimateLoading.tsx +115 -0
  62. package/src/components/LoadingState.tsx +248 -0
  63. package/src/components/accessibility/keyboard-help-overlay.tsx +213 -0
  64. package/src/components/audio-player.tsx +85 -0
  65. package/src/components/basic/index.ts +37 -0
  66. package/src/components/enhanced/advanced-features.tsx +316 -0
  67. package/src/components/enhanced/debug-panel.tsx +422 -0
  68. package/src/components/enhanced/enhanced-controls.tsx +600 -0
  69. package/src/components/enhanced/enhanced-media-player.tsx +509 -0
  70. package/src/components/enhanced/error-handling.tsx +345 -0
  71. package/src/components/enhanced/index.ts +39 -0
  72. package/src/components/enhanced/media-player-enhanced.tsx +349 -0
  73. package/src/components/examples/basic-video-player.tsx +55 -0
  74. package/src/components/examples/custom-controls-example.tsx +63 -0
  75. package/src/components/examples/enhanced-controls-example.tsx +114 -0
  76. package/src/components/examples/enhanced-media-player-example.tsx +293 -0
  77. package/src/components/examples/loading-states-demo.tsx +142 -0
  78. package/src/components/examples/react-19-demo.tsx +381 -0
  79. package/src/components/examples/volume-orientation-demo.tsx +114 -0
  80. package/src/components/icon-demo.tsx +209 -0
  81. package/src/components/icons/index.tsx +166 -0
  82. package/src/components/icons/svg-icons/ArrowLeftIcon.tsx +18 -0
  83. package/src/components/icons/svg-icons/ArrowRightIcon.tsx +18 -0
  84. package/src/components/icons/svg-icons/AudioIcon.tsx +22 -0
  85. package/src/components/icons/svg-icons/BackwardIcon.tsx +12 -0
  86. package/src/components/icons/svg-icons/CameraIcon.tsx +19 -0
  87. package/src/components/icons/svg-icons/CheckIcon.tsx +19 -0
  88. package/src/components/icons/svg-icons/EnablePiPIcon.tsx +17 -0
  89. package/src/components/icons/svg-icons/ForwardIcon.tsx +12 -0
  90. package/src/components/icons/svg-icons/FullscreenEnterIcon.tsx +23 -0
  91. package/src/components/icons/svg-icons/FullscreenExitIcon.tsx +23 -0
  92. package/src/components/icons/svg-icons/LoadingIcon.tsx +32 -0
  93. package/src/components/icons/svg-icons/PauseIcon.tsx +23 -0
  94. package/src/components/icons/svg-icons/PlayIcon.tsx +21 -0
  95. package/src/components/icons/svg-icons/PlaybackSpeedIcon.tsx +23 -0
  96. package/src/components/icons/svg-icons/QualityIcon.tsx +21 -0
  97. package/src/components/icons/svg-icons/SettingsIcon.tsx +12 -0
  98. package/src/components/icons/svg-icons/SliderIcon.tsx +21 -0
  99. package/src/components/icons/svg-icons/SubtitleIcon.tsx +21 -0
  100. package/src/components/icons/svg-icons/SubtitleOffIcon.tsx +25 -0
  101. package/src/components/icons/svg-icons/UnPiPIcon.tsx +17 -0
  102. package/src/components/icons/svg-icons/VolumeMutedIcon.tsx +16 -0
  103. package/src/components/icons/svg-icons/VolumeOneIcon.tsx +22 -0
  104. package/src/components/icons/svg-icons/VolumeThreeIcon.tsx +16 -0
  105. package/src/components/icons/svg-icons/VolumeTwoIcon.tsx +16 -0
  106. package/src/components/legacy.tsx +93 -0
  107. package/src/components/media-metadata-display.tsx +100 -0
  108. package/src/components/media-player-audio.tsx +39 -0
  109. package/src/components/media-player-controls.tsx +226 -0
  110. package/src/components/media-player-error.tsx +163 -0
  111. package/src/components/media-player-fullscreen.tsx +109 -0
  112. package/src/components/media-player-hls.tsx +111 -0
  113. package/src/components/media-player-loading.tsx +76 -0
  114. package/src/components/media-player-play.tsx +75 -0
  115. package/src/components/media-player-root.tsx +340 -0
  116. package/src/components/media-player-seek.tsx +168 -0
  117. package/src/components/media-player-time.tsx +99 -0
  118. package/src/components/media-player-tooltip.tsx +58 -0
  119. package/src/components/media-player-video.tsx +39 -0
  120. package/src/components/media-player-volume.tsx +155 -0
  121. package/src/components/media-player.tsx +257 -0
  122. package/src/components/media-suspense.tsx +362 -0
  123. package/src/components/player-settings-form.tsx +163 -0
  124. package/src/components/react-player-wrapper.tsx +651 -0
  125. package/src/components/simple-video-player.tsx +60 -0
  126. package/src/components/ui/enhanced-seek-bar.tsx +235 -0
  127. package/src/components/ui/fullscreen-button.tsx +60 -0
  128. package/src/components/ui/media-resource-preloader.tsx +395 -0
  129. package/src/components/ui/play-button.tsx +107 -0
  130. package/src/components/ui/seek-bar.tsx +161 -0
  131. package/src/components/ui/time-display.tsx +40 -0
  132. package/src/components/ui/volume-control.tsx +143 -0
  133. package/src/components/unified/base-media-player.tsx +246 -0
  134. package/src/components/unified/media-player.tsx +75 -0
  135. package/src/components/variants/minimal/AccessibleMinimalPlayer.tsx +561 -0
  136. package/src/components/variants/minimal/EnhancedMinimalMediaPlayer.tsx +552 -0
  137. package/src/components/variants/minimal/MinimalControls.tsx +142 -0
  138. package/src/components/variants/minimal/MinimalLoading.tsx +32 -0
  139. package/src/components/variants/minimal/MinimalMediaPlayer.tsx +315 -0
  140. package/src/components/variants/minimal/MinimalOverlay.tsx +64 -0
  141. package/src/components/variants/minimal/MinimalPlayButton.tsx +65 -0
  142. package/src/components/variants/minimal/MinimalSeekBar.tsx +150 -0
  143. package/src/components/variants/minimal/MinimalVolumeControl.tsx +80 -0
  144. package/src/components/variants/minimal/SimpleMinimalPlayer.tsx +210 -0
  145. package/src/components/variants/minimal/components/CenterPlayButton.tsx +22 -0
  146. package/src/components/variants/minimal/components/ControlBar.tsx +146 -0
  147. package/src/components/variants/minimal/components/EnhancedSettingsMenu.tsx +361 -0
  148. package/src/components/variants/minimal/components/PlaybackControls.tsx +51 -0
  149. package/src/components/variants/minimal/components/RightControls.tsx +173 -0
  150. package/src/components/variants/minimal/components/SeekBar.tsx +131 -0
  151. package/src/components/variants/minimal/components/SettingsDropdown.tsx +70 -0
  152. package/src/components/variants/minimal/components/SubtitleDisplay.tsx +21 -0
  153. package/src/components/variants/minimal/components/TimeDisplay.tsx +18 -0
  154. package/src/components/variants/minimal/components/VideoElement.tsx +40 -0
  155. package/src/components/variants/minimal/components/VolumeControl.tsx +217 -0
  156. package/src/components/variants/minimal/index.ts +23 -0
  157. package/src/components/video-player.tsx +100 -0
  158. package/src/context/error-handling.ts +394 -0
  159. package/src/context/media-context.tsx +208 -0
  160. package/src/context/media-provider.tsx +265 -0
  161. package/src/context/media-store.ts +379 -0
  162. package/src/context/persistence.ts +453 -0
  163. package/src/core/events/event-system.ts +442 -0
  164. package/src/core/events/hooks.ts +302 -0
  165. package/src/core/events/index.ts +22 -0
  166. package/src/core/events/middleware.ts +269 -0
  167. package/src/core/index.ts +22 -0
  168. package/src/core/optimization/bundle-optimizer.tsx +308 -0
  169. package/src/core/performance/cicd.ts +96 -0
  170. package/src/core/performance/index.ts +38 -0
  171. package/src/core/performance/media-loading-optimizer.ts +538 -0
  172. package/src/core/performance/performance-budgets.ts +432 -0
  173. package/src/core/performance/performance-monitor.tsx +476 -0
  174. package/src/core/performance/performance-testing.ts +459 -0
  175. package/src/core/plugins/base-plugin.ts +224 -0
  176. package/src/core/plugins/enhanced-plugin-system.ts +411 -0
  177. package/src/core/plugins/examples/analytics-plugin.ts +242 -0
  178. package/src/core/plugins/index.ts +39 -0
  179. package/src/core/plugins/registry.ts +327 -0
  180. package/src/core/plugins/types.ts +159 -0
  181. package/src/core/plugins/utils.ts +316 -0
  182. package/src/core/progressive-loading.tsx +322 -0
  183. package/src/core/providers/enhanced-hls-provider.ts +339 -0
  184. package/src/core/providers/service-provider.tsx +168 -0
  185. package/src/core/utils.tsx +38 -0
  186. package/src/features/media-session/media-session-manager.ts +429 -0
  187. package/src/features/picture-in-picture/pip-manager.ts +429 -0
  188. package/src/features/playlist/playlist-manager.ts +606 -0
  189. package/src/features/subtitles/subtitle-manager.ts +441 -0
  190. package/src/features/subtitles/subtitle-parser.ts +280 -0
  191. package/src/features/thumbnails/thumbnail-generator.ts +519 -0
  192. package/src/hooks/accessibility/index.ts +27 -0
  193. package/src/hooks/accessibility/use-accessibility-preferences.ts +188 -0
  194. package/src/hooks/accessibility/use-focus-management.ts +176 -0
  195. package/src/hooks/accessibility/use-keyboard-shortcuts.ts +144 -0
  196. package/src/hooks/accessibility/use-screen-reader.ts +182 -0
  197. package/src/hooks/core/index.ts +47 -0
  198. package/src/hooks/legacy.ts +27 -0
  199. package/src/hooks/use-enhanced-media-player.ts +468 -0
  200. package/src/hooks/use-intelligent-preloading.ts +358 -0
  201. package/src/hooks/use-keyboard-controls.ts +115 -0
  202. package/src/hooks/use-media-actions.ts +175 -0
  203. package/src/hooks/use-media-metadata.ts +89 -0
  204. package/src/hooks/use-media-optimistic.ts +270 -0
  205. package/src/hooks/use-media-player.ts +312 -0
  206. package/src/hooks/use-media-state.ts +190 -0
  207. package/src/hooks/use-memory-optimization.ts +358 -0
  208. package/src/hooks/use-optimistic-controls.ts +92 -0
  209. package/src/hooks/use-optimized-media.ts +263 -0
  210. package/src/hooks/use-touch-gestures.ts +417 -0
  211. package/src/hooks/useEnhancedSubtitles.ts +258 -0
  212. package/src/hooks/useKeyboardShortcuts.ts +74 -0
  213. package/src/hooks/useMediaControls.ts +52 -0
  214. package/src/hooks/useScreenshot.ts +57 -0
  215. package/src/hooks/useSubtitles.ts +91 -0
  216. package/src/hooks/useVideoPlayer.ts +232 -0
  217. package/src/icons/components/FullscreenIcon.tsx +37 -0
  218. package/src/icons/components/SettingsIcon.tsx +38 -0
  219. package/src/icons/components/animated/LoadingIcon.tsx +43 -0
  220. package/src/icons/components/animated/PlayPauseIcon.tsx +50 -0
  221. package/src/icons/components/media/PauseIcon.tsx +39 -0
  222. package/src/icons/components/media/PlayIcon.tsx +38 -0
  223. package/src/icons/components/volume/VolumeIcon.tsx +39 -0
  224. package/src/icons/components/volume/VolumeOffIcon.tsx +39 -0
  225. package/src/icons/index.ts +56 -0
  226. package/src/icons/provider.tsx +64 -0
  227. package/src/icons/types.ts +40 -0
  228. package/src/index-enhanced.ts +35 -0
  229. package/src/index-legacy.ts +326 -0
  230. package/src/index.css +102 -0
  231. package/src/index.ts +216 -0
  232. package/src/lib/deprecation.ts +51 -0
  233. package/src/lib/format-time.ts +37 -0
  234. package/src/lib/index.ts +3 -0
  235. package/src/lib/utils.ts +6 -0
  236. package/src/styles/globals.css +462 -0
  237. package/src/styles/minimal-player.css +589 -0
  238. package/src/styles/pixel-art.css +46 -0
  239. package/src/styles/videojs.css +100 -0
  240. package/src/test/setup.ts +79 -0
  241. package/src/types/events.ts +47 -0
  242. package/src/types/formats.ts +95 -0
  243. package/src/types/index.ts +190 -0
  244. package/src/types/videojs-plugins.d.ts +14 -0
@@ -0,0 +1,429 @@
1
+ export interface MediaMetadata {
2
+ title?: string
3
+ artist?: string
4
+ album?: string
5
+ artwork?: MediaImage[]
6
+ }
7
+
8
+ export interface MediaImage {
9
+ src: string
10
+ sizes?: string
11
+ type?: string
12
+ }
13
+
14
+ export interface MediaPositionState {
15
+ duration?: number
16
+ playbackRate?: number
17
+ position?: number
18
+ }
19
+
20
+ export interface MediaSessionCallbacks {
21
+ onPlay?: () => void
22
+ onPause?: () => void
23
+ onSeekBackward?: (skipTime?: number) => void
24
+ onSeekForward?: (skipTime?: number) => void
25
+ onSeekTo?: (seekTime: number) => void
26
+ onPreviousTrack?: () => void
27
+ onNextTrack?: () => void
28
+ onStop?: () => void
29
+ onToggleMicrophone?: () => void
30
+ onToggleCamera?: () => void
31
+ onHangup?: () => void
32
+ }
33
+
34
+ export interface MediaSessionConfig {
35
+ enableActions?: string[]
36
+ skipBackwardTime?: number
37
+ skipForwardTime?: number
38
+ enablePositionTracking?: boolean
39
+ }
40
+
41
+ export class MediaSessionManager {
42
+ private callbacks: MediaSessionCallbacks = {}
43
+ private config: MediaSessionConfig
44
+ private positionUpdateInterval: number | null = null
45
+ private isInitialized = false
46
+
47
+ constructor(config: MediaSessionConfig = {}) {
48
+ this.config = {
49
+ enableActions: ['play', 'pause', 'seekbackward', 'seekforward', 'seekto'],
50
+ skipBackwardTime: 10,
51
+ skipForwardTime: 10,
52
+ enablePositionTracking: true,
53
+ ...config
54
+ }
55
+
56
+ this.initialize()
57
+ }
58
+
59
+ /**
60
+ * Initialize Media Session API
61
+ */
62
+ private initialize(): void {
63
+ if (!this.isSupported()) {
64
+ console.warn('Media Session API is not supported')
65
+ return
66
+ }
67
+
68
+ this.setupActionHandlers()
69
+ this.isInitialized = true
70
+ }
71
+
72
+ /**
73
+ * Check if Media Session API is supported
74
+ */
75
+ isSupported(): boolean {
76
+ return 'mediaSession' in navigator
77
+ }
78
+
79
+ /**
80
+ * Set media metadata
81
+ */
82
+ setMetadata(metadata: MediaMetadata): void {
83
+ if (!this.isInitialized) return
84
+
85
+ try {
86
+ const processedArtwork = metadata.artwork?.map(img => ({
87
+ src: img.src,
88
+ sizes: img.sizes || '512x512',
89
+ type: img.type || 'image/png'
90
+ }))
91
+
92
+ navigator.mediaSession.metadata = new MediaMetadata({
93
+ title: metadata.title || 'Unknown Title',
94
+ artist: metadata.artist || 'Unknown Artist',
95
+ album: metadata.album || 'Unknown Album',
96
+ artwork: processedArtwork || []
97
+ })
98
+ } catch (error) {
99
+ console.error('Failed to set media metadata:', error)
100
+ }
101
+ }
102
+
103
+ /**
104
+ * Set playback state
105
+ */
106
+ setPlaybackState(state: MediaSessionPlaybackState): void {
107
+ if (!this.isInitialized) return
108
+
109
+ try {
110
+ navigator.mediaSession.playbackState = state
111
+ } catch (error) {
112
+ console.error('Failed to set playback state:', error)
113
+ }
114
+ }
115
+
116
+ /**
117
+ * Set position state
118
+ */
119
+ setPositionState(state: MediaPositionState): void {
120
+ if (!this.isInitialized || !this.config.enablePositionTracking) return
121
+
122
+ try {
123
+ navigator.mediaSession.setPositionState(state)
124
+ } catch (error) {
125
+ console.error('Failed to set position state:', error)
126
+ }
127
+ }
128
+
129
+ /**
130
+ * Register callbacks for media actions
131
+ */
132
+ setCallbacks(callbacks: MediaSessionCallbacks): void {
133
+ this.callbacks = { ...this.callbacks, ...callbacks }
134
+
135
+ if (this.isInitialized) {
136
+ this.updateActionHandlers()
137
+ }
138
+ }
139
+
140
+ /**
141
+ * Setup action handlers
142
+ */
143
+ private setupActionHandlers(): void {
144
+ const actions = this.config.enableActions || []
145
+
146
+ actions.forEach(action => {
147
+ this.setActionHandler(action as MediaSessionAction)
148
+ })
149
+ }
150
+
151
+ /**
152
+ * Update action handlers with current callbacks
153
+ */
154
+ private updateActionHandlers(): void {
155
+ this.setupActionHandlers()
156
+ }
157
+
158
+ /**
159
+ * Set individual action handler
160
+ */
161
+ private setActionHandler(action: MediaSessionAction): void {
162
+ try {
163
+ navigator.mediaSession.setActionHandler(action, (details) => {
164
+ this.handleAction(action, details)
165
+ })
166
+ } catch (error) {
167
+ console.warn(`Failed to set handler for action: ${action}`, error)
168
+ }
169
+ }
170
+
171
+ /**
172
+ * Handle media session actions
173
+ */
174
+ private handleAction(action: MediaSessionAction, details?: MediaSessionActionDetails): void {
175
+ switch (action) {
176
+ case 'play':
177
+ this.callbacks.onPlay?.()
178
+ break
179
+
180
+ case 'pause':
181
+ this.callbacks.onPause?.()
182
+ break
183
+
184
+ case 'seekbackward':
185
+ const backwardTime = details?.seekOffset || this.config.skipBackwardTime || 10
186
+ this.callbacks.onSeekBackward?.(backwardTime)
187
+ break
188
+
189
+ case 'seekforward':
190
+ const forwardTime = details?.seekOffset || this.config.skipForwardTime || 10
191
+ this.callbacks.onSeekForward?.(forwardTime)
192
+ break
193
+
194
+ case 'seekto':
195
+ if (details?.seekTime !== undefined) {
196
+ this.callbacks.onSeekTo?.(details.seekTime)
197
+ }
198
+ break
199
+
200
+ case 'previoustrack':
201
+ this.callbacks.onPreviousTrack?.()
202
+ break
203
+
204
+ case 'nexttrack':
205
+ this.callbacks.onNextTrack?.()
206
+ break
207
+
208
+ case 'stop':
209
+ this.callbacks.onStop?.()
210
+ break
211
+
212
+ case 'togglemicrophone':
213
+ this.callbacks.onToggleMicrophone?.()
214
+ break
215
+
216
+ case 'togglecamera':
217
+ this.callbacks.onToggleCamera?.()
218
+ break
219
+
220
+ case 'hangup':
221
+ this.callbacks.onHangup?.()
222
+ break
223
+
224
+ default:
225
+ console.warn(`Unhandled media session action: ${action}`)
226
+ }
227
+ }
228
+
229
+ /**
230
+ * Start automatic position tracking
231
+ */
232
+ startPositionTracking(getCurrentTime: () => number, getDuration: () => number): void {
233
+ if (!this.config.enablePositionTracking || this.positionUpdateInterval) {
234
+ return
235
+ }
236
+
237
+ this.positionUpdateInterval = window.setInterval(() => {
238
+ try {
239
+ const currentTime = getCurrentTime()
240
+ const duration = getDuration()
241
+
242
+ if (!isNaN(currentTime) && !isNaN(duration) && duration > 0) {
243
+ this.setPositionState({
244
+ duration,
245
+ position: currentTime,
246
+ playbackRate: 1.0
247
+ })
248
+ }
249
+ } catch (error) {
250
+ console.error('Failed to update position state:', error)
251
+ }
252
+ }, 1000) // Update every second
253
+ }
254
+
255
+ /**
256
+ * Stop automatic position tracking
257
+ */
258
+ stopPositionTracking(): void {
259
+ if (this.positionUpdateInterval) {
260
+ clearInterval(this.positionUpdateInterval)
261
+ this.positionUpdateInterval = null
262
+ }
263
+ }
264
+
265
+ /**
266
+ * Enable specific actions
267
+ */
268
+ enableActions(actions: MediaSessionAction[]): void {
269
+ this.config.enableActions = [...(this.config.enableActions || []), ...actions]
270
+
271
+ if (this.isInitialized) {
272
+ actions.forEach(action => {
273
+ this.setActionHandler(action)
274
+ })
275
+ }
276
+ }
277
+
278
+ /**
279
+ * Disable specific actions
280
+ */
281
+ disableActions(actions: MediaSessionAction[]): void {
282
+ if (!this.isInitialized) return
283
+
284
+ actions.forEach(action => {
285
+ try {
286
+ navigator.mediaSession.setActionHandler(action, null)
287
+ } catch (error) {
288
+ console.warn(`Failed to disable action: ${action}`, error)
289
+ }
290
+ })
291
+
292
+ this.config.enableActions = this.config.enableActions?.filter(
293
+ action => !actions.includes(action as MediaSessionAction)
294
+ )
295
+ }
296
+
297
+ /**
298
+ * Create artwork from video thumbnail
299
+ */
300
+ createArtworkFromVideo(videoElement: HTMLVideoElement): Promise<MediaImage[]> {
301
+ return new Promise((resolve) => {
302
+ try {
303
+ const canvas = document.createElement('canvas')
304
+ const ctx = canvas.getContext('2d')
305
+
306
+ if (!ctx || videoElement.videoWidth === 0 || videoElement.videoHeight === 0) {
307
+ resolve([])
308
+ return
309
+ }
310
+
311
+ canvas.width = Math.min(videoElement.videoWidth, 512)
312
+ canvas.height = Math.min(videoElement.videoHeight, 512)
313
+
314
+ ctx.drawImage(videoElement, 0, 0, canvas.width, canvas.height)
315
+
316
+ canvas.toBlob((blob) => {
317
+ if (blob) {
318
+ const url = URL.createObjectURL(blob)
319
+ resolve([{
320
+ src: url,
321
+ sizes: `${canvas.width}x${canvas.height}`,
322
+ type: blob.type
323
+ }])
324
+ } else {
325
+ resolve([])
326
+ }
327
+ }, 'image/png')
328
+
329
+ } catch (error) {
330
+ console.error('Failed to create artwork from video:', error)
331
+ resolve([])
332
+ }
333
+ })
334
+ }
335
+
336
+ /**
337
+ * Update metadata from media element
338
+ */
339
+ async updateFromMediaElement(mediaElement: HTMLMediaElement, additionalInfo?: Partial<MediaMetadata>): Promise<void> {
340
+ const metadata: MediaMetadata = {
341
+ title: additionalInfo?.title || document.title || 'Media Player',
342
+ artist: additionalInfo?.artist || 'Unknown Artist',
343
+ album: additionalInfo?.album || 'Unknown Album',
344
+ artwork: additionalInfo?.artwork || []
345
+ }
346
+
347
+ // Try to extract artwork from video element
348
+ if (mediaElement instanceof HTMLVideoElement && metadata.artwork?.length === 0) {
349
+ try {
350
+ const videoArtwork = await this.createArtworkFromVideo(mediaElement)
351
+ metadata.artwork = videoArtwork
352
+ } catch (error) {
353
+ console.error('Failed to extract video artwork:', error)
354
+ }
355
+ }
356
+
357
+ this.setMetadata(metadata)
358
+ }
359
+
360
+ /**
361
+ * Get current session info
362
+ */
363
+ getSessionInfo(): {
364
+ supported: boolean
365
+ initialized: boolean
366
+ metadata: MediaMetadata | null
367
+ playbackState: MediaSessionPlaybackState | null
368
+ enabledActions: string[]
369
+ } {
370
+ return {
371
+ supported: this.isSupported(),
372
+ initialized: this.isInitialized,
373
+ metadata: this.isInitialized ? navigator.mediaSession.metadata : null,
374
+ playbackState: this.isInitialized ? navigator.mediaSession.playbackState : null,
375
+ enabledActions: this.config.enableActions || []
376
+ }
377
+ }
378
+
379
+ /**
380
+ * Reset session
381
+ */
382
+ reset(): void {
383
+ if (!this.isInitialized) return
384
+
385
+ try {
386
+ navigator.mediaSession.metadata = null
387
+ navigator.mediaSession.playbackState = 'none'
388
+
389
+ this.stopPositionTracking()
390
+
391
+ const actions = this.config.enableActions || []
392
+ actions.forEach(action => {
393
+ try {
394
+ navigator.mediaSession.setActionHandler(action as MediaSessionAction, null)
395
+ } catch (error) {
396
+ console.warn(`Failed to reset handler for action: ${action}`, error)
397
+ }
398
+ })
399
+
400
+ this.callbacks = {}
401
+ } catch (error) {
402
+ console.error('Failed to reset media session:', error)
403
+ }
404
+ }
405
+
406
+ /**
407
+ * Cleanup resources
408
+ */
409
+ destroy(): void {
410
+ this.stopPositionTracking()
411
+ this.reset()
412
+ this.isInitialized = false
413
+ }
414
+ }
415
+
416
+ // Utility function to create a configured media session manager
417
+ export function createMediaSessionManager(config?: MediaSessionConfig): MediaSessionManager {
418
+ return new MediaSessionManager(config)
419
+ }
420
+
421
+ // Type definitions for better TypeScript support
422
+ declare global {
423
+ interface Navigator {
424
+ mediaSession: MediaSession
425
+ }
426
+ }
427
+
428
+ // Export types for use in other modules
429
+ export type { MediaSessionAction, MediaSessionActionDetails, MediaSessionPlaybackState }