unified-video-framework 1.4.380 → 1.4.381

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.
@@ -1,378 +1,378 @@
1
- import { DRMErrorCode, } from '../../core/dist/index.js';
2
- export class WebDRMProtection {
3
- constructor(videoElement) {
4
- this.mediaKeys = null;
5
- this.screenRecordingCheckInterval = null;
6
- this.castSession = null;
7
- this.castContext = null;
8
- this.KEY_SYSTEMS = {
9
- widevine: 'com.widevine.alpha',
10
- playready: 'com.microsoft.playready',
11
- clearkey: 'org.w3.clearkey',
12
- };
13
- this.videoElement = videoElement;
14
- this.config = { enabled: false };
15
- this.status = {
16
- isProtected: false,
17
- drmSystem: 'none',
18
- isScreenRecordingBlocked: false,
19
- isAudioCaptureBlocked: false,
20
- isScreenshotBlocked: false,
21
- isCasting: false,
22
- screenRecordingDetected: false,
23
- mirroringDetected: false,
24
- };
25
- }
26
- async initialize(config) {
27
- this.config = {
28
- blockScreenRecording: true,
29
- blockAudioCapture: true,
30
- blockScreenshots: true,
31
- allowCasting: true,
32
- blockMirroring: true,
33
- widevineSecurityLevel: 'L1',
34
- ...config,
35
- };
36
- if (!this.config.enabled) {
37
- console.log('[DRM] Protection disabled by configuration');
38
- return;
39
- }
40
- console.log('[DRM] Initializing web DRM protection...', this.config);
41
- try {
42
- if (!this.isEMESupported()) {
43
- throw this.createError(DRMErrorCode.DEVICE_NOT_SUPPORTED, 'Encrypted Media Extensions (EME) not supported');
44
- }
45
- if (this.config.licenseServerUrl) {
46
- await this.initializeDRMKeySystem();
47
- }
48
- if (this.config.blockScreenRecording) {
49
- this.startScreenRecordingDetection();
50
- }
51
- if (this.config.allowCasting) {
52
- await this.initializeCastSupport();
53
- }
54
- if (this.config.blockScreenshots) {
55
- this.blockScreenshots();
56
- }
57
- if (this.config.blockMirroring) {
58
- this.preventTabCapture();
59
- }
60
- this.status.isProtected = true;
61
- console.log('[DRM] Protection initialized successfully');
62
- }
63
- catch (error) {
64
- console.error('[DRM] Initialization failed:', error);
65
- this.config.onDRMError?.(error);
66
- throw error;
67
- }
68
- }
69
- isEMESupported() {
70
- return !!(window.navigator &&
71
- window.navigator.requestMediaKeySystemAccess &&
72
- window.MediaKeys);
73
- }
74
- async initializeDRMKeySystem() {
75
- console.log('[DRM] Initializing key system...');
76
- const keySystemConfigs = [
77
- {
78
- keySystem: this.KEY_SYSTEMS.widevine,
79
- licenseServerUrl: this.config.licenseServerUrl,
80
- certificateUrl: this.config.certificateUrl,
81
- headers: this.config.licenseHeaders,
82
- videoRobustness: this.config.widevineSecurityLevel === 'L1' ? 'HW_SECURE_ALL' : 'SW_SECURE_CRYPTO',
83
- audioRobustness: this.config.widevineSecurityLevel === 'L1' ? 'HW_SECURE_ALL' : 'SW_SECURE_CRYPTO',
84
- persistentState: 'optional',
85
- distinctiveIdentifier: 'optional',
86
- },
87
- {
88
- keySystem: this.KEY_SYSTEMS.playready,
89
- licenseServerUrl: this.config.licenseServerUrl,
90
- headers: this.config.licenseHeaders,
91
- videoRobustness: '3000',
92
- audioRobustness: '3000',
93
- persistentState: 'optional',
94
- distinctiveIdentifier: 'optional',
95
- },
96
- ];
97
- for (const config of keySystemConfigs) {
98
- try {
99
- await this.requestMediaKeySystemAccess(config);
100
- console.log(`[DRM] Successfully initialized ${config.keySystem}`);
101
- return;
102
- }
103
- catch (error) {
104
- console.warn(`[DRM] ${config.keySystem} not available:`, error);
105
- }
106
- }
107
- throw this.createError(DRMErrorCode.WIDEVINE_NOT_AVAILABLE, 'No supported DRM system available (tried Widevine and PlayReady)');
108
- }
109
- async requestMediaKeySystemAccess(config) {
110
- const keySystemConfig = [
111
- {
112
- initDataTypes: ['cenc', 'keyids', 'webm'],
113
- audioCapabilities: [
114
- {
115
- contentType: 'audio/mp4; codecs="mp4a.40.2"',
116
- robustness: config.audioRobustness || '',
117
- },
118
- ],
119
- videoCapabilities: [
120
- {
121
- contentType: 'video/mp4; codecs="avc1.42E01E"',
122
- robustness: config.videoRobustness || '',
123
- },
124
- {
125
- contentType: 'video/webm; codecs="vp9"',
126
- robustness: config.videoRobustness || '',
127
- },
128
- ],
129
- distinctiveIdentifier: config.distinctiveIdentifier || 'optional',
130
- persistentState: config.persistentState || 'optional',
131
- },
132
- ];
133
- const keySystemAccess = await navigator.requestMediaKeySystemAccess(config.keySystem, keySystemConfig);
134
- this.mediaKeys = await keySystemAccess.createMediaKeys();
135
- await this.videoElement.setMediaKeys(this.mediaKeys);
136
- this.setupLicenseAcquisition(config);
137
- if (config.keySystem === this.KEY_SYSTEMS.widevine) {
138
- this.status.drmSystem = 'widevine';
139
- this.status.securityLevel = config.videoRobustness === 'HW_SECURE_ALL' ? 'L1' : 'L3';
140
- }
141
- else if (config.keySystem === this.KEY_SYSTEMS.playready) {
142
- this.status.drmSystem = 'playready';
143
- }
144
- }
145
- setupLicenseAcquisition(config) {
146
- this.videoElement.addEventListener('encrypted', async (event) => {
147
- console.log('[DRM] Encrypted event received, requesting license...');
148
- try {
149
- if (!this.mediaKeys) {
150
- throw new Error('MediaKeys not initialized');
151
- }
152
- const session = this.mediaKeys.createSession();
153
- session.addEventListener('message', async (messageEvent) => {
154
- console.log('[DRM] License request message received');
155
- try {
156
- const response = await fetch(config.licenseServerUrl, {
157
- method: 'POST',
158
- headers: {
159
- 'Content-Type': 'application/octet-stream',
160
- ...config.headers,
161
- },
162
- body: messageEvent.message,
163
- });
164
- if (!response.ok) {
165
- throw this.createError(DRMErrorCode.LICENSE_REQUEST_FAILED, `License server returned ${response.status}`);
166
- }
167
- const license = await response.arrayBuffer();
168
- await session.update(license);
169
- console.log('[DRM] License acquired successfully');
170
- this.config.onLicenseAcquired?.();
171
- }
172
- catch (error) {
173
- console.error('[DRM] License acquisition failed:', error);
174
- this.config.onDRMError?.(error);
175
- }
176
- });
177
- await session.generateRequest(event.initDataType, event.initData);
178
- }
179
- catch (error) {
180
- console.error('[DRM] Failed to generate license request:', error);
181
- this.config.onDRMError?.(error);
182
- }
183
- });
184
- }
185
- startScreenRecordingDetection() {
186
- console.log('[DRM] Starting screen recording detection...');
187
- this.detectGetDisplayMedia();
188
- this.detectCanvasCapture();
189
- this.detectTabCapture();
190
- this.screenRecordingCheckInterval = window.setInterval(() => {
191
- this.analyzeScreenRecordingSignals();
192
- }, 1000);
193
- this.status.isScreenRecordingBlocked = true;
194
- }
195
- detectGetDisplayMedia() {
196
- if (!navigator.mediaDevices || !navigator.mediaDevices.getDisplayMedia) {
197
- return;
198
- }
199
- const originalGetDisplayMedia = navigator.mediaDevices.getDisplayMedia.bind(navigator.mediaDevices);
200
- navigator.mediaDevices.getDisplayMedia = async function (constraints) {
201
- console.warn('[DRM] Screen capture attempt detected via getDisplayMedia');
202
- throw new DOMException('Screen capture blocked by DRM protection', 'NotAllowedError');
203
- };
204
- }
205
- detectCanvasCapture() {
206
- const observer = new MutationObserver((mutations) => {
207
- mutations.forEach((mutation) => {
208
- if (mutation.type === 'childList') {
209
- mutation.addedNodes.forEach((node) => {
210
- if (node.nodeName === 'CANVAS') {
211
- console.warn('[DRM] Canvas element detected - potential screen capture');
212
- this.handleScreenRecordingDetected();
213
- }
214
- });
215
- }
216
- });
217
- });
218
- observer.observe(document.body, {
219
- childList: true,
220
- subtree: true,
221
- });
222
- }
223
- detectTabCapture() {
224
- if ('mediaSession' in navigator) {
225
- document.addEventListener('visibilitychange', () => {
226
- if (document.hidden) {
227
- console.log('[DRM] Tab hidden - checking for capture...');
228
- }
229
- });
230
- }
231
- }
232
- analyzeScreenRecordingSignals() {
233
- if (document.hidden && !this.videoElement.paused) {
234
- console.warn('[DRM] Video playing in hidden tab - possible screen recording');
235
- }
236
- if (this.videoElement.captureStream) {
237
- console.warn('[DRM] captureStream API available - monitoring...');
238
- }
239
- }
240
- handleScreenRecordingDetected() {
241
- console.error('[DRM] ⚠️ SCREEN RECORDING DETECTED!');
242
- this.status.screenRecordingDetected = true;
243
- this.videoElement.style.filter = 'brightness(0)';
244
- this.videoElement.pause();
245
- this.config.onScreenRecordingDetected?.();
246
- this.showProtectionWarning('Screen recording detected. Playback blocked.');
247
- }
248
- blockScreenshots() {
249
- this.videoElement.style.webkitUserSelect = 'none';
250
- this.videoElement.style.userSelect = 'none';
251
- this.videoElement.setAttribute('oncontextmenu', 'return false');
252
- this.videoElement.addEventListener('dragstart', (e) => e.preventDefault());
253
- document.addEventListener('keyup', (e) => {
254
- if (e.key === 'PrintScreen') {
255
- console.warn('[DRM] Screenshot attempt detected (PrintScreen key)');
256
- this.config.onScreenshotAttempted?.();
257
- }
258
- });
259
- this.status.isScreenshotBlocked = true;
260
- console.log('[DRM] Screenshot blocking enabled');
261
- }
262
- preventTabCapture() {
263
- if (window.screen && window.screen.isExtended) {
264
- console.warn('[DRM] Extended display detected');
265
- this.status.mirroringDetected = true;
266
- this.config.onMirroringDetected?.();
267
- }
268
- if ('presentation' in navigator) {
269
- console.log('[DRM] Monitoring presentation API for mirroring...');
270
- }
271
- }
272
- async initializeCastSupport() {
273
- if (!window.chrome || !window.chrome.cast) {
274
- console.warn('[DRM] Google Cast API not available');
275
- return;
276
- }
277
- console.log('[DRM] Initializing Chromecast support...');
278
- const script = document.createElement('script');
279
- script.src = 'https://www.gstatic.com/cv/js/sender/v1/cast_sender.js?loadCastFramework=1';
280
- document.head.appendChild(script);
281
- await new Promise((resolve) => {
282
- script.onload = resolve;
283
- });
284
- window.__onGCastApiAvailable = (isAvailable) => {
285
- if (isAvailable) {
286
- this.castContext = window.cast.framework.CastContext.getInstance();
287
- this.castContext.setOptions({
288
- receiverApplicationId: window.chrome.cast.media.DEFAULT_MEDIA_RECEIVER_APP_ID,
289
- autoJoinPolicy: window.chrome.cast.AutoJoinPolicy.ORIGIN_SCOPED,
290
- });
291
- console.log('[DRM] Chromecast initialized');
292
- }
293
- };
294
- }
295
- getStatus() {
296
- return { ...this.status };
297
- }
298
- setEnabled(enabled) {
299
- this.config.enabled = enabled;
300
- if (!enabled) {
301
- this.dispose();
302
- }
303
- }
304
- setFeature(feature, enabled) {
305
- this.config[feature] = enabled;
306
- switch (feature) {
307
- case 'blockScreenRecording':
308
- if (enabled) {
309
- this.startScreenRecordingDetection();
310
- }
311
- else if (this.screenRecordingCheckInterval) {
312
- clearInterval(this.screenRecordingCheckInterval);
313
- }
314
- break;
315
- case 'blockScreenshots':
316
- this.status.isScreenshotBlocked = enabled;
317
- break;
318
- }
319
- }
320
- async startCasting(deviceId) {
321
- if (!this.castContext) {
322
- throw new Error('Cast not initialized');
323
- }
324
- console.log('[DRM] Starting cast to device:', deviceId);
325
- this.status.isCasting = true;
326
- }
327
- async stopCasting() {
328
- if (this.castSession) {
329
- this.castSession.endSession(true);
330
- this.castSession = null;
331
- }
332
- this.status.isCasting = false;
333
- }
334
- async getAvailableCastDevices() {
335
- return [];
336
- }
337
- async renewLicense() {
338
- console.log('[DRM] Renewing license...');
339
- }
340
- showProtectionWarning(message) {
341
- const overlay = document.createElement('div');
342
- overlay.style.cssText = `
343
- position: absolute;
344
- top: 0;
345
- left: 0;
346
- width: 100%;
347
- height: 100%;
348
- background: #000;
349
- color: #fff;
350
- display: flex;
351
- align-items: center;
352
- justify-content: center;
353
- font-size: 18px;
354
- z-index: 9999999;
355
- `;
356
- overlay.textContent = message;
357
- this.videoElement.parentElement?.appendChild(overlay);
358
- }
359
- createError(code, message) {
360
- return {
361
- code,
362
- message,
363
- platform: 'web',
364
- recoverable: false,
365
- };
366
- }
367
- dispose() {
368
- if (this.screenRecordingCheckInterval) {
369
- clearInterval(this.screenRecordingCheckInterval);
370
- }
371
- if (this.castSession) {
372
- this.stopCasting();
373
- }
374
- this.status.isProtected = false;
375
- console.log('[DRM] Protection disposed');
376
- }
377
- }
1
+ import { DRMErrorCode, } from "../../core/dist/index.js";
2
+ export class WebDRMProtection {
3
+ constructor(videoElement) {
4
+ this.mediaKeys = null;
5
+ this.screenRecordingCheckInterval = null;
6
+ this.castSession = null;
7
+ this.castContext = null;
8
+ this.KEY_SYSTEMS = {
9
+ widevine: 'com.widevine.alpha',
10
+ playready: 'com.microsoft.playready',
11
+ clearkey: 'org.w3.clearkey',
12
+ };
13
+ this.videoElement = videoElement;
14
+ this.config = { enabled: false };
15
+ this.status = {
16
+ isProtected: false,
17
+ drmSystem: 'none',
18
+ isScreenRecordingBlocked: false,
19
+ isAudioCaptureBlocked: false,
20
+ isScreenshotBlocked: false,
21
+ isCasting: false,
22
+ screenRecordingDetected: false,
23
+ mirroringDetected: false,
24
+ };
25
+ }
26
+ async initialize(config) {
27
+ this.config = {
28
+ blockScreenRecording: true,
29
+ blockAudioCapture: true,
30
+ blockScreenshots: true,
31
+ allowCasting: true,
32
+ blockMirroring: true,
33
+ widevineSecurityLevel: 'L1',
34
+ ...config,
35
+ };
36
+ if (!this.config.enabled) {
37
+ console.log('[DRM] Protection disabled by configuration');
38
+ return;
39
+ }
40
+ console.log('[DRM] Initializing web DRM protection...', this.config);
41
+ try {
42
+ if (!this.isEMESupported()) {
43
+ throw this.createError(DRMErrorCode.DEVICE_NOT_SUPPORTED, 'Encrypted Media Extensions (EME) not supported');
44
+ }
45
+ if (this.config.licenseServerUrl) {
46
+ await this.initializeDRMKeySystem();
47
+ }
48
+ if (this.config.blockScreenRecording) {
49
+ this.startScreenRecordingDetection();
50
+ }
51
+ if (this.config.allowCasting) {
52
+ await this.initializeCastSupport();
53
+ }
54
+ if (this.config.blockScreenshots) {
55
+ this.blockScreenshots();
56
+ }
57
+ if (this.config.blockMirroring) {
58
+ this.preventTabCapture();
59
+ }
60
+ this.status.isProtected = true;
61
+ console.log('[DRM] Protection initialized successfully');
62
+ }
63
+ catch (error) {
64
+ console.error('[DRM] Initialization failed:', error);
65
+ this.config.onDRMError?.(error);
66
+ throw error;
67
+ }
68
+ }
69
+ isEMESupported() {
70
+ return !!(window.navigator &&
71
+ window.navigator.requestMediaKeySystemAccess &&
72
+ window.MediaKeys);
73
+ }
74
+ async initializeDRMKeySystem() {
75
+ console.log('[DRM] Initializing key system...');
76
+ const keySystemConfigs = [
77
+ {
78
+ keySystem: this.KEY_SYSTEMS.widevine,
79
+ licenseServerUrl: this.config.licenseServerUrl,
80
+ certificateUrl: this.config.certificateUrl,
81
+ headers: this.config.licenseHeaders,
82
+ videoRobustness: this.config.widevineSecurityLevel === 'L1' ? 'HW_SECURE_ALL' : 'SW_SECURE_CRYPTO',
83
+ audioRobustness: this.config.widevineSecurityLevel === 'L1' ? 'HW_SECURE_ALL' : 'SW_SECURE_CRYPTO',
84
+ persistentState: 'optional',
85
+ distinctiveIdentifier: 'optional',
86
+ },
87
+ {
88
+ keySystem: this.KEY_SYSTEMS.playready,
89
+ licenseServerUrl: this.config.licenseServerUrl,
90
+ headers: this.config.licenseHeaders,
91
+ videoRobustness: '3000',
92
+ audioRobustness: '3000',
93
+ persistentState: 'optional',
94
+ distinctiveIdentifier: 'optional',
95
+ },
96
+ ];
97
+ for (const config of keySystemConfigs) {
98
+ try {
99
+ await this.requestMediaKeySystemAccess(config);
100
+ console.log(`[DRM] Successfully initialized ${config.keySystem}`);
101
+ return;
102
+ }
103
+ catch (error) {
104
+ console.warn(`[DRM] ${config.keySystem} not available:`, error);
105
+ }
106
+ }
107
+ throw this.createError(DRMErrorCode.WIDEVINE_NOT_AVAILABLE, 'No supported DRM system available (tried Widevine and PlayReady)');
108
+ }
109
+ async requestMediaKeySystemAccess(config) {
110
+ const keySystemConfig = [
111
+ {
112
+ initDataTypes: ['cenc', 'keyids', 'webm'],
113
+ audioCapabilities: [
114
+ {
115
+ contentType: 'audio/mp4; codecs="mp4a.40.2"',
116
+ robustness: config.audioRobustness || '',
117
+ },
118
+ ],
119
+ videoCapabilities: [
120
+ {
121
+ contentType: 'video/mp4; codecs="avc1.42E01E"',
122
+ robustness: config.videoRobustness || '',
123
+ },
124
+ {
125
+ contentType: 'video/webm; codecs="vp9"',
126
+ robustness: config.videoRobustness || '',
127
+ },
128
+ ],
129
+ distinctiveIdentifier: config.distinctiveIdentifier || 'optional',
130
+ persistentState: config.persistentState || 'optional',
131
+ },
132
+ ];
133
+ const keySystemAccess = await navigator.requestMediaKeySystemAccess(config.keySystem, keySystemConfig);
134
+ this.mediaKeys = await keySystemAccess.createMediaKeys();
135
+ await this.videoElement.setMediaKeys(this.mediaKeys);
136
+ this.setupLicenseAcquisition(config);
137
+ if (config.keySystem === this.KEY_SYSTEMS.widevine) {
138
+ this.status.drmSystem = 'widevine';
139
+ this.status.securityLevel = config.videoRobustness === 'HW_SECURE_ALL' ? 'L1' : 'L3';
140
+ }
141
+ else if (config.keySystem === this.KEY_SYSTEMS.playready) {
142
+ this.status.drmSystem = 'playready';
143
+ }
144
+ }
145
+ setupLicenseAcquisition(config) {
146
+ this.videoElement.addEventListener('encrypted', async (event) => {
147
+ console.log('[DRM] Encrypted event received, requesting license...');
148
+ try {
149
+ if (!this.mediaKeys) {
150
+ throw new Error('MediaKeys not initialized');
151
+ }
152
+ const session = this.mediaKeys.createSession();
153
+ session.addEventListener('message', async (messageEvent) => {
154
+ console.log('[DRM] License request message received');
155
+ try {
156
+ const response = await fetch(config.licenseServerUrl, {
157
+ method: 'POST',
158
+ headers: {
159
+ 'Content-Type': 'application/octet-stream',
160
+ ...config.headers,
161
+ },
162
+ body: messageEvent.message,
163
+ });
164
+ if (!response.ok) {
165
+ throw this.createError(DRMErrorCode.LICENSE_REQUEST_FAILED, `License server returned ${response.status}`);
166
+ }
167
+ const license = await response.arrayBuffer();
168
+ await session.update(license);
169
+ console.log('[DRM] License acquired successfully');
170
+ this.config.onLicenseAcquired?.();
171
+ }
172
+ catch (error) {
173
+ console.error('[DRM] License acquisition failed:', error);
174
+ this.config.onDRMError?.(error);
175
+ }
176
+ });
177
+ await session.generateRequest(event.initDataType, event.initData);
178
+ }
179
+ catch (error) {
180
+ console.error('[DRM] Failed to generate license request:', error);
181
+ this.config.onDRMError?.(error);
182
+ }
183
+ });
184
+ }
185
+ startScreenRecordingDetection() {
186
+ console.log('[DRM] Starting screen recording detection...');
187
+ this.detectGetDisplayMedia();
188
+ this.detectCanvasCapture();
189
+ this.detectTabCapture();
190
+ this.screenRecordingCheckInterval = window.setInterval(() => {
191
+ this.analyzeScreenRecordingSignals();
192
+ }, 1000);
193
+ this.status.isScreenRecordingBlocked = true;
194
+ }
195
+ detectGetDisplayMedia() {
196
+ if (!navigator.mediaDevices || !navigator.mediaDevices.getDisplayMedia) {
197
+ return;
198
+ }
199
+ const originalGetDisplayMedia = navigator.mediaDevices.getDisplayMedia.bind(navigator.mediaDevices);
200
+ navigator.mediaDevices.getDisplayMedia = async function (constraints) {
201
+ console.warn('[DRM] Screen capture attempt detected via getDisplayMedia');
202
+ throw new DOMException('Screen capture blocked by DRM protection', 'NotAllowedError');
203
+ };
204
+ }
205
+ detectCanvasCapture() {
206
+ const observer = new MutationObserver((mutations) => {
207
+ mutations.forEach((mutation) => {
208
+ if (mutation.type === 'childList') {
209
+ mutation.addedNodes.forEach((node) => {
210
+ if (node.nodeName === 'CANVAS') {
211
+ console.warn('[DRM] Canvas element detected - potential screen capture');
212
+ this.handleScreenRecordingDetected();
213
+ }
214
+ });
215
+ }
216
+ });
217
+ });
218
+ observer.observe(document.body, {
219
+ childList: true,
220
+ subtree: true,
221
+ });
222
+ }
223
+ detectTabCapture() {
224
+ if ('mediaSession' in navigator) {
225
+ document.addEventListener('visibilitychange', () => {
226
+ if (document.hidden) {
227
+ console.log('[DRM] Tab hidden - checking for capture...');
228
+ }
229
+ });
230
+ }
231
+ }
232
+ analyzeScreenRecordingSignals() {
233
+ if (document.hidden && !this.videoElement.paused) {
234
+ console.warn('[DRM] Video playing in hidden tab - possible screen recording');
235
+ }
236
+ if (this.videoElement.captureStream) {
237
+ console.warn('[DRM] captureStream API available - monitoring...');
238
+ }
239
+ }
240
+ handleScreenRecordingDetected() {
241
+ console.error('[DRM] ⚠️ SCREEN RECORDING DETECTED!');
242
+ this.status.screenRecordingDetected = true;
243
+ this.videoElement.style.filter = 'brightness(0)';
244
+ this.videoElement.pause();
245
+ this.config.onScreenRecordingDetected?.();
246
+ this.showProtectionWarning('Screen recording detected. Playback blocked.');
247
+ }
248
+ blockScreenshots() {
249
+ this.videoElement.style.webkitUserSelect = 'none';
250
+ this.videoElement.style.userSelect = 'none';
251
+ this.videoElement.setAttribute('oncontextmenu', 'return false');
252
+ this.videoElement.addEventListener('dragstart', (e) => e.preventDefault());
253
+ document.addEventListener('keyup', (e) => {
254
+ if (e.key === 'PrintScreen') {
255
+ console.warn('[DRM] Screenshot attempt detected (PrintScreen key)');
256
+ this.config.onScreenshotAttempted?.();
257
+ }
258
+ });
259
+ this.status.isScreenshotBlocked = true;
260
+ console.log('[DRM] Screenshot blocking enabled');
261
+ }
262
+ preventTabCapture() {
263
+ if (window.screen && window.screen.isExtended) {
264
+ console.warn('[DRM] Extended display detected');
265
+ this.status.mirroringDetected = true;
266
+ this.config.onMirroringDetected?.();
267
+ }
268
+ if ('presentation' in navigator) {
269
+ console.log('[DRM] Monitoring presentation API for mirroring...');
270
+ }
271
+ }
272
+ async initializeCastSupport() {
273
+ if (!window.chrome || !window.chrome.cast) {
274
+ console.warn('[DRM] Google Cast API not available');
275
+ return;
276
+ }
277
+ console.log('[DRM] Initializing Chromecast support...');
278
+ const script = document.createElement('script');
279
+ script.src = 'https://www.gstatic.com/cv/js/sender/v1/cast_sender.js?loadCastFramework=1';
280
+ document.head.appendChild(script);
281
+ await new Promise((resolve) => {
282
+ script.onload = resolve;
283
+ });
284
+ window.__onGCastApiAvailable = (isAvailable) => {
285
+ if (isAvailable) {
286
+ this.castContext = window.cast.framework.CastContext.getInstance();
287
+ this.castContext.setOptions({
288
+ receiverApplicationId: window.chrome.cast.media.DEFAULT_MEDIA_RECEIVER_APP_ID,
289
+ autoJoinPolicy: window.chrome.cast.AutoJoinPolicy.ORIGIN_SCOPED,
290
+ });
291
+ console.log('[DRM] Chromecast initialized');
292
+ }
293
+ };
294
+ }
295
+ getStatus() {
296
+ return { ...this.status };
297
+ }
298
+ setEnabled(enabled) {
299
+ this.config.enabled = enabled;
300
+ if (!enabled) {
301
+ this.dispose();
302
+ }
303
+ }
304
+ setFeature(feature, enabled) {
305
+ this.config[feature] = enabled;
306
+ switch (feature) {
307
+ case 'blockScreenRecording':
308
+ if (enabled) {
309
+ this.startScreenRecordingDetection();
310
+ }
311
+ else if (this.screenRecordingCheckInterval) {
312
+ clearInterval(this.screenRecordingCheckInterval);
313
+ }
314
+ break;
315
+ case 'blockScreenshots':
316
+ this.status.isScreenshotBlocked = enabled;
317
+ break;
318
+ }
319
+ }
320
+ async startCasting(deviceId) {
321
+ if (!this.castContext) {
322
+ throw new Error('Cast not initialized');
323
+ }
324
+ console.log('[DRM] Starting cast to device:', deviceId);
325
+ this.status.isCasting = true;
326
+ }
327
+ async stopCasting() {
328
+ if (this.castSession) {
329
+ this.castSession.endSession(true);
330
+ this.castSession = null;
331
+ }
332
+ this.status.isCasting = false;
333
+ }
334
+ async getAvailableCastDevices() {
335
+ return [];
336
+ }
337
+ async renewLicense() {
338
+ console.log('[DRM] Renewing license...');
339
+ }
340
+ showProtectionWarning(message) {
341
+ const overlay = document.createElement('div');
342
+ overlay.style.cssText = `
343
+ position: absolute;
344
+ top: 0;
345
+ left: 0;
346
+ width: 100%;
347
+ height: 100%;
348
+ background: #000;
349
+ color: #fff;
350
+ display: flex;
351
+ align-items: center;
352
+ justify-content: center;
353
+ font-size: 18px;
354
+ z-index: 9999999;
355
+ `;
356
+ overlay.textContent = message;
357
+ this.videoElement.parentElement?.appendChild(overlay);
358
+ }
359
+ createError(code, message) {
360
+ return {
361
+ code,
362
+ message,
363
+ platform: 'web',
364
+ recoverable: false,
365
+ };
366
+ }
367
+ dispose() {
368
+ if (this.screenRecordingCheckInterval) {
369
+ clearInterval(this.screenRecordingCheckInterval);
370
+ }
371
+ if (this.castSession) {
372
+ this.stopCasting();
373
+ }
374
+ this.status.isProtected = false;
375
+ console.log('[DRM] Protection disposed');
376
+ }
377
+ }
378
378
  //# sourceMappingURL=WebDRMProtection.js.map