unified-video-framework 1.4.413 → 1.4.414

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 (106) hide show
  1. package/package.json +6 -1
  2. package/packages/core/src/BasePlayer.d.ts +61 -0
  3. package/packages/core/src/BasePlayer.d.ts.map +1 -0
  4. package/packages/core/src/BasePlayer.js +175 -0
  5. package/packages/core/src/BasePlayer.js.map +1 -0
  6. package/packages/core/src/VideoPlayerFactory.d.ts +8 -0
  7. package/packages/core/src/VideoPlayerFactory.d.ts.map +1 -0
  8. package/packages/core/src/VideoPlayerFactory.js +95 -0
  9. package/packages/core/src/VideoPlayerFactory.js.map +1 -0
  10. package/packages/core/src/analytics/adapters/PlayerAnalyticsAdapter.d.ts +18 -0
  11. package/packages/core/src/analytics/adapters/PlayerAnalyticsAdapter.d.ts.map +1 -0
  12. package/packages/core/src/analytics/adapters/PlayerAnalyticsAdapter.js +117 -0
  13. package/packages/core/src/analytics/adapters/PlayerAnalyticsAdapter.js.map +1 -0
  14. package/packages/core/src/analytics/core/AnalyticsProvider.d.ts +18 -0
  15. package/packages/core/src/analytics/core/AnalyticsProvider.d.ts.map +1 -0
  16. package/packages/core/src/analytics/core/AnalyticsProvider.js +99 -0
  17. package/packages/core/src/analytics/core/AnalyticsProvider.js.map +1 -0
  18. package/packages/core/src/analytics/core/DynamicAnalyticsManager.d.ts +20 -0
  19. package/packages/core/src/analytics/core/DynamicAnalyticsManager.d.ts.map +1 -0
  20. package/packages/core/src/analytics/core/DynamicAnalyticsManager.js +161 -0
  21. package/packages/core/src/analytics/core/DynamicAnalyticsManager.js.map +1 -0
  22. package/packages/core/src/analytics/core/EventBatcher.d.ts +32 -0
  23. package/packages/core/src/analytics/core/EventBatcher.d.ts.map +1 -0
  24. package/packages/core/src/analytics/core/EventBatcher.js +98 -0
  25. package/packages/core/src/analytics/core/EventBatcher.js.map +1 -0
  26. package/packages/core/src/analytics/core/PlayerAnalytics.d.ts +19 -0
  27. package/packages/core/src/analytics/core/PlayerAnalytics.d.ts.map +1 -0
  28. package/packages/core/src/analytics/core/PlayerAnalytics.js +80 -0
  29. package/packages/core/src/analytics/core/PlayerAnalytics.js.map +1 -0
  30. package/packages/core/src/analytics/index.d.ts +13 -0
  31. package/packages/core/src/analytics/index.d.ts.map +1 -0
  32. package/packages/core/src/analytics/index.js +13 -0
  33. package/packages/core/src/analytics/index.js.map +1 -0
  34. package/packages/core/src/analytics/types/AnalyticsTypes.d.ts +239 -0
  35. package/packages/core/src/analytics/types/AnalyticsTypes.d.ts.map +1 -0
  36. package/packages/core/src/analytics/types/AnalyticsTypes.js +8 -0
  37. package/packages/core/src/analytics/types/AnalyticsTypes.js.map +1 -0
  38. package/packages/core/src/analytics/utils/DeviceDetection.d.ts +27 -0
  39. package/packages/core/src/analytics/utils/DeviceDetection.d.ts.map +1 -0
  40. package/packages/core/src/analytics/utils/DeviceDetection.js +184 -0
  41. package/packages/core/src/analytics/utils/DeviceDetection.js.map +1 -0
  42. package/packages/core/src/chapter-manager.d.ts +39 -0
  43. package/packages/core/src/chapter-manager.d.ts.map +1 -0
  44. package/packages/core/src/chapter-manager.js +173 -0
  45. package/packages/core/src/chapter-manager.js.map +1 -0
  46. package/packages/core/src/index.d.ts +10 -0
  47. package/packages/core/src/index.d.ts.map +1 -0
  48. package/packages/core/src/index.js +8 -0
  49. package/packages/core/src/index.js.map +1 -0
  50. package/packages/core/src/interfaces/IVideoPlayer.d.ts +229 -0
  51. package/packages/core/src/interfaces/IVideoPlayer.d.ts.map +1 -0
  52. package/packages/core/src/interfaces/IVideoPlayer.js +2 -0
  53. package/packages/core/src/interfaces/IVideoPlayer.js.map +1 -0
  54. package/packages/core/src/interfaces.d.ts +455 -0
  55. package/packages/core/src/interfaces.d.ts.map +1 -0
  56. package/packages/core/src/interfaces.js +32 -0
  57. package/packages/core/src/interfaces.js.map +1 -0
  58. package/packages/core/src/utils/EventEmitter.d.ts +14 -0
  59. package/packages/core/src/utils/EventEmitter.d.ts.map +1 -0
  60. package/packages/core/src/utils/EventEmitter.js +55 -0
  61. package/packages/core/src/utils/EventEmitter.js.map +1 -0
  62. package/packages/web/dist/drm/DRMManager.d.ts +1 -1
  63. package/packages/web/dist/drm/DRMManager.d.ts.map +1 -1
  64. package/packages/web/dist/drm/DRMManager.js +7 -7
  65. package/packages/web/dist/drm/DRMManager.js.map +1 -1
  66. package/packages/web/dist/drm/providers/BunnyNetProvider.d.ts +1 -1
  67. package/packages/web/dist/drm/providers/BunnyNetProvider.d.ts.map +1 -1
  68. package/packages/web/dist/drm/providers/BunnyNetProvider.js +13 -13
  69. package/packages/web/dist/drm/providers/BunnyNetProvider.js.map +1 -1
  70. package/packages/web/dist/drm/providers/GenericProvider.d.ts +1 -1
  71. package/packages/web/dist/drm/providers/GenericProvider.d.ts.map +1 -1
  72. package/packages/web/dist/drm/providers/GenericProvider.js +8 -6
  73. package/packages/web/dist/drm/providers/GenericProvider.js.map +1 -1
  74. package/packages/web/dist/drm/systems/FairPlayDRM.d.ts.map +1 -1
  75. package/packages/web/dist/drm/systems/FairPlayDRM.js +2 -2
  76. package/packages/web/dist/drm/systems/FairPlayDRM.js.map +1 -1
  77. package/packages/web/dist/drm/systems/PlayReadyDRM.d.ts.map +1 -1
  78. package/packages/web/dist/drm/systems/PlayReadyDRM.js +7 -7
  79. package/packages/web/dist/drm/systems/PlayReadyDRM.js.map +1 -1
  80. package/packages/web/dist/drm/systems/WidevineDRM.d.ts.map +1 -1
  81. package/packages/web/dist/drm/systems/WidevineDRM.js +2 -2
  82. package/packages/web/dist/drm/systems/WidevineDRM.js.map +1 -1
  83. package/packages/web/dist/drm/types/BunnyNetTypes.d.ts +1 -1
  84. package/packages/web/dist/drm/types/BunnyNetTypes.d.ts.map +1 -1
  85. package/packages/web/dist/drm/types/DRMTypes.d.ts +1 -1
  86. package/packages/web/dist/drm/types/DRMTypes.d.ts.map +1 -1
  87. package/packages/web/dist/drm/types/DRMTypes.js +5 -5
  88. package/packages/web/dist/drm/types/DRMTypes.js.map +1 -1
  89. package/packages/web/dist/drm/utils/BrowserDetector.d.ts +1 -1
  90. package/packages/web/dist/drm/utils/BrowserDetector.d.ts.map +1 -1
  91. package/packages/web/dist/drm/utils/BrowserDetector.js +10 -10
  92. package/packages/web/dist/drm/utils/BrowserDetector.js.map +1 -1
  93. package/packages/web/src/drm/DRMManager.ts +214 -213
  94. package/packages/web/src/drm/index.ts +37 -37
  95. package/packages/web/src/drm/providers/BunnyNetProvider.ts +171 -170
  96. package/packages/web/src/drm/providers/GenericProvider.ts +151 -148
  97. package/packages/web/src/drm/systems/BaseDRM.ts +68 -68
  98. package/packages/web/src/drm/systems/FairPlayDRM.ts +306 -305
  99. package/packages/web/src/drm/systems/PlayReadyDRM.ts +132 -131
  100. package/packages/web/src/drm/systems/WidevineDRM.ts +106 -105
  101. package/packages/web/src/drm/types/BunnyNetTypes.ts +35 -35
  102. package/packages/web/src/drm/types/DRMTypes.ts +92 -91
  103. package/packages/web/src/drm/utils/BrowserDetector.ts +233 -232
  104. package/packages/web/src/drm/utils/CertificateManager.ts +86 -86
  105. package/packages/web/src/drm/utils/DRMErrorHandler.ts +84 -84
  106. package/packages/web/src/drm/utils/LicenseRequestHandler.ts +180 -180
@@ -1,91 +1,92 @@
1
- /**
2
- * DRM Type Definitions
3
- * Core type definitions and enums for DRM functionality
4
- */
5
-
6
- import { DRMConfig, DRMType } from '@unified-video/core';
7
-
8
- // Extended DRM configuration for internal use
9
- export interface ExtendedDRMConfig extends DRMConfig {
10
- // Provider-specific settings
11
- provider?: 'bunny' | 'generic' | string;
12
-
13
- // Library/Video IDs for Bunny.net
14
- libraryId?: string;
15
- videoId?: string;
16
-
17
- // Advanced options
18
- retryConfig?: {
19
- maxRetries: number;
20
- retryDelay: number;
21
- };
22
-
23
- // Debugging
24
- debug?: boolean;
25
- }
26
-
27
- // Browser DRM capabilities
28
- export interface DRMCapabilities {
29
- widevine: boolean;
30
- fairplay: boolean;
31
- playready: boolean;
32
- supportedType: DRMType | null;
33
- }
34
-
35
- // License request/response types
36
- export interface LicenseRequest {
37
- url: string;
38
- method: 'POST' | 'GET';
39
- headers: Record<string, string>;
40
- body: ArrayBuffer | string;
41
- responseType: 'arraybuffer' | 'text' | 'json';
42
- }
43
-
44
- export interface LicenseResponse {
45
- license: ArrayBuffer;
46
- metadata?: any;
47
- }
48
-
49
- // EME event types
50
- export interface EMEMessageEvent {
51
- messageType: string;
52
- message: ArrayBuffer;
53
- }
54
-
55
- // DRM initialization result
56
- export interface DRMInitResult {
57
- success: boolean;
58
- drmType: DRMType;
59
- keySystem: string;
60
- error?: DRMError;
61
- }
62
-
63
- // DRM-specific errors
64
- export interface DRMError {
65
- code: DRMErrorCode;
66
- message: string;
67
- fatal: boolean;
68
- details?: any;
69
- systemError?: any;
70
- }
71
-
72
- export enum DRMErrorCode {
73
- UNSUPPORTED_BROWSER = 'DRM_UNSUPPORTED_BROWSER',
74
- CERTIFICATE_LOAD_FAILED = 'DRM_CERTIFICATE_LOAD_FAILED',
75
- LICENSE_REQUEST_FAILED = 'DRM_LICENSE_REQUEST_FAILED',
76
- KEY_SYSTEM_ACCESS_DENIED = 'DRM_KEY_SYSTEM_ACCESS_DENIED',
77
- MEDIA_KEYS_CREATION_FAILED = 'DRM_MEDIA_KEYS_CREATION_FAILED',
78
- SESSION_CREATION_FAILED = 'DRM_SESSION_CREATION_FAILED',
79
- LICENSE_INVALID = 'DRM_LICENSE_INVALID',
80
- CONFIGURATION_ERROR = 'DRM_CONFIGURATION_ERROR',
81
- NETWORK_ERROR = 'DRM_NETWORK_ERROR',
82
- TIMEOUT = 'DRM_TIMEOUT',
83
- }
84
-
85
- // Key system mappings
86
- export const KEY_SYSTEMS: Record<DRMType, string[]> = {
87
- [DRMType.WIDEVINE]: ['com.widevine.alpha'],
88
- [DRMType.PLAYREADY]: ['com.microsoft.playready', 'com.microsoft.playready.recommendation'],
89
- [DRMType.FAIRPLAY]: ['com.apple.fps.1_0', 'com.apple.fps'],
90
- [DRMType.CLEARKEY]: ['webkit-org.w3.clearkey', 'org.w3.clearkey'],
91
- };
1
+ /**
2
+ * DRM Type Definitions
3
+ * Core type definitions and enums for DRM functionality
4
+ */
5
+
6
+ import type { DRMConfig, DRMType } from '@unified-video/core';
7
+ import { DRMType as DRMTypeEnum } from '@unified-video/core';
8
+
9
+ // Extended DRM configuration for internal use
10
+ export interface ExtendedDRMConfig extends DRMConfig {
11
+ // Provider-specific settings
12
+ provider?: 'bunny' | 'generic' | string;
13
+
14
+ // Library/Video IDs for Bunny.net
15
+ libraryId?: string;
16
+ videoId?: string;
17
+
18
+ // Advanced options
19
+ retryConfig?: {
20
+ maxRetries: number;
21
+ retryDelay: number;
22
+ };
23
+
24
+ // Debugging
25
+ debug?: boolean;
26
+ }
27
+
28
+ // Browser DRM capabilities
29
+ export interface DRMCapabilities {
30
+ widevine: boolean;
31
+ fairplay: boolean;
32
+ playready: boolean;
33
+ supportedType: DRMType | null;
34
+ }
35
+
36
+ // License request/response types
37
+ export interface LicenseRequest {
38
+ url: string;
39
+ method: 'POST' | 'GET';
40
+ headers: Record<string, string>;
41
+ body: ArrayBuffer | string;
42
+ responseType: 'arraybuffer' | 'text' | 'json';
43
+ }
44
+
45
+ export interface LicenseResponse {
46
+ license: ArrayBuffer;
47
+ metadata?: any;
48
+ }
49
+
50
+ // EME event types
51
+ export interface EMEMessageEvent {
52
+ messageType: string;
53
+ message: ArrayBuffer;
54
+ }
55
+
56
+ // DRM initialization result
57
+ export interface DRMInitResult {
58
+ success: boolean;
59
+ drmType: DRMType;
60
+ keySystem: string;
61
+ error?: DRMError;
62
+ }
63
+
64
+ // DRM-specific errors
65
+ export interface DRMError {
66
+ code: DRMErrorCode;
67
+ message: string;
68
+ fatal: boolean;
69
+ details?: any;
70
+ systemError?: any;
71
+ }
72
+
73
+ export enum DRMErrorCode {
74
+ UNSUPPORTED_BROWSER = 'DRM_UNSUPPORTED_BROWSER',
75
+ CERTIFICATE_LOAD_FAILED = 'DRM_CERTIFICATE_LOAD_FAILED',
76
+ LICENSE_REQUEST_FAILED = 'DRM_LICENSE_REQUEST_FAILED',
77
+ KEY_SYSTEM_ACCESS_DENIED = 'DRM_KEY_SYSTEM_ACCESS_DENIED',
78
+ MEDIA_KEYS_CREATION_FAILED = 'DRM_MEDIA_KEYS_CREATION_FAILED',
79
+ SESSION_CREATION_FAILED = 'DRM_SESSION_CREATION_FAILED',
80
+ LICENSE_INVALID = 'DRM_LICENSE_INVALID',
81
+ CONFIGURATION_ERROR = 'DRM_CONFIGURATION_ERROR',
82
+ NETWORK_ERROR = 'DRM_NETWORK_ERROR',
83
+ TIMEOUT = 'DRM_TIMEOUT',
84
+ }
85
+
86
+ // Key system mappings
87
+ export const KEY_SYSTEMS: Record<DRMType, string[]> = {
88
+ [DRMTypeEnum.WIDEVINE]: ['com.widevine.alpha'],
89
+ [DRMTypeEnum.PLAYREADY]: ['com.microsoft.playready', 'com.microsoft.playready.recommendation'],
90
+ [DRMTypeEnum.FAIRPLAY]: ['com.apple.fps.1_0', 'com.apple.fps'],
91
+ [DRMTypeEnum.CLEARKEY]: ['webkit-org.w3.clearkey', 'org.w3.clearkey'],
92
+ };
@@ -1,232 +1,233 @@
1
- /**
2
- * Browser DRM Detector
3
- * Detects browser capabilities and determines optimal DRM system
4
- */
5
-
6
- import { DRMType } from '@unified-video/core';
7
- import { DRMCapabilities, KEY_SYSTEMS } from '../types/DRMTypes';
8
-
9
- export class BrowserDetector {
10
- private static instance: BrowserDetector;
11
- private capabilities: DRMCapabilities | null = null;
12
-
13
- private constructor() {}
14
-
15
- static getInstance(): BrowserDetector {
16
- if (!BrowserDetector.instance) {
17
- BrowserDetector.instance = new BrowserDetector();
18
- }
19
- return BrowserDetector.instance;
20
- }
21
-
22
- /**
23
- * Detect DRM capabilities of current browser
24
- */
25
- async detectCapabilities(): Promise<DRMCapabilities> {
26
- if (this.capabilities) {
27
- return this.capabilities;
28
- }
29
-
30
- const capabilities: DRMCapabilities = {
31
- widevine: false,
32
- fairplay: false,
33
- playready: false,
34
- supportedType: null,
35
- };
36
-
37
- // Check for FairPlay (Safari/iOS) - highest priority on Apple devices
38
- if (this.isSafari() || this.isWebKitBased()) {
39
- capabilities.fairplay = await this.checkFairPlaySupport();
40
- if (capabilities.fairplay) {
41
- capabilities.supportedType = DRMType.FAIRPLAY;
42
- }
43
- }
44
-
45
- // Check for Widevine (Chrome, Firefox, Edge)
46
- if (!capabilities.supportedType) {
47
- capabilities.widevine = await this.checkWidevineSupport();
48
- if (capabilities.widevine) {
49
- capabilities.supportedType = DRMType.WIDEVINE;
50
- }
51
- }
52
-
53
- // Check for PlayReady (Edge, IE)
54
- if (!capabilities.supportedType && this.isEdge()) {
55
- capabilities.playready = await this.checkPlayReadySupport();
56
- if (capabilities.playready) {
57
- capabilities.supportedType = DRMType.PLAYREADY;
58
- }
59
- }
60
-
61
- this.capabilities = capabilities;
62
- return capabilities;
63
- }
64
-
65
- /**
66
- * Get recommended DRM type for current browser
67
- */
68
- async getRecommendedDRMType(): Promise<DRMType | null> {
69
- const caps = await this.detectCapabilities();
70
- return caps.supportedType;
71
- }
72
-
73
- /**
74
- * Check if specific DRM type is supported
75
- */
76
- async isDRMTypeSupported(drmType: DRMType): Promise<boolean> {
77
- const caps = await this.detectCapabilities();
78
- switch (drmType) {
79
- case DRMType.WIDEVINE:
80
- return caps.widevine;
81
- case DRMType.FAIRPLAY:
82
- return caps.fairplay;
83
- case DRMType.PLAYREADY:
84
- return caps.playready;
85
- default:
86
- return false;
87
- }
88
- }
89
-
90
- /**
91
- * Check if browser is Safari
92
- */
93
- private isSafari(): boolean {
94
- const ua = navigator.userAgent.toLowerCase();
95
- return ua.includes('safari') && !ua.includes('chrome') && !ua.includes('chromium');
96
- }
97
-
98
- /**
99
- * Check if browser is WebKit-based
100
- */
101
- private isWebKitBased(): boolean {
102
- return 'WebKitMediaKeys' in window;
103
- }
104
-
105
- /**
106
- * Check if browser is Edge
107
- */
108
- private isEdge(): boolean {
109
- const ua = navigator.userAgent.toLowerCase();
110
- return ua.includes('edg/');
111
- }
112
-
113
- /**
114
- * Check FairPlay support
115
- */
116
- private async checkFairPlaySupport(): Promise<boolean> {
117
- try {
118
- // Check for WebKit-specific FairPlay API
119
- if ('WebKitMediaKeys' in window) {
120
- return true;
121
- }
122
-
123
- // Check via EME API
124
- if (navigator.requestMediaKeySystemAccess) {
125
- const config: MediaKeySystemConfiguration[] = [{
126
- initDataTypes: ['sinf', 'skd'],
127
- videoCapabilities: [{ contentType: 'application/vnd.apple.mpegurl' }],
128
- }];
129
-
130
- for (const keySystem of KEY_SYSTEMS[DRMType.FAIRPLAY]) {
131
- try {
132
- await navigator.requestMediaKeySystemAccess(keySystem, config);
133
- return true;
134
- } catch (e) {
135
- // Try next key system
136
- continue;
137
- }
138
- }
139
- }
140
-
141
- return false;
142
- } catch {
143
- return false;
144
- }
145
- }
146
-
147
- /**
148
- * Check Widevine support
149
- */
150
- private async checkWidevineSupport(): Promise<boolean> {
151
- try {
152
- if (!navigator.requestMediaKeySystemAccess) {
153
- return false;
154
- }
155
-
156
- const config: MediaKeySystemConfiguration[] = [{
157
- initDataTypes: ['cenc'],
158
- videoCapabilities: [{
159
- contentType: 'video/mp4; codecs="avc1.42E01E"',
160
- }],
161
- }];
162
-
163
- for (const keySystem of KEY_SYSTEMS[DRMType.WIDEVINE]) {
164
- try {
165
- await navigator.requestMediaKeySystemAccess(keySystem, config);
166
- return true;
167
- } catch (e) {
168
- // Try next key system
169
- continue;
170
- }
171
- }
172
-
173
- return false;
174
- } catch {
175
- return false;
176
- }
177
- }
178
-
179
- /**
180
- * Check PlayReady support
181
- */
182
- private async checkPlayReadySupport(): Promise<boolean> {
183
- try {
184
- if (!navigator.requestMediaKeySystemAccess) {
185
- return false;
186
- }
187
-
188
- const config: MediaKeySystemConfiguration[] = [{
189
- initDataTypes: ['cenc'],
190
- videoCapabilities: [{
191
- contentType: 'video/mp4; codecs="avc1.42E01E"',
192
- }],
193
- }];
194
-
195
- for (const keySystem of KEY_SYSTEMS[DRMType.PLAYREADY]) {
196
- try {
197
- await navigator.requestMediaKeySystemAccess(keySystem, config);
198
- return true;
199
- } catch (e) {
200
- // Try next key system
201
- continue;
202
- }
203
- }
204
-
205
- return false;
206
- } catch {
207
- return false;
208
- }
209
- }
210
-
211
- /**
212
- * Get user-friendly browser name
213
- */
214
- getBrowserName(): string {
215
- const ua = navigator.userAgent.toLowerCase();
216
-
217
- if (ua.includes('edg/')) return 'Edge';
218
- if (ua.includes('chrome') || ua.includes('chromium')) return 'Chrome';
219
- if (ua.includes('firefox')) return 'Firefox';
220
- if (ua.includes('safari')) return 'Safari';
221
- if (ua.includes('opera') || ua.includes('opr/')) return 'Opera';
222
-
223
- return 'Unknown';
224
- }
225
-
226
- /**
227
- * Reset cached capabilities (useful for testing)
228
- */
229
- resetCapabilities(): void {
230
- this.capabilities = null;
231
- }
232
- }
1
+ /**
2
+ * Browser DRM Detector
3
+ * Detects browser capabilities and determines optimal DRM system
4
+ */
5
+
6
+ import type { DRMType } from '@unified-video/core';
7
+ import { DRMCapabilities, KEY_SYSTEMS } from '../types/DRMTypes';
8
+ import { DRMType as DRMTypeEnum } from '@unified-video/core';
9
+
10
+ export class BrowserDetector {
11
+ private static instance: BrowserDetector;
12
+ private capabilities: DRMCapabilities | null = null;
13
+
14
+ private constructor() {}
15
+
16
+ static getInstance(): BrowserDetector {
17
+ if (!BrowserDetector.instance) {
18
+ BrowserDetector.instance = new BrowserDetector();
19
+ }
20
+ return BrowserDetector.instance;
21
+ }
22
+
23
+ /**
24
+ * Detect DRM capabilities of current browser
25
+ */
26
+ async detectCapabilities(): Promise<DRMCapabilities> {
27
+ if (this.capabilities) {
28
+ return this.capabilities;
29
+ }
30
+
31
+ const capabilities: DRMCapabilities = {
32
+ widevine: false,
33
+ fairplay: false,
34
+ playready: false,
35
+ supportedType: null,
36
+ };
37
+
38
+ // Check for FairPlay (Safari/iOS) - highest priority on Apple devices
39
+ if (this.isSafari() || this.isWebKitBased()) {
40
+ capabilities.fairplay = await this.checkFairPlaySupport();
41
+ if (capabilities.fairplay) {
42
+ capabilities.supportedType = DRMTypeEnum.FAIRPLAY;
43
+ }
44
+ }
45
+
46
+ // Check for Widevine (Chrome, Firefox, Edge)
47
+ if (!capabilities.supportedType) {
48
+ capabilities.widevine = await this.checkWidevineSupport();
49
+ if (capabilities.widevine) {
50
+ capabilities.supportedType = DRMTypeEnum.WIDEVINE;
51
+ }
52
+ }
53
+
54
+ // Check for PlayReady (Edge, IE)
55
+ if (!capabilities.supportedType && this.isEdge()) {
56
+ capabilities.playready = await this.checkPlayReadySupport();
57
+ if (capabilities.playready) {
58
+ capabilities.supportedType = DRMTypeEnum.PLAYREADY;
59
+ }
60
+ }
61
+
62
+ this.capabilities = capabilities;
63
+ return capabilities;
64
+ }
65
+
66
+ /**
67
+ * Get recommended DRM type for current browser
68
+ */
69
+ async getRecommendedDRMType(): Promise<DRMType | null> {
70
+ const caps = await this.detectCapabilities();
71
+ return caps.supportedType;
72
+ }
73
+
74
+ /**
75
+ * Check if specific DRM type is supported
76
+ */
77
+ async isDRMTypeSupported(drmType: DRMType): Promise<boolean> {
78
+ const caps = await this.detectCapabilities();
79
+ switch (drmType) {
80
+ case DRMTypeEnum.WIDEVINE:
81
+ return caps.widevine;
82
+ case DRMTypeEnum.FAIRPLAY:
83
+ return caps.fairplay;
84
+ case DRMTypeEnum.PLAYREADY:
85
+ return caps.playready;
86
+ default:
87
+ return false;
88
+ }
89
+ }
90
+
91
+ /**
92
+ * Check if browser is Safari
93
+ */
94
+ private isSafari(): boolean {
95
+ const ua = navigator.userAgent.toLowerCase();
96
+ return ua.includes('safari') && !ua.includes('chrome') && !ua.includes('chromium');
97
+ }
98
+
99
+ /**
100
+ * Check if browser is WebKit-based
101
+ */
102
+ private isWebKitBased(): boolean {
103
+ return 'WebKitMediaKeys' in window;
104
+ }
105
+
106
+ /**
107
+ * Check if browser is Edge
108
+ */
109
+ private isEdge(): boolean {
110
+ const ua = navigator.userAgent.toLowerCase();
111
+ return ua.includes('edg/');
112
+ }
113
+
114
+ /**
115
+ * Check FairPlay support
116
+ */
117
+ private async checkFairPlaySupport(): Promise<boolean> {
118
+ try {
119
+ // Check for WebKit-specific FairPlay API
120
+ if ('WebKitMediaKeys' in window) {
121
+ return true;
122
+ }
123
+
124
+ // Check via EME API
125
+ if (navigator.requestMediaKeySystemAccess) {
126
+ const config: MediaKeySystemConfiguration[] = [{
127
+ initDataTypes: ['sinf', 'skd'],
128
+ videoCapabilities: [{ contentType: 'application/vnd.apple.mpegurl' }],
129
+ }];
130
+
131
+ for (const keySystem of KEY_SYSTEMS[DRMTypeEnum.FAIRPLAY]) {
132
+ try {
133
+ await navigator.requestMediaKeySystemAccess(keySystem, config);
134
+ return true;
135
+ } catch (e) {
136
+ // Try next key system
137
+ continue;
138
+ }
139
+ }
140
+ }
141
+
142
+ return false;
143
+ } catch {
144
+ return false;
145
+ }
146
+ }
147
+
148
+ /**
149
+ * Check Widevine support
150
+ */
151
+ private async checkWidevineSupport(): Promise<boolean> {
152
+ try {
153
+ if (!navigator.requestMediaKeySystemAccess) {
154
+ return false;
155
+ }
156
+
157
+ const config: MediaKeySystemConfiguration[] = [{
158
+ initDataTypes: ['cenc'],
159
+ videoCapabilities: [{
160
+ contentType: 'video/mp4; codecs="avc1.42E01E"',
161
+ }],
162
+ }];
163
+
164
+ for (const keySystem of KEY_SYSTEMS[DRMTypeEnum.WIDEVINE]) {
165
+ try {
166
+ await navigator.requestMediaKeySystemAccess(keySystem, config);
167
+ return true;
168
+ } catch (e) {
169
+ // Try next key system
170
+ continue;
171
+ }
172
+ }
173
+
174
+ return false;
175
+ } catch {
176
+ return false;
177
+ }
178
+ }
179
+
180
+ /**
181
+ * Check PlayReady support
182
+ */
183
+ private async checkPlayReadySupport(): Promise<boolean> {
184
+ try {
185
+ if (!navigator.requestMediaKeySystemAccess) {
186
+ return false;
187
+ }
188
+
189
+ const config: MediaKeySystemConfiguration[] = [{
190
+ initDataTypes: ['cenc'],
191
+ videoCapabilities: [{
192
+ contentType: 'video/mp4; codecs="avc1.42E01E"',
193
+ }],
194
+ }];
195
+
196
+ for (const keySystem of KEY_SYSTEMS[DRMTypeEnum.PLAYREADY]) {
197
+ try {
198
+ await navigator.requestMediaKeySystemAccess(keySystem, config);
199
+ return true;
200
+ } catch (e) {
201
+ // Try next key system
202
+ continue;
203
+ }
204
+ }
205
+
206
+ return false;
207
+ } catch {
208
+ return false;
209
+ }
210
+ }
211
+
212
+ /**
213
+ * Get user-friendly browser name
214
+ */
215
+ getBrowserName(): string {
216
+ const ua = navigator.userAgent.toLowerCase();
217
+
218
+ if (ua.includes('edg/')) return 'Edge';
219
+ if (ua.includes('chrome') || ua.includes('chromium')) return 'Chrome';
220
+ if (ua.includes('firefox')) return 'Firefox';
221
+ if (ua.includes('safari')) return 'Safari';
222
+ if (ua.includes('opera') || ua.includes('opr/')) return 'Opera';
223
+
224
+ return 'Unknown';
225
+ }
226
+
227
+ /**
228
+ * Reset cached capabilities (useful for testing)
229
+ */
230
+ resetCapabilities(): void {
231
+ this.capabilities = null;
232
+ }
233
+ }