@adstage/web-sdk 1.3.4 → 2.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 (60) hide show
  1. package/README.md +539 -34
  2. package/dist/index.cjs.js +753 -509
  3. package/dist/index.d.ts +286 -97
  4. package/dist/index.esm.js +737 -485
  5. package/dist/index.standalone.js +737 -485
  6. package/package.json +12 -13
  7. package/src/constants/endpoints.ts +93 -0
  8. package/src/core/AdStage.ts +128 -0
  9. package/src/index.ts +14 -432
  10. package/src/managers/{slider-manager.ts → carousel-slider-manager.ts} +9 -8
  11. package/src/managers/event-tracker.ts +2 -4
  12. package/src/managers/{fade-slider-manager.ts → text-transition-manager.ts} +7 -7
  13. package/src/modules/ads/AdsModule.ts +525 -0
  14. package/src/modules/config/ConfigModule.ts +124 -0
  15. package/src/modules/events/EventsModule.ts +106 -0
  16. package/src/types/config.ts +74 -3
  17. package/src/types/index.ts +2 -1
  18. package/src/utils/api-headers.ts +52 -0
  19. package/src/utils/dom-utils.ts +1 -1
  20. package/examples/README.md +0 -33
  21. package/examples/banner-ads.html +0 -512
  22. package/examples/index.html +0 -338
  23. package/examples/native-ads.html +0 -634
  24. package/examples/react-app/README.md +0 -70
  25. package/examples/react-app/index.html +0 -13
  26. package/examples/react-app/package-lock.json +0 -3042
  27. package/examples/react-app/package.json +0 -26
  28. package/examples/react-app/pnpm-lock.yaml +0 -1857
  29. package/examples/react-app/public/index.standalone.js +0 -2331
  30. package/examples/react-app/src/App.tsx +0 -226
  31. package/examples/react-app/src/index.css +0 -37
  32. package/examples/react-app/src/main.tsx +0 -10
  33. package/examples/react-app/tsconfig.json +0 -25
  34. package/examples/react-app/tsconfig.node.json +0 -10
  35. package/examples/react-app/vite.config.ts +0 -15
  36. package/examples/react-nextjs/app/globals.css +0 -200
  37. package/examples/react-nextjs/app/layout.tsx +0 -27
  38. package/examples/react-nextjs/app/page.tsx +0 -258
  39. package/examples/react-nextjs/next.config.js +0 -9
  40. package/examples/react-nextjs/package.json +0 -22
  41. package/examples/react-nextjs/pnpm-lock.yaml +0 -343
  42. package/examples/react-nextjs/tsconfig.json +0 -34
  43. package/examples/text-ads.html +0 -597
  44. package/examples/video-ads.html +0 -739
  45. package/src/react/components/AdErrorBoundary.tsx +0 -75
  46. package/src/react/components/AdSlot.tsx +0 -144
  47. package/src/react/components/BannerAd.tsx +0 -24
  48. package/src/react/components/InterstitialAd.tsx +0 -24
  49. package/src/react/components/NativeAd.tsx +0 -24
  50. package/src/react/components/TextAd.tsx +0 -24
  51. package/src/react/components/VideoAd.tsx +0 -24
  52. package/src/react/components/index.ts +0 -8
  53. package/src/react/hooks/index.ts +0 -4
  54. package/src/react/hooks/useAdSlot.ts +0 -83
  55. package/src/react/hooks/useAdStage.ts +0 -14
  56. package/src/react/hooks/useAdTracking.ts +0 -61
  57. package/src/react/index.ts +0 -4
  58. package/src/react/providers/AdStageProvider.tsx +0 -86
  59. package/src/react/providers/index.ts +0 -2
  60. package/src/utils/sdk-standalone.ts +0 -155
@@ -1,739 +0,0 @@
1
- <!DOCTYPE html>
2
- <html lang="ko">
3
- <head>
4
- <meta charset="UTF-8">
5
- <meta name="viewport" content="width=device-width, initial-scale=1.0">
6
- <title>비디오 광고 예제 - AdStage SDK</title>
7
- <style>
8
- * {
9
- box-sizing: border-box;
10
- margin: 0;
11
- padding: 0;
12
- }
13
-
14
- body {
15
- font-family: -apple-system, BlinkMacSystemFont, 'Segoe UI', 'Roboto', sans-serif;
16
- line-height: 1.6;
17
- color: #333;
18
- background: #f8f9fa;
19
- padding: 20px;
20
- }
21
-
22
- .container {
23
- max-width: 1200px;
24
- margin: 0 auto;
25
- background: white;
26
- border-radius: 12px;
27
- box-shadow: 0 4px 12px rgba(0,0,0,0.1);
28
- overflow: hidden;
29
- }
30
-
31
- .header {
32
- background: linear-gradient(135deg, #fd7e14, #dc3545);
33
- color: white;
34
- padding: 30px;
35
- text-align: center;
36
- }
37
-
38
- .header h1 {
39
- font-size: 2rem;
40
- margin-bottom: 10px;
41
- }
42
-
43
- .nav {
44
- background: #f8f9fa;
45
- padding: 15px 30px;
46
- border-bottom: 1px solid #dee2e6;
47
- }
48
-
49
- .back-link {
50
- color: #fd7e14;
51
- text-decoration: none;
52
- font-weight: 500;
53
- }
54
-
55
- .content {
56
- padding: 30px;
57
- }
58
-
59
- .section {
60
- margin-bottom: 40px;
61
- }
62
-
63
- .section h2 {
64
- color: #495057;
65
- margin-bottom: 20px;
66
- padding-bottom: 10px;
67
- border-bottom: 2px solid #fd7e14;
68
- }
69
-
70
- .video-grid {
71
- display: grid;
72
- grid-template-columns: repeat(auto-fit, minmax(350px, 1fr));
73
- gap: 25px;
74
- margin-bottom: 30px;
75
- }
76
-
77
- .video-container {
78
- border: 2px solid #e9ecef;
79
- border-radius: 12px;
80
- overflow: hidden;
81
- background: #f8f9fa;
82
- transition: all 0.3s ease;
83
- }
84
-
85
- .video-container:hover {
86
- border-color: #fd7e14;
87
- box-shadow: 0 4px 12px rgba(253, 126, 20, 0.15);
88
- }
89
-
90
- .video-container h3 {
91
- padding: 15px 20px;
92
- margin: 0;
93
- color: #fd7e14;
94
- font-size: 1.1rem;
95
- background: white;
96
- border-bottom: 1px solid #e9ecef;
97
- }
98
-
99
- .video-ad-slot {
100
- width: 100%;
101
- height: 250px;
102
- background: #000;
103
- display: flex;
104
- align-items: center;
105
- justify-content: center;
106
- position: relative;
107
- overflow: hidden;
108
- }
109
-
110
- .video-ad-slot.loading::before {
111
- content: "🎬 비디오 광고 로딩 중...";
112
- color: white;
113
- font-size: 1rem;
114
- z-index: 10;
115
- }
116
-
117
- .video-player {
118
- width: 100%;
119
- height: 100%;
120
- background: linear-gradient(45deg, #fd7e14, #dc3545);
121
- display: flex;
122
- flex-direction: column;
123
- align-items: center;
124
- justify-content: center;
125
- color: white;
126
- cursor: pointer;
127
- position: relative;
128
- transition: all 0.3s ease;
129
- }
130
-
131
- .video-player:hover {
132
- background: linear-gradient(45deg, #e8690b, #c82333);
133
- }
134
-
135
- .play-button {
136
- width: 60px;
137
- height: 60px;
138
- background: rgba(255,255,255,0.2);
139
- border-radius: 50%;
140
- display: flex;
141
- align-items: center;
142
- justify-content: center;
143
- font-size: 24px;
144
- margin-bottom: 15px;
145
- transition: all 0.3s ease;
146
- }
147
-
148
- .play-button:hover {
149
- background: rgba(255,255,255,0.3);
150
- transform: scale(1.1);
151
- }
152
-
153
- .video-title {
154
- font-size: 1.1rem;
155
- font-weight: 600;
156
- text-align: center;
157
- margin-bottom: 8px;
158
- }
159
-
160
- .video-duration {
161
- font-size: 0.9rem;
162
- opacity: 0.8;
163
- }
164
-
165
- .video-overlay {
166
- position: absolute;
167
- top: 10px;
168
- right: 10px;
169
- background: rgba(0,0,0,0.7);
170
- color: white;
171
- padding: 4px 8px;
172
- border-radius: 12px;
173
- font-size: 0.8rem;
174
- }
175
-
176
- .video-controls {
177
- position: absolute;
178
- bottom: 10px;
179
- left: 10px;
180
- right: 10px;
181
- display: flex;
182
- justify-content: space-between;
183
- align-items: center;
184
- }
185
-
186
- .video-progress {
187
- flex: 1;
188
- height: 4px;
189
- background: rgba(255,255,255,0.3);
190
- border-radius: 2px;
191
- margin: 0 10px;
192
- overflow: hidden;
193
- }
194
-
195
- .progress-bar {
196
- height: 100%;
197
- background: white;
198
- width: 0%;
199
- transition: width 0.3s ease;
200
- }
201
-
202
- .ad-info {
203
- padding: 15px 20px;
204
- background: white;
205
- font-size: 0.9rem;
206
- color: #6c757d;
207
- border-bottom: 1px solid #e9ecef;
208
- }
209
-
210
- .controls {
211
- padding: 15px 20px;
212
- background: white;
213
- display: flex;
214
- gap: 10px;
215
- flex-wrap: wrap;
216
- }
217
-
218
- .btn {
219
- padding: 8px 16px;
220
- border: none;
221
- border-radius: 6px;
222
- background: #fd7e14;
223
- color: white;
224
- cursor: pointer;
225
- font-size: 0.9rem;
226
- transition: background 0.3s ease;
227
- }
228
-
229
- .btn:hover {
230
- background: #e8690b;
231
- }
232
-
233
- .btn.secondary {
234
- background: #6c757d;
235
- }
236
-
237
- .btn.secondary:hover {
238
- background: #5a6268;
239
- }
240
-
241
- .btn.small {
242
- padding: 6px 12px;
243
- font-size: 0.8rem;
244
- }
245
-
246
- .interstitial-container {
247
- position: fixed;
248
- top: 0;
249
- left: 0;
250
- width: 100%;
251
- height: 100%;
252
- background: rgba(0,0,0,0.9);
253
- display: none;
254
- align-items: center;
255
- justify-content: center;
256
- z-index: 1000;
257
- }
258
-
259
- .interstitial-content {
260
- width: 90%;
261
- max-width: 600px;
262
- height: 70%;
263
- background: linear-gradient(45deg, #fd7e14, #dc3545);
264
- border-radius: 12px;
265
- display: flex;
266
- flex-direction: column;
267
- align-items: center;
268
- justify-content: center;
269
- color: white;
270
- position: relative;
271
- }
272
-
273
- .close-button {
274
- position: absolute;
275
- top: 15px;
276
- right: 15px;
277
- background: rgba(255,255,255,0.2);
278
- border: none;
279
- color: white;
280
- width: 30px;
281
- height: 30px;
282
- border-radius: 50%;
283
- cursor: pointer;
284
- font-size: 18px;
285
- }
286
-
287
- .status {
288
- margin-top: 30px;
289
- padding: 20px;
290
- background: #fff3cd;
291
- border-left: 4px solid #fd7e14;
292
- border-radius: 4px;
293
- }
294
-
295
- .log {
296
- background: #f8f9fa;
297
- border: 1px solid #dee2e6;
298
- border-radius: 6px;
299
- padding: 15px;
300
- max-height: 200px;
301
- overflow-y: auto;
302
- font-family: monospace;
303
- font-size: 0.8rem;
304
- margin-top: 15px;
305
- }
306
-
307
- .log-entry {
308
- margin-bottom: 5px;
309
- padding: 2px 5px;
310
- border-radius: 3px;
311
- }
312
-
313
- .log-entry.info {
314
- background: #d4edda;
315
- color: #155724;
316
- }
317
-
318
- .log-entry.warn {
319
- background: #fff3cd;
320
- color: #856404;
321
- }
322
-
323
- .log-entry.error {
324
- background: #f8d7da;
325
- color: #721c24;
326
- }
327
-
328
- .video-playing {
329
- animation: pulse 2s infinite;
330
- }
331
-
332
- @keyframes pulse {
333
- 0% { opacity: 1; }
334
- 50% { opacity: 0.8; }
335
- 100% { opacity: 1; }
336
- }
337
-
338
- .sponsored-overlay {
339
- position: absolute;
340
- top: 0;
341
- left: 0;
342
- background: rgba(253, 126, 20, 0.9);
343
- color: white;
344
- padding: 4px 8px;
345
- font-size: 0.7rem;
346
- font-weight: 600;
347
- }
348
- </style>
349
- </head>
350
- <body>
351
- <div class="container">
352
- <div class="header">
353
- <h1>🎬 비디오 광고 예제</h1>
354
- <p>다양한 형태의 비디오 광고 표시 및 제어</p>
355
- </div>
356
-
357
- <div class="nav">
358
- <a href="index.html" class="back-link">← 메인 페이지로 돌아가기</a>
359
- </div>
360
-
361
- <div class="content">
362
- <div class="section">
363
- <h2>🎥 인스트림 비디오 광고</h2>
364
- <p style="margin-bottom: 20px; color: #6c757d;">콘텐츠 재생 전, 중간, 후에 표시되는 비디오 광고</p>
365
-
366
- <div class="video-grid">
367
- <div class="video-container">
368
- <h3>프리롤 광고 (Pre-roll)</h3>
369
- <div class="video-ad-slot loading"
370
- id="preroll-video"
371
- adstage="preroll-video"
372
- ad-type="VIDEO">
373
- <div class="video-player" onclick="playVideo('preroll-video')">
374
- <div class="sponsored-overlay">스폰서</div>
375
- <div class="play-button">▶</div>
376
- <div class="video-title">새로운 스마트워치 런칭!</div>
377
- <div class="video-duration">30초</div>
378
- <div class="video-overlay">HD</div>
379
- <div class="video-controls">
380
- <div class="video-progress">
381
- <div class="progress-bar" id="progress-preroll"></div>
382
- </div>
383
- </div>
384
- </div>
385
- </div>
386
- <div class="ad-info">
387
- 슬롯 ID: preroll-video<br>
388
- 타입: 프리롤 (콘텐츠 재생 전)<br>
389
- 길이: 30초 • 건너뛰기: 5초 후
390
- </div>
391
- <div class="controls">
392
- <button class="btn small" onclick="playVideo('preroll-video')">▶ 재생</button>
393
- <button class="btn small secondary" onclick="pauseVideo('preroll-video')">⏸ 일시정지</button>
394
- <button class="btn small secondary" onclick="skipVideo('preroll-video')">⏭ 건너뛰기</button>
395
- </div>
396
- </div>
397
-
398
- <div class="video-container">
399
- <h3>미드롤 광고 (Mid-roll)</h3>
400
- <div class="video-ad-slot loading"
401
- id="midroll-video"
402
- adstage="midroll-video"
403
- ad-type="VIDEO">
404
- <div class="video-player" onclick="playVideo('midroll-video')">
405
- <div class="sponsored-overlay">스폰서</div>
406
- <div class="play-button">▶</div>
407
- <div class="video-title">온라인 교육 플랫폼</div>
408
- <div class="video-duration">15초</div>
409
- <div class="video-overlay">4K</div>
410
- <div class="video-controls">
411
- <div class="video-progress">
412
- <div class="progress-bar" id="progress-midroll"></div>
413
- </div>
414
- </div>
415
- </div>
416
- </div>
417
- <div class="ad-info">
418
- 슬롯 ID: midroll-video<br>
419
- 타입: 미드롤 (콘텐츠 중간)<br>
420
- 길이: 15초 • 건너뛰기: 불가
421
- </div>
422
- <div class="controls">
423
- <button class="btn small" onclick="playVideo('midroll-video')">▶ 재생</button>
424
- <button class="btn small secondary" onclick="pauseVideo('midroll-video')">⏸ 일시정지</button>
425
- <button class="btn small secondary" onclick="muteVideo('midroll-video')">🔇 음소거</button>
426
- </div>
427
- </div>
428
-
429
- <div class="video-container">
430
- <h3>포스트롤 광고 (Post-roll)</h3>
431
- <div class="video-ad-slot loading"
432
- id="postroll-video"
433
- adstage="postroll-video"
434
- ad-type="VIDEO">
435
- <div class="video-player" onclick="playVideo('postroll-video')">
436
- <div class="sponsored-overlay">스폰서</div>
437
- <div class="play-button">▶</div>
438
- <div class="video-title">프리미엄 구독 서비스</div>
439
- <div class="video-duration">20초</div>
440
- <div class="video-overlay">AUTO</div>
441
- <div class="video-controls">
442
- <div class="video-progress">
443
- <div class="progress-bar" id="progress-postroll"></div>
444
- </div>
445
- </div>
446
- </div>
447
- </div>
448
- <div class="ad-info">
449
- 슬롯 ID: postroll-video<br>
450
- 타입: 포스트롤 (콘텐츠 종료 후)<br>
451
- 길이: 20초 • 건너뛰기: 즉시 가능
452
- </div>
453
- <div class="controls">
454
- <button class="btn small" onclick="playVideo('postroll-video')">▶ 재생</button>
455
- <button class="btn small secondary" onclick="pauseVideo('postroll-video')">⏸ 일시정지</button>
456
- <button class="btn small secondary" onclick="replayVideo('postroll-video')">🔄 다시보기</button>
457
- </div>
458
- </div>
459
-
460
- <div class="video-container">
461
- <h3>오버레이 비디오 광고</h3>
462
- <div class="video-ad-slot loading"
463
- id="overlay-video"
464
- adstage="overlay-video"
465
- ad-type="VIDEO">
466
- <div class="video-player" onclick="playVideo('overlay-video')">
467
- <div class="sponsored-overlay">스폰서</div>
468
- <div class="play-button">▶</div>
469
- <div class="video-title">모바일 게임 신작</div>
470
- <div class="video-duration">25초</div>
471
- <div class="video-overlay">LIVE</div>
472
- <div class="video-controls">
473
- <div class="video-progress">
474
- <div class="progress-bar" id="progress-overlay"></div>
475
- </div>
476
- </div>
477
- </div>
478
- </div>
479
- <div class="ad-info">
480
- 슬롯 ID: overlay-video<br>
481
- 타입: 오버레이 (콘텐츠 위에 표시)<br>
482
- 길이: 25초 • 반투명 배경
483
- </div>
484
- <div class="controls">
485
- <button class="btn small" onclick="playVideo('overlay-video')">▶ 재생</button>
486
- <button class="btn small secondary" onclick="pauseVideo('overlay-video')">⏸ 일시정지</button>
487
- <button class="btn small secondary" onclick="closeOverlay('overlay-video')">✕ 닫기</button>
488
- </div>
489
- </div>
490
- </div>
491
- </div>
492
-
493
- <div class="section">
494
- <h2>🖼️ 전면 광고 (Interstitial)</h2>
495
- <p style="margin-bottom: 20px; color: #6c757d;">화면 전체를 덮는 전면 비디오 광고</p>
496
-
497
- <div style="text-align: center;">
498
- <button class="btn" onclick="showInterstitial()" style="font-size: 1.1rem; padding: 15px 30px;">
499
- 🎬 전면 비디오 광고 표시
500
- </button>
501
- <p style="margin-top: 10px; color: #6c757d; font-size: 0.9rem;">
502
- 페이지 전환이나 앱 시작 시 표시되는 전면 광고
503
- </p>
504
- </div>
505
- </div>
506
-
507
- <div class="section">
508
- <h2>⚡ 전체 제어</h2>
509
- <div class="controls">
510
- <button class="btn" onclick="playAllVideos()">▶ 모든 비디오 재생</button>
511
- <button class="btn secondary" onclick="pauseAllVideos()">⏸ 모든 비디오 일시정지</button>
512
- <button class="btn secondary" onclick="muteAllVideos()">🔇 전체 음소거</button>
513
- <button class="btn" onclick="refreshAllVideoAds()">🔄 비디오 광고 새로고침</button>
514
- <button class="btn secondary" onclick="clearLog()">🧹 로그 지우기</button>
515
- </div>
516
- </div>
517
-
518
- <div class="status" id="status">
519
- SDK 초기화 중...
520
- </div>
521
-
522
- <div class="log" id="log">
523
- <div class="log-entry info">비디오 광고 페이지 로드 시작...</div>
524
- </div>
525
- </div>
526
- </div>
527
-
528
- <!-- 전면 광고 컨테이너 -->
529
- <div class="interstitial-container" id="interstitial">
530
- <div class="interstitial-content"
531
- id="interstitial-video"
532
- adstage="interstitial-video"
533
- ad-type="VIDEO">
534
- <button class="close-button" onclick="closeInterstitial()">✕</button>
535
- <div class="sponsored-overlay">스폰서</div>
536
- <div class="play-button" onclick="playInterstitialVideo()">▶</div>
537
- <div class="video-title">전면 비디오 광고</div>
538
- <div class="video-duration">30초</div>
539
- <div style="margin-top: 20px; text-align: center;">
540
- <button class="btn" onclick="playInterstitialVideo()">비디오 재생</button>
541
- <button class="btn secondary" onclick="closeInterstitial()" style="margin-left: 10px;">건너뛰기</button>
542
- </div>
543
- </div>
544
- </div>
545
-
546
- <script type="module">
547
- import AdStageSDK, { AdType } from './dist/index.standalone.js';
548
-
549
- const statusEl = document.getElementById('status');
550
- const logEl = document.getElementById('log');
551
- let videoStates = {};
552
-
553
- function addLog(message, type = 'info') {
554
- const timestamp = new Date().toLocaleTimeString();
555
- const logEntry = document.createElement('div');
556
- logEntry.className = `log-entry ${type}`;
557
- logEntry.textContent = `[${timestamp}] ${message}`;
558
- logEl.appendChild(logEntry);
559
- logEl.scrollTop = logEl.scrollHeight;
560
- }
561
-
562
- // 비디오 제어 함수들
563
- window.playVideo = function(slotId) {
564
- addLog(`비디오 재생 시작: ${slotId}`, 'info');
565
- const slot = document.getElementById(slotId);
566
- const player = slot.querySelector('.video-player');
567
- const progressBar = document.getElementById(`progress-${slotId}`);
568
-
569
- if (player) {
570
- player.classList.add('video-playing');
571
-
572
- // 진행률 시뮬레이션
573
- let progress = 0;
574
- const interval = setInterval(() => {
575
- progress += 2;
576
- if (progressBar) {
577
- progressBar.style.width = progress + '%';
578
- }
579
-
580
- if (progress >= 100) {
581
- clearInterval(interval);
582
- player.classList.remove('video-playing');
583
- addLog(`비디오 재생 완료: ${slotId}`, 'info');
584
-
585
- // 5초 후 리셋
586
- setTimeout(() => {
587
- if (progressBar) progressBar.style.width = '0%';
588
- }, 2000);
589
- }
590
- }, 100);
591
-
592
- videoStates[slotId] = { interval, progress };
593
- }
594
- };
595
-
596
- window.pauseVideo = function(slotId) {
597
- addLog(`비디오 일시정지: ${slotId}`, 'info');
598
- const player = document.getElementById(slotId)?.querySelector('.video-player');
599
- if (player) {
600
- player.classList.remove('video-playing');
601
-
602
- if (videoStates[slotId]?.interval) {
603
- clearInterval(videoStates[slotId].interval);
604
- }
605
- }
606
- };
607
-
608
- window.skipVideo = function(slotId) {
609
- addLog(`비디오 건너뛰기: ${slotId}`, 'info');
610
- pauseVideo(slotId);
611
- const progressBar = document.getElementById(`progress-${slotId}`);
612
- if (progressBar) {
613
- progressBar.style.width = '100%';
614
- setTimeout(() => progressBar.style.width = '0%', 1000);
615
- }
616
- };
617
-
618
- window.muteVideo = function(slotId) {
619
- addLog(`비디오 음소거: ${slotId}`, 'info');
620
- // 실제 구현에서는 비디오 요소의 muted 속성 조작
621
- };
622
-
623
- window.replayVideo = function(slotId) {
624
- addLog(`비디오 다시보기: ${slotId}`, 'info');
625
- const progressBar = document.getElementById(`progress-${slotId}`);
626
- if (progressBar) progressBar.style.width = '0%';
627
- setTimeout(() => playVideo(slotId), 500);
628
- };
629
-
630
- window.closeOverlay = function(slotId) {
631
- addLog(`오버레이 광고 닫기: ${slotId}`, 'info');
632
- const slot = document.getElementById(slotId);
633
- if (slot) {
634
- slot.style.opacity = '0.5';
635
- setTimeout(() => slot.style.opacity = '1', 2000);
636
- }
637
- };
638
-
639
- // 전면 광고 제어
640
- window.showInterstitial = function() {
641
- addLog('전면 비디오 광고 표시', 'info');
642
- document.getElementById('interstitial').style.display = 'flex';
643
- };
644
-
645
- window.closeInterstitial = function() {
646
- addLog('전면 비디오 광고 닫기', 'info');
647
- document.getElementById('interstitial').style.display = 'none';
648
- };
649
-
650
- window.playInterstitialVideo = function() {
651
- addLog('전면 비디오 재생', 'info');
652
- const content = document.querySelector('.interstitial-content');
653
- content.style.animation = 'pulse 2s infinite';
654
-
655
- setTimeout(() => {
656
- content.style.animation = '';
657
- addLog('전면 비디오 재생 완료', 'info');
658
- }, 5000);
659
- };
660
-
661
- // 전체 제어 함수들
662
- window.playAllVideos = function() {
663
- const slots = ['preroll-video', 'midroll-video', 'postroll-video', 'overlay-video'];
664
- slots.forEach(slotId => {
665
- setTimeout(() => playVideo(slotId), Math.random() * 1000);
666
- });
667
- };
668
-
669
- window.pauseAllVideos = function() {
670
- const slots = ['preroll-video', 'midroll-video', 'postroll-video', 'overlay-video'];
671
- slots.forEach(pauseVideo);
672
- };
673
-
674
- window.muteAllVideos = function() {
675
- const slots = ['preroll-video', 'midroll-video', 'postroll-video', 'overlay-video'];
676
- slots.forEach(muteVideo);
677
- addLog('모든 비디오 음소거됨', 'info');
678
- };
679
-
680
- window.refreshAllVideoAds = function() {
681
- const slots = ['preroll-video', 'midroll-video', 'postroll-video', 'overlay-video'];
682
- slots.forEach(slotId => {
683
- addLog(`비디오 광고 새로고침: ${slotId}`, 'info');
684
- const slot = document.getElementById(slotId);
685
- if (slot) {
686
- slot.classList.add('loading');
687
- setTimeout(() => {
688
- slot.classList.remove('loading');
689
- addLog(`비디오 광고 로드 완료: ${slotId}`, 'info');
690
- }, Math.random() * 2000 + 500);
691
- }
692
- });
693
- };
694
-
695
- window.clearLog = function() {
696
- logEl.innerHTML = '<div class="log-entry info">로그가 지워졌습니다.</div>';
697
- };
698
-
699
- try {
700
- addLog('AdStage SDK 초기화 시작...', 'info');
701
-
702
- // SDK 초기화
703
- const sdk = AdStageSDK.init({
704
- apiKey: '7dfddcfda637fbb73225bac3731688b80b90675942fe9f2057a88e2379aba2a4',
705
- debug: true
706
- });
707
-
708
- window.adstageSDK = sdk;
709
-
710
- statusEl.innerHTML = '✅ SDK 초기화 완료 - 비디오 광고 로딩 중...';
711
- statusEl.style.background = '#fff3cd';
712
- statusEl.style.borderColor = '#fd7e14';
713
-
714
- addLog('SDK 초기화 완료', 'info');
715
-
716
- // 비디오 광고 슬롯들 초기화
717
- document.querySelectorAll('.video-ad-slot').forEach(slot => {
718
- const slotId = slot.getAttribute('adstage');
719
-
720
- // 로딩 시뮬레이션
721
- setTimeout(() => {
722
- slot.classList.remove('loading');
723
- addLog(`비디오 광고 로드 완료: ${slotId}`, 'info');
724
- }, Math.random() * 3000 + 1000);
725
- });
726
-
727
- addLog('비디오 광고 페이지 초기화 완료', 'info');
728
- console.log('비디오 광고 예제 페이지 로드 완료');
729
-
730
- } catch (error) {
731
- console.error('SDK 초기화 오류:', error);
732
- addLog(`SDK 초기화 실패: ${error.message}`, 'error');
733
- statusEl.innerHTML = '❌ SDK 초기화 실패: ' + error.message;
734
- statusEl.style.background = '#f8d7da';
735
- statusEl.style.borderColor = '#dc3545';
736
- }
737
- </script>
738
- </body>
739
- </html>