unified-video-framework 1.4.412 → 1.4.413

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 (87) hide show
  1. package/package.json +1 -1
  2. package/packages/core/dist/interfaces/IVideoPlayer.d.ts +0 -22
  3. package/packages/core/dist/interfaces/IVideoPlayer.d.ts.map +1 -1
  4. package/packages/core/src/interfaces/IVideoPlayer.ts +0 -27
  5. package/packages/web/dist/WebPlayer.d.ts +0 -4
  6. package/packages/web/dist/WebPlayer.d.ts.map +1 -1
  7. package/packages/web/dist/WebPlayer.js +62 -73
  8. package/packages/web/dist/WebPlayer.js.map +1 -1
  9. package/packages/web/dist/drm/DRMManager.d.ts +16 -9
  10. package/packages/web/dist/drm/DRMManager.d.ts.map +1 -1
  11. package/packages/web/dist/drm/DRMManager.js +109 -42
  12. package/packages/web/dist/drm/DRMManager.js.map +1 -1
  13. package/packages/web/dist/drm/index.d.ts +15 -0
  14. package/packages/web/dist/drm/index.d.ts.map +1 -0
  15. package/packages/web/dist/drm/index.js +13 -0
  16. package/packages/web/dist/drm/index.js.map +1 -0
  17. package/packages/web/dist/drm/providers/BunnyNetProvider.d.ts +19 -0
  18. package/packages/web/dist/drm/providers/BunnyNetProvider.d.ts.map +1 -0
  19. package/packages/web/dist/drm/providers/BunnyNetProvider.js +112 -0
  20. package/packages/web/dist/drm/providers/BunnyNetProvider.js.map +1 -0
  21. package/packages/web/dist/drm/providers/GenericProvider.d.ts +30 -0
  22. package/packages/web/dist/drm/providers/GenericProvider.d.ts.map +1 -0
  23. package/packages/web/dist/drm/providers/GenericProvider.js +102 -0
  24. package/packages/web/dist/drm/providers/GenericProvider.js.map +1 -0
  25. package/packages/web/dist/drm/systems/BaseDRM.d.ts +18 -0
  26. package/packages/web/dist/drm/systems/BaseDRM.d.ts.map +1 -0
  27. package/packages/web/dist/drm/systems/BaseDRM.js +29 -0
  28. package/packages/web/dist/drm/systems/BaseDRM.js.map +1 -0
  29. package/packages/web/dist/drm/systems/FairPlayDRM.d.ts +32 -0
  30. package/packages/web/dist/drm/systems/FairPlayDRM.d.ts.map +1 -0
  31. package/packages/web/dist/drm/systems/FairPlayDRM.js +198 -0
  32. package/packages/web/dist/drm/systems/FairPlayDRM.js.map +1 -0
  33. package/packages/web/dist/drm/systems/PlayReadyDRM.d.ts +9 -0
  34. package/packages/web/dist/drm/systems/PlayReadyDRM.d.ts.map +1 -0
  35. package/packages/web/dist/drm/systems/PlayReadyDRM.js +92 -0
  36. package/packages/web/dist/drm/systems/PlayReadyDRM.js.map +1 -0
  37. package/packages/web/dist/drm/systems/WidevineDRM.d.ts +9 -0
  38. package/packages/web/dist/drm/systems/WidevineDRM.d.ts.map +1 -0
  39. package/packages/web/dist/drm/systems/WidevineDRM.js +73 -0
  40. package/packages/web/dist/drm/systems/WidevineDRM.js.map +1 -0
  41. package/packages/web/dist/drm/types/BunnyNetTypes.d.ts +20 -0
  42. package/packages/web/dist/drm/types/BunnyNetTypes.d.ts.map +1 -0
  43. package/packages/web/dist/drm/types/BunnyNetTypes.js +8 -0
  44. package/packages/web/dist/drm/types/BunnyNetTypes.js.map +1 -0
  45. package/packages/web/dist/drm/types/DRMTypes.d.ts +56 -49
  46. package/packages/web/dist/drm/types/DRMTypes.d.ts.map +1 -1
  47. package/packages/web/dist/drm/types/DRMTypes.js +19 -13
  48. package/packages/web/dist/drm/types/DRMTypes.js.map +1 -1
  49. package/packages/web/dist/drm/utils/BrowserDetector.d.ts +20 -0
  50. package/packages/web/dist/drm/utils/BrowserDetector.d.ts.map +1 -0
  51. package/packages/web/dist/drm/utils/BrowserDetector.js +168 -0
  52. package/packages/web/dist/drm/utils/BrowserDetector.js.map +1 -0
  53. package/packages/web/dist/drm/utils/CertificateManager.d.ts +15 -0
  54. package/packages/web/dist/drm/utils/CertificateManager.d.ts.map +1 -0
  55. package/packages/web/dist/drm/utils/CertificateManager.js +46 -0
  56. package/packages/web/dist/drm/utils/CertificateManager.js.map +1 -0
  57. package/packages/web/dist/drm/utils/DRMErrorHandler.d.ts +7 -0
  58. package/packages/web/dist/drm/utils/DRMErrorHandler.d.ts.map +1 -0
  59. package/packages/web/dist/drm/utils/DRMErrorHandler.js +49 -0
  60. package/packages/web/dist/drm/utils/DRMErrorHandler.js.map +1 -0
  61. package/packages/web/dist/drm/utils/LicenseRequestHandler.d.ts +15 -0
  62. package/packages/web/dist/drm/utils/LicenseRequestHandler.d.ts.map +1 -0
  63. package/packages/web/dist/drm/utils/LicenseRequestHandler.js +110 -0
  64. package/packages/web/dist/drm/utils/LicenseRequestHandler.js.map +1 -0
  65. package/packages/web/dist/react/WebPlayerView.d.ts +1 -18
  66. package/packages/web/dist/react/WebPlayerView.d.ts.map +1 -1
  67. package/packages/web/dist/react/WebPlayerView.js +0 -5
  68. package/packages/web/dist/react/WebPlayerView.js.map +1 -1
  69. package/packages/web/src/WebPlayer.ts +79 -106
  70. package/packages/web/src/drm/DRMManager.ts +172 -58
  71. package/packages/web/src/drm/index.ts +37 -0
  72. package/packages/web/src/drm/providers/BunnyNetProvider.ts +170 -0
  73. package/packages/web/src/drm/providers/GenericProvider.ts +148 -0
  74. package/packages/web/src/drm/systems/BaseDRM.ts +68 -0
  75. package/packages/web/src/drm/systems/FairPlayDRM.ts +305 -0
  76. package/packages/web/src/drm/systems/PlayReadyDRM.ts +131 -0
  77. package/packages/web/src/drm/systems/WidevineDRM.ts +105 -0
  78. package/packages/web/src/drm/types/BunnyNetTypes.ts +35 -0
  79. package/packages/web/src/drm/types/DRMTypes.ts +70 -76
  80. package/packages/web/src/drm/utils/BrowserDetector.ts +232 -0
  81. package/packages/web/src/drm/utils/CertificateManager.ts +86 -0
  82. package/packages/web/src/drm/utils/DRMErrorHandler.ts +84 -0
  83. package/packages/web/src/drm/utils/LicenseRequestHandler.ts +180 -0
  84. package/packages/web/src/react/WebPlayerView.tsx +1 -28
  85. package/packages/web/src/drm/BunnyCDNDRMProvider.ts +0 -104
  86. package/packages/web/src/drm/FairPlayDRMHandler.ts +0 -322
  87. package/packages/web/src/drm/WidevineDRMHandler.ts +0 -246
@@ -1,99 +1,213 @@
1
1
  /**
2
2
  * DRM Manager
3
- * Main orchestrator for web DRM - detects browser and initializes appropriate handler
3
+ * Main orchestrator for all DRM systems
4
+ * Provides a unified interface for HLS.js, dash.js, and native playback
4
5
  */
5
6
 
6
- import { IDRMHandler, WebDRMConfig, DRMError } from './types/DRMTypes';
7
- import { WidevineDRMHandler } from './WidevineDRMHandler';
8
- import { FairPlayDRMHandler } from './FairPlayDRMHandler';
7
+ import { DRMType, DRMConfig } from '@unified-video/core';
8
+ import { ExtendedDRMConfig, DRMInitResult, DRMError, DRMErrorCode, DRMCapabilities } from './types/DRMTypes';
9
+ import { BrowserDetector } from './utils/BrowserDetector';
10
+ import { BunnyNetProvider } from './providers/BunnyNetProvider';
11
+ import { WidevineDRM } from './systems/WidevineDRM';
12
+ import { FairPlayDRM } from './systems/FairPlayDRM';
13
+ import { PlayReadyDRM } from './systems/PlayReadyDRM';
14
+ import { BaseDRM } from './systems/BaseDRM';
15
+ import { DRMErrorHandler } from './utils/DRMErrorHandler';
9
16
 
10
17
  export class DRMManager {
11
- private handler: IDRMHandler | null = null;
12
- private config: WebDRMConfig;
18
+ private videoElement: HTMLVideoElement;
19
+ private config: ExtendedDRMConfig;
20
+ private drmSystem: BaseDRM | null = null;
21
+ private browserDetector: BrowserDetector;
22
+ private debug: boolean = false;
13
23
 
14
- constructor(config: WebDRMConfig) {
15
- this.config = config;
24
+ constructor(videoElement: HTMLVideoElement, config: DRMConfig, debug: boolean = false) {
25
+ this.videoElement = videoElement;
26
+ this.config = this.normalizeConfig(config);
27
+ this.debug = debug || this.config.debug || false;
28
+ this.browserDetector = BrowserDetector.getInstance();
16
29
  }
17
30
 
18
31
  /**
19
- * Detect browser and return appropriate DRM handler
32
+ * Initialize DRM system based on browser capabilities
20
33
  */
21
- private detectDRMHandler(): IDRMHandler {
22
- const userAgent = navigator.userAgent.toLowerCase();
23
- const isSafari = /^((?!chrome|android).)*safari/i.test(navigator.userAgent);
24
-
25
- if (isSafari) {
26
- console.log('[DRM] Detected Safari - using FairPlay DRM');
27
- return new FairPlayDRMHandler(this.config);
28
- } else {
29
- console.log('[DRM] Detected non-Safari browser - using Widevine DRM');
30
- return new WidevineDRMHandler(this.config);
34
+ async initialize(): Promise<DRMInitResult> {
35
+ try {
36
+ this.log('Initializing DRM system...');
37
+
38
+ // Detect browser capabilities
39
+ const capabilities = await this.browserDetector.detectCapabilities();
40
+ this.log('Browser DRM capabilities:', capabilities);
41
+
42
+ // Determine which DRM system to use
43
+ const drmType = this.selectDRMType(capabilities);
44
+ if (!drmType) {
45
+ const browserName = this.browserDetector.getBrowserName();
46
+ throw DRMErrorHandler.createError(
47
+ DRMErrorCode.UNSUPPORTED_BROWSER,
48
+ `No supported DRM system found in ${browserName}. Please use Chrome, Safari, Firefox, or Edge.`,
49
+ true,
50
+ { browser: browserName, capabilities }
51
+ );
52
+ }
53
+
54
+ this.log(`Selected DRM type: ${drmType}`);
55
+
56
+ // Create appropriate DRM system
57
+ this.drmSystem = this.createDRMSystem(drmType);
58
+
59
+ // Initialize the DRM system
60
+ await this.drmSystem.initialize();
61
+
62
+ return {
63
+ success: true,
64
+ drmType,
65
+ keySystem: this.drmSystem.getKeySystem(),
66
+ };
67
+ } catch (error: any) {
68
+ this.log('DRM initialization failed:', error);
69
+
70
+ const drmError = error.code && error.code.startsWith('DRM_')
71
+ ? error
72
+ : DRMErrorHandler.createError(
73
+ DRMErrorCode.CONFIGURATION_ERROR,
74
+ error.message || 'DRM initialization failed',
75
+ true,
76
+ error
77
+ );
78
+
79
+ return {
80
+ success: false,
81
+ drmType: this.config.type,
82
+ keySystem: '',
83
+ error: drmError,
84
+ };
31
85
  }
32
86
  }
33
87
 
34
88
  /**
35
- * Initialize DRM system
89
+ * Get HLS.js configuration for DRM
36
90
  */
37
- async initialize(): Promise<void> {
38
- console.log('[DRM] Initializing DRM Manager...');
91
+ getHLSConfig(): any {
92
+ if (!this.drmSystem) {
93
+ throw new Error('DRM system not initialized. Call initialize() first.');
94
+ }
39
95
 
40
- try {
41
- // Detect and create appropriate handler
42
- this.handler = this.detectDRMHandler();
43
-
44
- // Check if DRM is supported
45
- if (!this.handler.isSupported()) {
46
- throw new DRMError(
47
- 'DRM is not supported in this browser',
48
- 'DRM_NOT_SUPPORTED'
49
- );
50
- }
96
+ return this.drmSystem.getHLSConfig();
97
+ }
51
98
 
52
- // Initialize the handler
53
- await this.handler.initialize();
54
- console.log('[DRM] DRM Manager initialized successfully');
99
+ /**
100
+ * Get dash.js protection data for DRM
101
+ */
102
+ getDashProtectionData(): any {
103
+ if (!this.drmSystem) {
104
+ throw new Error('DRM system not initialized. Call initialize() first.');
105
+ }
55
106
 
56
- } catch (error) {
57
- console.error('[DRM] Failed to initialize DRM Manager:', error);
58
- throw error;
107
+ return this.drmSystem.getDashProtectionData();
108
+ }
109
+
110
+ /**
111
+ * Cleanup DRM resources
112
+ */
113
+ async destroy(): Promise<void> {
114
+ if (this.drmSystem) {
115
+ this.log('Destroying DRM system');
116
+ await this.drmSystem.destroy();
117
+ this.drmSystem = null;
59
118
  }
60
119
  }
61
120
 
62
121
  /**
63
- * Setup DRM for video element and manifest
122
+ * Select appropriate DRM type based on config and capabilities
64
123
  */
65
- async setupDRM(videoElement: HTMLVideoElement, manifestUrl: string): Promise<void> {
66
- if (!this.handler) {
67
- throw new DRMError('DRM Manager not initialized', 'DRM_NOT_INITIALIZED');
124
+ private selectDRMType(capabilities: DRMCapabilities): DRMType | null {
125
+ // If config specifies a type and it's supported, use it
126
+ if (this.config.type) {
127
+ const typeSupported = this.isDRMTypeSupported(this.config.type, capabilities);
128
+ if (typeSupported) {
129
+ return this.config.type;
130
+ }
131
+
132
+ this.log(`Requested DRM type ${this.config.type} not supported, falling back to browser default`);
68
133
  }
69
134
 
70
- console.log('[DRM] Setting up DRM for video element');
71
- await this.handler.setupDRM(videoElement, manifestUrl);
135
+ // Otherwise, use browser's preferred DRM system
136
+ return capabilities.supportedType;
72
137
  }
73
138
 
74
139
  /**
75
- * Check if DRM is currently active
140
+ * Check if specific DRM type is supported
76
141
  */
77
- isActive(): boolean {
78
- return this.handler !== null;
142
+ private isDRMTypeSupported(drmType: DRMType, capabilities: DRMCapabilities): boolean {
143
+ switch (drmType) {
144
+ case DRMType.WIDEVINE:
145
+ return capabilities.widevine;
146
+ case DRMType.FAIRPLAY:
147
+ return capabilities.fairplay;
148
+ case DRMType.PLAYREADY:
149
+ return capabilities.playready;
150
+ default:
151
+ return false;
152
+ }
79
153
  }
80
154
 
81
155
  /**
82
- * Get current DRM handler type
156
+ * Create DRM system instance
83
157
  */
84
- getHandlerType(): 'widevine' | 'fairplay' | null {
85
- if (!this.handler) return null;
86
- return this.handler instanceof FairPlayDRMHandler ? 'fairplay' : 'widevine';
158
+ private createDRMSystem(drmType: DRMType): BaseDRM {
159
+ switch (drmType) {
160
+ case DRMType.FAIRPLAY:
161
+ return new FairPlayDRM(this.videoElement, this.config, this.debug);
162
+
163
+ case DRMType.WIDEVINE:
164
+ return new WidevineDRM(this.videoElement, this.config, this.debug);
165
+
166
+ case DRMType.PLAYREADY:
167
+ return new PlayReadyDRM(this.videoElement, this.config, this.debug);
168
+
169
+ default:
170
+ throw DRMErrorHandler.createError(
171
+ DRMErrorCode.CONFIGURATION_ERROR,
172
+ `Unsupported DRM type: ${drmType}`,
173
+ true
174
+ );
175
+ }
87
176
  }
88
177
 
89
178
  /**
90
- * Cleanup DRM resources
179
+ * Normalize and enrich DRM config
180
+ */
181
+ private normalizeConfig(config: DRMConfig): ExtendedDRMConfig {
182
+ const extended = { ...config } as ExtendedDRMConfig;
183
+
184
+ // Auto-detect Bunny.net and enhance config
185
+ if (BunnyNetProvider.isBunnyNetConfig(config)) {
186
+ extended.provider = 'bunny';
187
+
188
+ // Extract IDs if available
189
+ const ids = BunnyNetProvider.extractIdsFromUrl(config.licenseUrl);
190
+ if (ids.libraryId) extended.libraryId = ids.libraryId;
191
+ if (ids.videoId) extended.videoId = ids.videoId;
192
+
193
+ this.log('Detected Bunny.net DRM configuration');
194
+ }
195
+
196
+ // Set defaults
197
+ extended.retryConfig = extended.retryConfig || {
198
+ maxRetries: 3,
199
+ retryDelay: 1000,
200
+ };
201
+
202
+ return extended;
203
+ }
204
+
205
+ /**
206
+ * Debug logging
91
207
  */
92
- destroy(): void {
93
- if (this.handler) {
94
- console.log('[DRM] Destroying DRM Manager');
95
- this.handler.destroy();
96
- this.handler = null;
208
+ private log(...args: any[]): void {
209
+ if (this.debug) {
210
+ console.log('[DRMManager]', ...args);
97
211
  }
98
212
  }
99
213
  }
@@ -0,0 +1,37 @@
1
+ /**
2
+ * DRM System - Public API
3
+ * Exports for the DRM system
4
+ */
5
+
6
+ // Main DRM Manager
7
+ export { DRMManager } from './DRMManager';
8
+
9
+ // Providers
10
+ export { BunnyNetProvider } from './providers/BunnyNetProvider';
11
+ export { GenericProvider } from './providers/GenericProvider';
12
+
13
+ // Types
14
+ export type {
15
+ ExtendedDRMConfig,
16
+ DRMCapabilities,
17
+ LicenseRequest,
18
+ LicenseResponse,
19
+ DRMInitResult,
20
+ DRMError,
21
+ } from './types/DRMTypes';
22
+
23
+ export { DRMErrorCode, KEY_SYSTEMS } from './types/DRMTypes';
24
+
25
+ export type { BunnyNetConfig, BunnyNetEndpoints } from './types/BunnyNetTypes';
26
+ export { BUNNY_NET_BASE_URL, BUNNY_NET_ENDPOINTS } from './types/BunnyNetTypes';
27
+
28
+ // Utilities
29
+ export { BrowserDetector } from './utils/BrowserDetector';
30
+ export { DRMErrorHandler } from './utils/DRMErrorHandler';
31
+ export { CertificateManager } from './utils/CertificateManager';
32
+
33
+ // DRM Systems (for advanced usage)
34
+ export { BaseDRM } from './systems/BaseDRM';
35
+ export { WidevineDRM } from './systems/WidevineDRM';
36
+ export { FairPlayDRM } from './systems/FairPlayDRM';
37
+ export { PlayReadyDRM } from './systems/PlayReadyDRM';
@@ -0,0 +1,170 @@
1
+ /**
2
+ * Bunny.net DRM Provider
3
+ * Helper utilities for Bunny.net MediaCage DRM integration
4
+ */
5
+
6
+ import { DRMType, DRMConfig } from '@unified-video/core';
7
+ import { ExtendedDRMConfig } from '../types/DRMTypes';
8
+ import { BunnyNetConfig, BUNNY_NET_ENDPOINTS } from '../types/BunnyNetTypes';
9
+
10
+ export class BunnyNetProvider {
11
+ /**
12
+ * Generate complete DRM config from Bunny.net credentials
13
+ */
14
+ static createDRMConfig(config: BunnyNetConfig): ExtendedDRMConfig {
15
+ const { libraryId, videoId, drmType = DRMType.WIDEVINE } = config;
16
+
17
+ const drmConfig: ExtendedDRMConfig = {
18
+ type: drmType,
19
+ licenseUrl: this.getLicenseUrl(drmType, libraryId, videoId),
20
+ provider: 'bunny',
21
+ libraryId,
22
+ videoId,
23
+ };
24
+
25
+ // Add FairPlay-specific settings
26
+ if (drmType === DRMType.FAIRPLAY) {
27
+ drmConfig.certificateUrl = this.getCertificateUrl(libraryId);
28
+ drmConfig.fairplayOptions = {
29
+ certificateUrl: this.getCertificateUrl(libraryId),
30
+ licenseUrl: this.getLicenseUrl(drmType, libraryId, videoId),
31
+ };
32
+ }
33
+
34
+ // Add Widevine-specific settings
35
+ if (drmType === DRMType.WIDEVINE) {
36
+ drmConfig.widevineOptions = {
37
+ licenseUrl: this.getLicenseUrl(drmType, libraryId, videoId),
38
+ };
39
+ }
40
+
41
+ // Add PlayReady-specific settings
42
+ if (drmType === DRMType.PLAYREADY) {
43
+ drmConfig.playreadyOptions = {
44
+ licenseUrl: this.getLicenseUrl(drmType, libraryId, videoId),
45
+ };
46
+ }
47
+
48
+ return drmConfig;
49
+ }
50
+
51
+ /**
52
+ * Get license URL for specific DRM type
53
+ */
54
+ static getLicenseUrl(drmType: DRMType, libraryId: string, videoId: string): string {
55
+ switch (drmType) {
56
+ case DRMType.WIDEVINE:
57
+ return BUNNY_NET_ENDPOINTS.WIDEVINE_LICENSE(libraryId, videoId);
58
+
59
+ case DRMType.FAIRPLAY:
60
+ return BUNNY_NET_ENDPOINTS.FAIRPLAY_LICENSE(libraryId, videoId);
61
+
62
+ case DRMType.PLAYREADY:
63
+ return BUNNY_NET_ENDPOINTS.PLAYREADY_LICENSE(libraryId, videoId);
64
+
65
+ default:
66
+ throw new Error(`Unsupported DRM type for Bunny.net: ${drmType}`);
67
+ }
68
+ }
69
+
70
+ /**
71
+ * Get certificate URL (FairPlay only)
72
+ */
73
+ static getCertificateUrl(libraryId: string): string {
74
+ return BUNNY_NET_ENDPOINTS.FAIRPLAY_CERTIFICATE(libraryId);
75
+ }
76
+
77
+ /**
78
+ * Validate Bunny.net DRM configuration
79
+ */
80
+ static validateConfig(config: BunnyNetConfig): { valid: boolean; error?: string } {
81
+ if (!config.libraryId || !config.videoId) {
82
+ return {
83
+ valid: false,
84
+ error: 'Bunny.net DRM requires libraryId and videoId',
85
+ };
86
+ }
87
+
88
+ if (!/^\d+$/.test(config.libraryId)) {
89
+ return {
90
+ valid: false,
91
+ error: 'libraryId must be a numeric string',
92
+ };
93
+ }
94
+
95
+ return { valid: true };
96
+ }
97
+
98
+ /**
99
+ * Auto-detect if a DRM config is for Bunny.net
100
+ */
101
+ static isBunnyNetConfig(config: DRMConfig): boolean {
102
+ return !!(
103
+ config.licenseUrl?.includes('bunnycdn.com') ||
104
+ config.certificateUrl?.includes('bunnycdn.com') ||
105
+ config.fairplayOptions?.licenseUrl?.includes('bunnycdn.com') ||
106
+ config.fairplayOptions?.certificateUrl?.includes('bunnycdn.com') ||
107
+ config.widevineOptions?.licenseUrl?.includes('bunnycdn.com') ||
108
+ config.playreadyOptions?.licenseUrl?.includes('bunnycdn.com')
109
+ );
110
+ }
111
+
112
+ /**
113
+ * Extract library and video IDs from Bunny.net URLs
114
+ */
115
+ static extractIdsFromUrl(url: string): { libraryId?: string; videoId?: string } {
116
+ if (!url) return {};
117
+
118
+ const widevineMatch = url.match(/WidevineLicense\/([^/]+)\/([^/?]+)/);
119
+ const fairplayLicenseMatch = url.match(/FairPlay\/([^/]+)\/license.*videoId=([^&]+)/);
120
+ const fairplayCertMatch = url.match(/FairPlay\/([^/]+)\/certificate/);
121
+ const playreadyMatch = url.match(/PlayReadyLicense\/([^/]+)\/([^/?]+)/);
122
+
123
+ if (widevineMatch) {
124
+ return { libraryId: widevineMatch[1], videoId: widevineMatch[2] };
125
+ }
126
+ if (fairplayLicenseMatch) {
127
+ return { libraryId: fairplayLicenseMatch[1], videoId: fairplayLicenseMatch[2] };
128
+ }
129
+ if (fairplayCertMatch) {
130
+ return { libraryId: fairplayCertMatch[1] };
131
+ }
132
+ if (playreadyMatch) {
133
+ return { libraryId: playreadyMatch[1], videoId: playreadyMatch[2] };
134
+ }
135
+
136
+ return {};
137
+ }
138
+
139
+ /**
140
+ * Create multi-DRM config for Bunny.net (auto-detects browser)
141
+ */
142
+ static createMultiDRMConfig(libraryId: string, videoId: string): ExtendedDRMConfig {
143
+ // Primary Widevine config with FairPlay fallback
144
+ const config: ExtendedDRMConfig = {
145
+ type: DRMType.WIDEVINE,
146
+ licenseUrl: this.getLicenseUrl(DRMType.WIDEVINE, libraryId, videoId),
147
+ provider: 'bunny',
148
+ libraryId,
149
+ videoId,
150
+
151
+ // Widevine options
152
+ widevineOptions: {
153
+ licenseUrl: this.getLicenseUrl(DRMType.WIDEVINE, libraryId, videoId),
154
+ },
155
+
156
+ // FairPlay options (for Safari fallback)
157
+ fairplayOptions: {
158
+ certificateUrl: this.getCertificateUrl(libraryId),
159
+ licenseUrl: this.getLicenseUrl(DRMType.FAIRPLAY, libraryId, videoId),
160
+ },
161
+
162
+ // PlayReady options (for Edge fallback)
163
+ playreadyOptions: {
164
+ licenseUrl: this.getLicenseUrl(DRMType.PLAYREADY, libraryId, videoId),
165
+ },
166
+ };
167
+
168
+ return config;
169
+ }
170
+ }
@@ -0,0 +1,148 @@
1
+ /**
2
+ * Generic DRM Provider
3
+ * Helper utilities for generic DRM configurations
4
+ */
5
+
6
+ import { DRMType, DRMConfig } from '@unified-video/core';
7
+ import { ExtendedDRMConfig } from '../types/DRMTypes';
8
+
9
+ export class GenericProvider {
10
+ /**
11
+ * Create generic DRM config with sensible defaults
12
+ */
13
+ static createDRMConfig(config: {
14
+ drmType: DRMType;
15
+ licenseUrl: string;
16
+ certificateUrl?: string;
17
+ headers?: Record<string, string>;
18
+ customData?: string;
19
+ }): ExtendedDRMConfig {
20
+ const drmConfig: ExtendedDRMConfig = {
21
+ type: config.drmType,
22
+ licenseUrl: config.licenseUrl,
23
+ certificateUrl: config.certificateUrl,
24
+ headers: config.headers,
25
+ customData: config.customData,
26
+ provider: 'generic',
27
+ };
28
+
29
+ // Add type-specific options
30
+ switch (config.drmType) {
31
+ case DRMType.FAIRPLAY:
32
+ if (config.certificateUrl) {
33
+ drmConfig.fairplayOptions = {
34
+ certificateUrl: config.certificateUrl,
35
+ licenseUrl: config.licenseUrl,
36
+ };
37
+ }
38
+ break;
39
+
40
+ case DRMType.WIDEVINE:
41
+ drmConfig.widevineOptions = {
42
+ licenseUrl: config.licenseUrl,
43
+ };
44
+ break;
45
+
46
+ case DRMType.PLAYREADY:
47
+ drmConfig.playreadyOptions = {
48
+ licenseUrl: config.licenseUrl,
49
+ customData: config.customData,
50
+ };
51
+ break;
52
+ }
53
+
54
+ return drmConfig;
55
+ }
56
+
57
+ /**
58
+ * Validate generic DRM configuration
59
+ */
60
+ static validateConfig(config: DRMConfig): { valid: boolean; error?: string } {
61
+ if (!config.type) {
62
+ return {
63
+ valid: false,
64
+ error: 'DRM type is required',
65
+ };
66
+ }
67
+
68
+ if (!config.licenseUrl) {
69
+ return {
70
+ valid: false,
71
+ error: 'License URL is required',
72
+ };
73
+ }
74
+
75
+ // FairPlay requires certificate URL
76
+ if (config.type === DRMType.FAIRPLAY) {
77
+ const certificateUrl = config.certificateUrl || config.fairplayOptions?.certificateUrl;
78
+ if (!certificateUrl) {
79
+ return {
80
+ valid: false,
81
+ error: 'FairPlay requires certificateUrl',
82
+ };
83
+ }
84
+ }
85
+
86
+ // Validate URL format
87
+ try {
88
+ new URL(config.licenseUrl);
89
+ } catch (e) {
90
+ return {
91
+ valid: false,
92
+ error: 'Invalid license URL format',
93
+ };
94
+ }
95
+
96
+ if (config.certificateUrl) {
97
+ try {
98
+ new URL(config.certificateUrl);
99
+ } catch (e) {
100
+ return {
101
+ valid: false,
102
+ error: 'Invalid certificate URL format',
103
+ };
104
+ }
105
+ }
106
+
107
+ return { valid: true };
108
+ }
109
+
110
+ /**
111
+ * Create multi-DRM config for generic provider
112
+ */
113
+ static createMultiDRMConfig(config: {
114
+ widevine: { licenseUrl: string };
115
+ fairplay: { licenseUrl: string; certificateUrl: string };
116
+ playready?: { licenseUrl: string; customData?: string };
117
+ headers?: Record<string, string>;
118
+ }): ExtendedDRMConfig {
119
+ // Primary Widevine config with FairPlay and PlayReady fallbacks
120
+ const drmConfig: ExtendedDRMConfig = {
121
+ type: DRMType.WIDEVINE,
122
+ licenseUrl: config.widevine.licenseUrl,
123
+ provider: 'generic',
124
+ headers: config.headers,
125
+
126
+ // Widevine options
127
+ widevineOptions: {
128
+ licenseUrl: config.widevine.licenseUrl,
129
+ },
130
+
131
+ // FairPlay options
132
+ fairplayOptions: {
133
+ certificateUrl: config.fairplay.certificateUrl,
134
+ licenseUrl: config.fairplay.licenseUrl,
135
+ },
136
+
137
+ // PlayReady options (optional)
138
+ playreadyOptions: config.playready
139
+ ? {
140
+ licenseUrl: config.playready.licenseUrl,
141
+ customData: config.playready.customData,
142
+ }
143
+ : undefined,
144
+ };
145
+
146
+ return drmConfig;
147
+ }
148
+ }
@@ -0,0 +1,68 @@
1
+ /**
2
+ * Base DRM System
3
+ * Abstract base class for all DRM system implementations
4
+ */
5
+
6
+ import { ExtendedDRMConfig, LicenseRequest, LicenseResponse } from '../types/DRMTypes';
7
+ import { LicenseRequestHandler } from '../utils/LicenseRequestHandler';
8
+
9
+ export abstract class BaseDRM {
10
+ protected videoElement: HTMLVideoElement;
11
+ protected config: ExtendedDRMConfig;
12
+ protected debug: boolean;
13
+ protected licenseHandler: LicenseRequestHandler;
14
+ protected mediaKeys: MediaKeys | null = null;
15
+ protected keySession: MediaKeySession | null = null;
16
+
17
+ constructor(videoElement: HTMLVideoElement, config: ExtendedDRMConfig, debug: boolean = false) {
18
+ this.videoElement = videoElement;
19
+ this.config = config;
20
+ this.debug = debug;
21
+ this.licenseHandler = new LicenseRequestHandler(config, debug);
22
+ }
23
+
24
+ /**
25
+ * Initialize DRM system
26
+ */
27
+ abstract initialize(): Promise<void>;
28
+
29
+ /**
30
+ * Get key system identifier
31
+ */
32
+ abstract getKeySystem(): string;
33
+
34
+ /**
35
+ * Get HLS.js configuration
36
+ */
37
+ abstract getHLSConfig(): any;
38
+
39
+ /**
40
+ * Get dash.js protection data
41
+ */
42
+ abstract getDashProtectionData(): any;
43
+
44
+ /**
45
+ * Cleanup resources
46
+ */
47
+ async destroy(): Promise<void> {
48
+ if (this.keySession) {
49
+ try {
50
+ await this.keySession.close();
51
+ } catch (error) {
52
+ this.log('Error closing key session:', error);
53
+ }
54
+ this.keySession = null;
55
+ }
56
+
57
+ this.mediaKeys = null;
58
+ }
59
+
60
+ /**
61
+ * Debug logging
62
+ */
63
+ protected log(...args: any[]): void {
64
+ if (this.debug) {
65
+ console.log(`[${this.constructor.name}]`, ...args);
66
+ }
67
+ }
68
+ }