@sgrsoft/vpe-react-sdk 0.1.8 → 0.1.9

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.
package/README.md CHANGED
@@ -1,26 +1,31 @@
1
1
  # VPE React SDK
2
2
 
3
- React 19/Vite 기반 VPE 플레이어 UI 라이브러리입니다. hls.js/dashjs 번들에 포함되지 않으며, 외부 플러그인으로 주입합니다.
4
-
5
- ## 주요 기능
6
- - HLS/DASH/MP4 재생 및 재생 타입 자동 판별
7
- - 플레이리스트 재생, 다음/이전 이동, 자동 다음 재생(카운트다운)
8
- - DRM 지원: Widevine/PlayReady/FairPlay + DRM 라이선스/인증서 헤더 전달
9
- - 토큰 기반 스트림 URL 자동 부착(`options.token`)
10
- - 커스텀 컨트롤바 레이아웃(라이브/VOD, PC/모바일/전체화면 분기)
11
- - 이벤트 브리지(`onEvent`) 및 외부 컨트롤(Ref/UMD 인스턴스)
12
- - 에러 UI 기본 제공 및 `errorOverride`로 커스터마이즈
13
-
14
- ## 설치
3
+ React 19/Vite 기반 VPE 플레이어 SDK입니다. `hls.js`/`dashjs`는 번들에 포함되지 않으며 외부에서 주입합니다.
4
+
5
+ ## Modules 이용하기
6
+
7
+ ### npm 이용한 설치
8
+ ```bash
9
+ npm install @sgrsoft/vpe-react-sdk
10
+ ```
11
+
12
+ ### yarn 이용한 설치
13
+ ```bash
14
+ yarn add @sgrsoft/vpe-react-sdk
15
+ ```
16
+
17
+ ### pnpm 이용한 설치
15
18
  ```bash
16
19
  pnpm add @sgrsoft/vpe-react-sdk
17
- # 선택: 스트리밍 라이브러리
18
- pnpm add hls.js dashjs
19
20
  ```
20
- - hls.js/dashjs는 선택적 peerDependency입니다. 브라우저/CDN 또는 `import Hls from "hls.js"`, `import dashjs from "dashjs"`로 주입하세요.
21
21
 
22
+ ### 스트리밍 라이브러리 설치(선택)
23
+ ```bash
24
+ npm install hls.js dashjs
25
+ ```
26
+
27
+ ## 플레이어 생성
22
28
 
23
- ## 사용법
24
29
  ### React (ESM)
25
30
  ```tsx
26
31
  import Hls from "hls.js";
@@ -28,219 +33,777 @@ import dashjs from "dashjs";
28
33
  import { VpePlayer } from "@sgrsoft/vpe-react-sdk";
29
34
 
30
35
  export function App() {
31
- return (
32
- <VpePlayer
33
- accessKey="..."
34
- platform="pub"
35
- stage="prod"
36
- hls={Hls}
37
- dashjs={dashjs}
38
- options={{
36
+ return (
37
+ <VpePlayer
38
+ accessKey="YOUR_ACCESS_KEY"
39
+ platform="pub"
40
+ stage="prod"
41
+ hls={Hls}
42
+ dashjs={dashjs}
43
+ options={{
44
+ aspectRatio: "16/9",
45
+ playlist: [
46
+ {
47
+ file: "https://CDN_DOMAIN/example_video_01.mp4",
48
+ poster: "https://CDN_DOMAIN/example_video_01.png",
49
+ },
50
+ ],
51
+ }}
52
+ />
53
+ );
54
+ }
55
+ ```
56
+
57
+ ## 옵션 레퍼런스
58
+ `options`는 `vpe-core-sdk`에서 검증/보정됩니다. 기본값은 코어에서 결정되는 항목이 많아, 명시되지 않은 경우는 “vpe-core-sdk 기본값”으로 표기합니다.
59
+
60
+ | 옵션 | 타입 | 기본값 | 필수 | 설명 |
61
+ | --- | --- | --- | --- | --- |
62
+ | autostart | boolean | vpe-core-sdk 기본값 | No | 자동 재생 여부 |
63
+ | muted | boolean | vpe-core-sdk 기본값 | No | 시작 시 음소거 |
64
+ | aspectRatio | string | vpe-core-sdk 기본값 | No | 비율 (`"16/9"`, `"9/16"` 등) |
65
+ | objectFit | `"contain" \| "cover" \| "fill" \| "scale-down" \| "stretch"` | vpe-core-sdk 기본값 | No | 비디오 fit 방식 |
66
+ | controls | boolean | vpe-core-sdk 기본값 | No | 기본 컨트롤 표시 |
67
+ | keyboardShortcut | boolean | vpe-core-sdk 기본값 | No | 키보드 단축키 |
68
+ | seekingPreview | boolean | vpe-core-sdk 기본값 | No | 시킹 프리뷰 표시 |
69
+ | touchGestures | boolean | vpe-core-sdk 기본값 | No | 터치 제스처 사용 |
70
+ | startMutedInfoNotVisible | boolean | vpe-core-sdk 기본값 | No | 시작 음소거 안내 표시 여부 |
71
+ | lang | string | vpe-core-sdk 기본값 | No | UI 언어 |
72
+ | ui | string | vpe-core-sdk 기본값 | No | UI 모드/스킨 키 |
73
+ | controlBtn | object | vpe-core-sdk 기본값 | No | 버튼 표시 on/off 설정 |
74
+ | progressBarColor | string | vpe-core-sdk 기본값 | No | 진행바 색상 |
75
+ | controlActiveTime | number | `3000` | No | 컨트롤 자동 숨김(ms) |
76
+ | playRateSetting | number[] | vpe-core-sdk 기본값 | No | 재생 속도 리스트 |
77
+ | autoPause | boolean | vpe-core-sdk 기본값 | No | 자동 정지 |
78
+ | repeat | boolean | vpe-core-sdk 기본값 | No | 반복 재생 |
79
+ | setStartTime | string \| null | vpe-core-sdk 기본값 | No | 시작 시간 (문자열) |
80
+ | lowLatencyMode | boolean | vpe-core-sdk 기본값 | No | 저지연 모드 |
81
+ | descriptionNotVisible | boolean | vpe-core-sdk 기본값 | No | 메타 설명 숨김 |
82
+ | iosFullscreenNativeMode | boolean | vpe-core-sdk 기본값 | No | iOS 네이티브 전체화면 |
83
+ | visibleWatermark | boolean | vpe-core-sdk 기본값 | No | 워터마크 표시 |
84
+ | watermarkText | string | vpe-core-sdk 기본값 | No | 워터마크 텍스트 |
85
+ | watermarkConfig | object | vpe-core-sdk 기본값 | No | 워터마크 상세 설정 |
86
+ | devTestAppId | string | vpe-core-sdk 기본값 | No | 개발 테스트용 AppId |
87
+ | token | string | vpe-core-sdk 기본값 | No | 스트림 URL 토큰 |
88
+ | override | object | vpe-core-sdk 기본값 | No | 이벤트/동작 오버라이드 |
89
+ | layout | ControlBarLayout \| Variant \| Responsive | SDK 기본 레이아웃 | No | 컨트롤바 레이아웃 |
90
+
91
+ 참고
92
+ - `playlist` 등 재생 관련 옵션은 `vpe-core-sdk`에서 확장 처리됩니다. 예시는 위 “플레이어 생성” 섹션을 참고하세요.
93
+
94
+ ## 옵션 사용 예시
95
+ 아래 예시는 각 옵션을 단독으로 적용하는 형태입니다. 공통으로 `accessKey`와 `playlist`를 포함한 실행 코드를 제공합니다.
96
+
97
+ ### autostart
98
+ - 자동 재생 여부를 설정합니다.
99
+ ```tsx
100
+ <VpePlayer
101
+ accessKey="YOUR_ACCESS_KEY"
102
+ options={{
103
+ playlist: [
104
+ {
105
+ file: "https://CDN_DOMAIN/example_video_01.mp4"
106
+ }
107
+ ],
108
+ autostart: true,
109
+ }}
110
+ />
111
+ ```
112
+
113
+ ### muted
114
+ - 시작 시 음소거를 적용합니다.
115
+ ```tsx
116
+ <VpePlayer
117
+ accessKey="YOUR_ACCESS_KEY"
118
+ options={{
119
+ playlist: [
120
+ {
121
+ file: "https://CDN_DOMAIN/example_video_01.mp4"
122
+ }
123
+ ],
124
+ muted: true,
125
+ }}
126
+ />
127
+ ```
128
+
129
+ ### aspectRatio
130
+ - 플레이어 비율을 지정합니다.
131
+ ```tsx
132
+ <VpePlayer
133
+ accessKey="YOUR_ACCESS_KEY"
134
+ options={{
135
+ playlist: [
136
+ {
137
+ file: "https://CDN_DOMAIN/example_video_01.mp4"
138
+ }
139
+ ],
39
140
  aspectRatio: "16/9",
141
+ }}
142
+ />
143
+ ```
144
+
145
+ ### objectFit
146
+ - 비디오 표시 방식을 설정합니다.
147
+ - cover | contain | fill | stretch
148
+ ```tsx
149
+ <VpePlayer
150
+ accessKey="YOUR_ACCESS_KEY"
151
+ options={{
40
152
  playlist: [
41
- {
42
- file: "https://.../master.m3u8",
43
- poster: "https://.../poster.jpg",
44
- vtt: [{ label: "KR", src: "https://.../subtitle.vtt", default: true }],
45
- },
153
+ {
154
+ file: "https://CDN_DOMAIN/example_video_01.mp4"
155
+ }
46
156
  ],
47
- }}
48
- />
49
- );
50
- }
157
+ objectFit: "cover",
158
+ }}
159
+ />
51
160
  ```
52
161
 
53
- ### React (Ref로 제어)
162
+ ### controls
163
+ - 기본 컨트롤 표시 여부를 설정합니다.
54
164
  ```tsx
55
- import { useRef } from "react";
56
- import { VpePlayer, type PlayerHandle } from "@sgrsoft/vpe-react-sdk";
165
+ <VpePlayer
166
+ accessKey="YOUR_ACCESS_KEY"
167
+ options={{
168
+ playlist: [
169
+ {
170
+ file: "https://CDN_DOMAIN/example_video_01.mp4"
171
+ }
172
+ ],
173
+ controls: true
174
+ }}
175
+ />
176
+ ```
57
177
 
58
- export function App() {
59
- const playerRef = useRef<PlayerHandle>(null);
60
-
61
- return (
62
- <>
63
- <VpePlayer ref={playerRef} accessKey="..." options={{ playlist: [{ file: "..." }] }} />
64
- <button onClick={() => playerRef.current?.play()}>Play</button>
65
- <button onClick={() => playerRef.current?.fullscreenOn()}>Fullscreen</button>
66
- </>
67
- );
68
- }
178
+ ### keyboardShortcut
179
+ - 키보드 단축키를 활성화합니다.
180
+ ```tsx
181
+ <VpePlayer
182
+ accessKey="YOUR_ACCESS_KEY"
183
+ options={{
184
+ keyboardShortcut: true,
185
+ playlist: [{ file: "https://CDN_DOMAIN/example_video_01.mp4" }],
186
+ }}
187
+ />
69
188
  ```
70
189
 
71
- ## 레이아웃 시스템 사용 가이드
72
- `VpePlayer`는 `layout` props로 컨트롤바 구성을 유연하게 커스터마이즈할 수 있습니다.
73
- 기본값은 내부 `defaultLayout`이며, 지정하지 않으면 기본 레이아웃을 사용합니다.
190
+ ### seekingPreview
191
+ - 시킹 프리뷰 표시 여부를 설정합니다.
192
+ ```tsx
193
+ <VpePlayer
194
+ accessKey="YOUR_ACCESS_KEY"
195
+ options={{
196
+ playlist: [
197
+ {
198
+ file: "https://CDN_DOMAIN/example_video_01.mp4"
199
+ }
200
+ ],
201
+ seekingPreview: true,
202
+ }}
203
+ />
204
+ ```
74
205
 
75
- ### 실시간 레이아웃 변경 (메소드)
76
- UMD/ES 인스턴스에서 `layout(nextLayout, merge?)`를 호출하면 즉시 반영됩니다.
77
- 기본 동작은 **전달된 필드만 교체**하며, `merge=false`를 전달하면 전체 교체합니다.
206
+ ### touchGestures
207
+ - 터치 제스처 사용 여부를 설정합니다.
208
+ ```tsx
209
+ <VpePlayer
210
+ accessKey="YOUR_ACCESS_KEY"
211
+ options={{
212
+ playlist: [
213
+ {
214
+ file: "https://CDN_DOMAIN/example_video_01.mp4"
215
+ }
216
+ ],
217
+ touchGestures: true,
218
+ }}
219
+ />
220
+ ```
78
221
 
79
- #### ES (setup 인스턴스)
80
- ```ts
81
- import { setup } from "@sgrsoft/vpe-react-sdk";
222
+ ### startMutedInfoNotVisible
223
+ - 시작 음소거 안내 문구 표시 여부를 설정합니다.
224
+ ```tsx
225
+ <VpePlayer
226
+ accessKey="YOUR_ACCESS_KEY"
227
+ options={{
228
+ playlist: [
229
+ {
230
+ file: "https://CDN_DOMAIN/example_video_01.mp4"
231
+ }
232
+ ],
233
+ startMutedInfoNotVisible: true,
234
+ }}
235
+ />
236
+ ```
82
237
 
83
- const instance = setup("#video", "ACCESS_KEY", {
84
- options: { playlist: [{ file: "..." }] },
85
- });
238
+ ### lang
239
+ - UI 언어를 설정합니다.
240
+ - 설정하지 않거나 'auto'로 설정되면 브라우저 or 기기설정을 따라갑니다.
241
+ ```tsx
242
+ <VpePlayer
243
+ accessKey="YOUR_ACCESS_KEY"
244
+ options={{
245
+ playlist: [
246
+ {
247
+ file: "https://CDN_DOMAIN/example_video_01.mp4"
248
+ }
249
+ ],
250
+ lang: "ko",
251
+ }}
252
+ />
253
+ ```
86
254
 
87
- instance.layout({
88
- bottom: [{ key: "custom", items: ["SettingBtn"] }],
89
- });
255
+ ### ui
256
+ - UI 모드/스킨 키를 설정합니다.
257
+ - auto | pc | mobile
258
+ - 설정하지 않거나 'auto'로 설정되면 브라우저 가로폭이나 기기를 따라갑니다.
259
+ ```tsx
260
+ <VpePlayer
261
+ accessKey="YOUR_ACCESS_KEY"
262
+ options={{
263
+ playlist: [
264
+ {
265
+ file: "https://CDN_DOMAIN/example_video_01.mp4"
266
+ }
267
+ ],
268
+ ui: "auto",
269
+ }}
270
+ />
271
+ ```
90
272
 
91
- // 기존 bottom 삭제
92
- // instance.layout({ bottom: [] });
273
+ ### controlBtn
274
+ - 컨트롤 버튼 표시 여부를 설정합니다.
275
+ ```tsx
276
+ <VpePlayer
277
+ accessKey="YOUR_ACCESS_KEY"
278
+ options={{
279
+ playlist: [
280
+ {
281
+ file: "https://CDN_DOMAIN/example_video_01.mp4"
282
+ }
283
+ ],
284
+ controlBtn: {
285
+ play: true,
286
+ fullscreen: true,
287
+ progressBar: true,
288
+ volume: true,
289
+ times: true,
290
+ pictureInPicture: true,
291
+ setting: true,
292
+ subtitle: true,
293
+ },
294
+ }}
295
+ />
296
+ ```
93
297
 
94
- // 전체 교체
95
- // instance.layout({ bottom: [] }, false);
298
+ ### progressBarColor
299
+ - 진행바 색상을 설정합니다.
300
+ ```tsx
301
+ <VpePlayer
302
+ accessKey="YOUR_ACCESS_KEY"
303
+ options={{
304
+ playlist: [
305
+ {
306
+ file: "https://CDN_DOMAIN/example_video_01.mp4"
307
+ }
308
+ ],
309
+ progressBarColor: "#00E0FF",
310
+ }}
311
+ />
96
312
  ```
97
313
 
98
- #### UMD (ncplayer 인스턴스)
99
- ```html
100
- <script>
101
- const player = new ncplayer("#video", "ACCESS_KEY", {});
102
- player.layout({
103
- bottom: [{ key: "custom", items: ["SettingBtn"] }],
104
- });
105
- // player.layout({ bottom: [] });
106
- // player.layout({ bottom: [] }, false);
107
- </script>
314
+ ### controlActiveTime
315
+ - 컨트롤 자동 숨김 시간을 설정합니다(ms).
316
+ ```tsx
317
+ <VpePlayer
318
+ accessKey="YOUR_ACCESS_KEY"
319
+ options={{
320
+ playlist: [
321
+ {
322
+ file: "https://CDN_DOMAIN/example_video_01.mp4"
323
+ }
324
+ ],
325
+ controlActiveTime: 3000,
326
+ }}
327
+ />
108
328
  ```
109
329
 
110
- ### 1) 기본 레이아웃 정의
111
- 레이아웃은 섹션 단위(`top`, `upper`, `center`, `lower`, `bottom`)로 구성됩니다.
112
- 각 섹션은 그룹 배열이며, 그룹은 `items`로 버튼을 배치합니다.
330
+ ### playRateSetting
331
+ - 재생 속도 옵션을 설정합니다.
332
+ ```tsx
333
+ <VpePlayer
334
+ accessKey="YOUR_ACCESS_KEY"
335
+ options={{
336
+ playlist: [
337
+ {
338
+ file: "https://CDN_DOMAIN/example_video_01.mp4"
339
+ }
340
+ ],
341
+ playRateSetting: [0.5, 1, 1.5, 2],
342
+ }}
343
+ />
344
+ ```
113
345
 
346
+ ### autoPause
347
+ - 탭 전환/창 최소화 시 자동 정지를 설정합니다.
348
+ - 인앱의 웹뷰 상황에서는 정상동작하지 않습니다. (앱의 백그라운드 상황은 지원하지 않습니다.)
349
+ ```tsx
350
+ <VpePlayer
351
+ accessKey="YOUR_ACCESS_KEY"
352
+ options={{
353
+ playlist: [
354
+ {
355
+ file: "https://CDN_DOMAIN/example_video_01.mp4"
356
+ }
357
+ ],
358
+ autoPause: true,
359
+ }}
360
+ />
361
+ ```
362
+
363
+ ### repeat
364
+ - 반복 재생을 설정합니다.
365
+ - 여러 영상의 플레이리스트 상태라면 모든 영상이 재생 후 맨처음 영상으로 이동하여 반복 재생됩니다.
366
+ ```tsx
367
+ <VpePlayer
368
+ accessKey="YOUR_ACCESS_KEY"
369
+ options={{
370
+ playlist: [
371
+ {
372
+ file: "https://CDN_DOMAIN/example_video_01.mp4"
373
+ }
374
+ ],
375
+ repeat: true,
376
+ }}
377
+ />
378
+ ```
379
+
380
+ ### setStartTime
381
+ - 시작 시간을 지정합니다(문자열).
382
+ - 기존적으로 UTC 시간을 지원하지만, 로컬포멧도 지원합니다.
383
+ ```tsx
384
+ <VpePlayer
385
+ accessKey="YOUR_ACCESS_KEY"
386
+ options={{
387
+ playlist: [
388
+ {
389
+ file: "https://CDN_DOMAIN/example_video_01.mp4"
390
+ }
391
+ ],
392
+ setStartTime: "2026-02-03T09:00:00Z",
393
+ }}
394
+ />
395
+ ```
396
+
397
+ ### lowLatencyMode
398
+ - 저지연 모드를 활성화합니다.
399
+ - LL-HLS를 제대로 재생하려면 해당 옵션이 필수입니다.
400
+ ```tsx
401
+ <VpePlayer
402
+ accessKey="YOUR_ACCESS_KEY"
403
+ options={{
404
+ playlist: [
405
+ {
406
+ file: "https://CDN_DOMAIN/example_video_01.mp4"
407
+ }
408
+ ],
409
+ lowLatencyMode: true,
410
+ }}
411
+ />
412
+ ```
413
+
414
+ ### descriptionNotVisible
415
+ - 메타 설명 표시 여부를 설정합니다.
416
+ - 기본값은 false 이며 ture 설정시 화면에 표시되지 않습니다.
417
+ ```tsx
418
+ <VpePlayer
419
+ accessKey="YOUR_ACCESS_KEY"
420
+ options={{
421
+ playlist: [
422
+ {
423
+ file: "https://CDN_DOMAIN/example_video_01.mp4"
424
+ }
425
+ ],
426
+ descriptionNotVisible: true,
427
+ }}
428
+ />
429
+ ```
430
+
431
+ ### iosFullscreenNativeMode
432
+ - iOS 네이티브 전체화면 모드를 사용합니다.
433
+ ```tsx
434
+ <VpePlayer
435
+ accessKey="YOUR_ACCESS_KEY"
436
+ options={{
437
+ playlist: [
438
+ {
439
+ file: "https://CDN_DOMAIN/example_video_01.mp4"
440
+ }
441
+ ],
442
+ iosFullscreenNativeMode: true,
443
+ }}
444
+ />
445
+ ```
446
+
447
+ ### visibleWatermark
448
+ - 워터마크 표시 여부를 설정합니다.
449
+ - 이 옵션은 Video Player Enhancement 콘솔 옵션에서만 적용 가능합니다.
450
+ - 코드사에서 이 옵션을 수정할 수 없습니다.
451
+ ```tsx
452
+ <VpePlayer
453
+ accessKey="YOUR_ACCESS_KEY"
454
+ options={{
455
+ playlist: [
456
+ {
457
+ file: "https://CDN_DOMAIN/example_video_01.mp4"
458
+ }
459
+ ],
460
+ visibleWatermark: true,
461
+ }}
462
+ />
463
+ ```
464
+
465
+ ### watermarkText
466
+ - 워터마크 텍스트를 지정합니다.
467
+ ```tsx
468
+ <VpePlayer
469
+ accessKey="YOUR_ACCESS_KEY"
470
+ options={{
471
+ playlist: [
472
+ {
473
+ file: "https://CDN_DOMAIN/example_video_01.mp4"
474
+ }
475
+ ],
476
+ watermarkText: "SAMPLE@example.com",
477
+ }}
478
+ />
479
+ ```
480
+
481
+ ### watermarkConfig
482
+ - 워터마크 상세 설정을 지정합니다.
483
+ ```tsx
484
+ <VpePlayer
485
+ accessKey="YOUR_ACCESS_KEY"
486
+ options={{
487
+ playlist: [
488
+ {
489
+ file: "https://CDN_DOMAIN/example_video_01.mp4"
490
+ }
491
+ ],
492
+ watermarkConfig: {
493
+ randPosition: true, //위치 랜덤 여부
494
+ randPositionInterVal: 5000, //랜덤 주기 (ms)
495
+ x: 10, //randPosition 이 false 라면 워터마크 위치 고정시 X값 (단위 %)
496
+ y: 10, //randPosition 이 false 라면 워터마크 위치 고정시 Y값 (단위 %)
497
+ opacity: 0.4, //워터마크 투명도
498
+ },
499
+ }}
500
+ />
501
+ ```
502
+
503
+
504
+ ### token
505
+ - 스트림 URL에 자동으로 붙일 토큰을 설정합니다.
506
+ - 글로벌엣지 CDN 보안 토큰을 설정합니다. hls/dash 적용시 하위 ts 파일까지 함께 적용됩니다.
507
+ ```tsx
508
+ <VpePlayer
509
+ accessKey="YOUR_ACCESS_KEY"
510
+ options={{
511
+ playlist: [
512
+ {
513
+ file: "https://CDN_DOMAIN/example_video_01.mp4"
514
+ }
515
+ ],
516
+ token: "token=...",
517
+ }}
518
+ />
519
+ ```
520
+
521
+ ### override
522
+ - 내부 동작을 오버라이드합니다.
523
+ ```tsx
524
+ <VpePlayer
525
+ accessKey="YOUR_ACCESS_KEY"
526
+ options={{
527
+ playlist: [
528
+ {
529
+ file: "https://CDN_DOMAIN/example_video_01.mp4"
530
+ }
531
+ ],
532
+ override: {
533
+ error: (error) => console.log(error), //에러 발생시 실행
534
+ nextSource: () => {}, //다음 동영상 이동시 실행
535
+ prevSource: () => {}, //이전 동영상 이동시 실행
536
+ pip: { //pip 오버라이드, pip를 직접 구현할때 사용
537
+ on: () => {},
538
+ off: () => {},
539
+ },
540
+ },
541
+
542
+ }}
543
+ />
544
+ ```
545
+
546
+ ---
547
+
548
+ ### layout
549
+ - 레이아웃을 옵션으로 전달해 컨트롤바를 변경합니다.
550
+ - 레이아웃 Video Player Enhancement 시스템은 콘솔에 UI 편집툴을 이용하여 작성할 수 있습니다.
551
+ - PC | Mobile | FullScreen 상태에 vod | live 별로 레이아웃 구성 지원합니다.
552
+ - 전체 레이아웃이 아닌 일부만 입력한다면 기존 레이아웃과 머지되어 동작합니다.
553
+ - 자세한건 하위 레이아웃 시스템에 기술되어 있습니다.
554
+ ```tsx
555
+ <VpePlayer
556
+ accessKey="YOUR_ACCESS_KEY"
557
+ options={{
558
+ playlist: [
559
+ {
560
+ file: "https://CDN_DOMAIN/example_video_01.mp4"
561
+ }
562
+ ],
563
+ layout: {
564
+ pc:{
565
+ vod: {
566
+ bottom: [{ key: "play", items: ["PlayBtn"] }],
567
+ },
568
+ live:{
569
+ bottom: [{ key: "play", items: ["PlayBtn"] }],
570
+ }
571
+ }
572
+ },
573
+ }}
574
+ />
575
+ ```
576
+
577
+ ## 레이아웃 시스템
578
+ `layout` props로 컨트롤바를 커스터마이즈할 수 있습니다.
579
+
580
+ ### 기본 레이아웃
114
581
  ```tsx
115
582
  const layout = {
116
- top: [],
117
- center: [{ key: "bigPlayBtn", items: ["BigPlayBtn"] }],
118
- bottom: [
119
- { key: "play", items: ["PlayBtn"], wrapper: "Group", noPadding: true },
120
- { key: "volume", items: ["VolumeBtn"], wrapper: "Group" },
121
- { key: "time", items: ["TimeBtn"], wrapper: "Group" },
122
- { key: "blank", wrapper: "Blank", items: [] },
123
- { key: "right", items: ["SubtitleBtn", "FullscreenBtn"], cap: 2, wrapper: "Group" },
124
- ],
125
- order: ["top", "upper", "center", "seekbar", "lower", "bottom"],
583
+ top: [],
584
+ center: [{ key: "bigPlayBtn", items: ["BigPlayBtn"] }],
585
+ bottom: [
586
+ { key: "play", items: ["PlayBtn"], wrapper: "Group", noPadding: true },
587
+ { key: "volume", items: ["VolumeBtn"], wrapper: "Group" },
588
+ { key: "time", items: ["TimeBtn"], wrapper: "Group" },
589
+ { key: "blank", wrapper: "Blank", items: [] },
590
+ { key: "right", items: ["SubtitleBtn", "FullscreenBtn"], cap: 2, wrapper: "Group" },
591
+ ],
126
592
  };
127
593
 
128
- <VpePlayer layout={layout} />
594
+ <VpePlayer layout={layout} />;
129
595
  ```
130
596
 
131
- ### 2) 라이브/다시보기 분기
132
- 라이브/다시보기 레이아웃을 분기하려면 `live`, `vod`를 사용합니다.
133
-
597
+ ### 라이브/다시보기 분기
134
598
  ```tsx
135
599
  const layoutVariant = {
136
- live: { /* live 전용 레이아웃 */ },
137
- vod: { /* vod 전용 레이아웃 */ },
600
+ live: { /* live 전용 레이아웃 */ },
601
+ vod: { /* vod 전용 레이아웃 */ },
138
602
  };
139
603
 
140
- <VpePlayer layout={layoutVariant} />
604
+ <VpePlayer layout={layoutVariant} />;
141
605
  ```
142
606
 
143
- ### 3) 반응형 레이아웃
144
- PC/모바일/전체화면을 분기하려면 `pc`, `mobile`, `fullscreen`을 사용합니다.
145
- 각 항목은 기본 레이아웃 또는 라이브/다시보기 분기 레이아웃을 받을 수 있습니다.
146
-
607
+ ### 반응형 레이아웃
147
608
  ```tsx
148
609
  const responsiveLayout = {
149
- pc: {
150
- live: { /* pc live */ },
151
- vod: { /* pc vod */ },
152
- },
153
- mobile: {
154
- live: { /* mobile live */ },
155
- vod: { /* mobile vod */ },
156
- },
157
- fullscreen: {
158
- live: { /* fullscreen live */ },
159
- vod: { /* fullscreen vod */ },
160
- },
161
- breakpoint: 768, // 모바일 판단 기준(px)
610
+ pc: {
611
+ live: { /* pc live */ },
612
+ vod: { /* pc vod */ },
613
+ },
614
+ mobile: {
615
+ live: { /* mobile live */ },
616
+ vod: { /* mobile vod */ },
617
+ },
618
+ fullscreen: {
619
+ live: { /* fullscreen live */ },
620
+ vod: { /* fullscreen vod */ },
621
+ },
622
+ breakpoint: 768,
162
623
  };
163
624
 
164
- <VpePlayer layout={responsiveLayout} />
625
+ <VpePlayer layout={responsiveLayout} />;
165
626
  ```
166
627
 
167
- ### 4) 그룹 옵션 요약
168
- - `items`: 버튼 배열 또는 커스텀 ReactNode
169
- - `wrapper`: `"Group"` 또는 `"Blank"` (미지정 시 기본 컨테이너)
170
- - `cap`: 그룹에 버튼간 간격
171
- - `align`: `"left" | "right" | "center"`
628
+ ### 레이아웃 실시간 변경
629
+ Ref 인스턴스에서 `layout(nextLayout, merge?)`를 호출하면 즉시 반영됩니다.
630
+
631
+ ```ts
632
+ import { setup } from "@sgrsoft/vpe-react-sdk";
633
+
634
+ const instance = setup("#video", "YOUR_ACCESS_KEY", {
635
+ options: { playlist: [{ file: "https://CDN_DOMAIN/example_video_01.mp4" }] },
636
+ });
172
637
 
173
- ### 5) 사용 가능한 `items`
638
+ instance.layout({
639
+ bottom: [{ key: "custom", items: ["SettingBtn"] }],
640
+ });
174
641
  ```
175
- PlayBtn, VolumeBtn, TimeBtn, SubtitleBtn, FullscreenBtn, SettingBtn, PipBtn,
176
- MetaDesc, BigPlayBtn, SeekBar, SettingModal, DurationBtn,
177
- SkipForwardBtn, SkipBackBtn, CurrentTimeBtn, MuteBtn, PrevBtn, NextBtn,
178
- NextPrevBtn, Blank
642
+
643
+ ## 플레이어 메소드 (Ref)
644
+ `ref`로 전달되는 `PlayerHandle`에서 아래 메소드를 사용할 수 있습니다.
645
+
646
+ ```tsx
647
+ import { useRef } from "react";
648
+ import { VpePlayer, type PlayerHandle } from "@sgrsoft/vpe-react-sdk";
649
+
650
+ export function App() {
651
+ const playerRef = useRef<PlayerHandle>(null);
652
+
653
+ return (
654
+ <>
655
+ <VpePlayer
656
+ ref={playerRef}
657
+ accessKey="YOUR_ACCESS_KEY"
658
+ options={{
659
+ playlist: [
660
+ {
661
+ file: "https://CDN_DOMAIN/example_video_01.mp4"
662
+ }
663
+ ],
664
+ }}
665
+ />
666
+ <button onClick={() => playerRef.current?.play()}>Play</button>
667
+ <button onClick={() => playerRef.current?.pause()}>Pause</button>
668
+ </>
669
+ );
670
+ }
179
671
  ```
180
672
 
673
+ 지원 메소드
674
+
675
+ | 메소드 | 시그니처 | 설명 |
676
+ | --- | --- | --- |
677
+ | play | `play()` | 재생 시작 |
678
+ | pause | `pause()` | 재생 일시정지 |
679
+ | mute | `mute()` | 음소거 |
680
+ | prev | `prev()` | 이전 플레이리스트 아이템 |
681
+ | next | `next()` | 다음 플레이리스트 아이템 |
682
+ | fullscreen | `fullscreen()` | 전체화면 토글 |
683
+ | fullscreenOn | `fullscreenOn()` | 전체화면 진입 |
684
+ | fullScreenOff | `fullScreenOff()` | 전체화면 종료 |
685
+ | pip | `pip()` | PIP 토글 |
686
+ | volume | `volume(vol?)` | 볼륨 설정 |
687
+ | uiHidden | `uiHidden()` | UI 숨김 |
688
+ | uiVisible | `uiVisible()` | UI 표시 |
689
+ | currentTime | `currentTime(time?)` | 현재 재생 시간 설정 |
690
+ | controlBarActive | `controlBarActive()` | 컨트롤바 활성화 |
691
+ | controlBarDeactive | `controlBarDeactive()` | 컨트롤바 비활성화 |
692
+ | tokenChange | `tokenChange(token)` | 토큰 변경 |
693
+ | layout | `layout(nextLayout, merge?)` | 레이아웃 변경 |
694
+ | changeUiMode | `changeUiMode(mode)` | UI 모드 변경 |
695
+ | changePlayMode | `changePlayMode(mode)` | 재생 모드 변경 |
696
+
181
697
  ## 이벤트
182
- `onEvent` 또는 UMD 인스턴스의 `on`으로 이벤트를 수신합니다.
698
+ `onEvent`로 이벤트를 수신합니다.
183
699
 
184
700
  ```tsx
185
701
  <VpePlayer
186
- accessKey="..."
187
- options={{ playlist: [{ file: "..." }] }}
188
- onEvent={(event) => {
189
- if (event.type === "error") {
190
- console.log(event.data);
191
- }
192
- }}
193
- />
702
+ accessKey="YOUR_ACCESS_KEY"
703
+ options={{
704
+ playlist: [
705
+ {
706
+ file: "https://CDN_DOMAIN/example_video_01.mp4"
707
+ }
708
+ ],
709
+ }}
710
+ onEvent={(event) => {
711
+ if (event.type === "error") {
712
+ console.log(event.data);
713
+ }
714
+ }}
715
+ />;
194
716
  ```
195
717
 
196
- 지원 이벤트: `stateChange`, `ready`, `play`, `pause`, `ended`, `fullscreen`, `fullscreenExit`, `loadingStart`,
197
- `loadingEnd`, `bufferingStart`, `bufferingEnd`, `seeking`, `seeked`, `waiting`, `volumechange`, `timeupdate`,
198
- `controlbarActive`, `controlbarDeactive`, `next`, `prev`, `skipForward`, `skipBack`, `playlistChange`, `error`
199
-
200
- ## DRM/토큰 적용 예시
718
+ 지원 이벤트
719
+
720
+ | 이벤트 | 설명 |
721
+ | --- | --- |
722
+ | stateChange | 플레이어 상태 스냅샷 변경 |
723
+ | ready | 초기화 완료 및 재생 준비 |
724
+ | play | 재생 시작 |
725
+ | pause | 재생 일시정지 |
726
+ | ended | 재생 종료 |
727
+ | fullscreen | 전체화면 진입 |
728
+ | fullscreenExit | 전체화면 종료 |
729
+ | loadingStart | 로딩 시작 |
730
+ | loadingEnd | 로딩 종료 |
731
+ | bufferingStart | 버퍼링 시작 |
732
+ | bufferingEnd | 버퍼링 종료 |
733
+ | seeking | 탐색 시작 |
734
+ | seeked | 탐색 종료 |
735
+ | waiting | 재생 대기 상태 |
736
+ | volumechange | 볼륨 변경 |
737
+ | timeupdate | 재생 시간 변경 |
738
+ | controlbarActive | 컨트롤바 활성화 |
739
+ | controlbarDeactive | 컨트롤바 비활성화 |
740
+ | next | 다음 아이템으로 이동 |
741
+ | prev | 이전 아이템으로 이동 |
742
+ | skipForward | 앞으로 건너뜀 |
743
+ | skipBack | 뒤로 건너뜀 |
744
+ | playlistChange | 플레이리스트 변경 |
745
+ | error | 오류 발생 |
746
+
747
+ ## One Click Multi DRM 예제
201
748
  ```ts
202
749
  options={{
203
- token: "token=...",
204
- playlist: [
205
- {
206
- drm: {
207
- "com.widevine.alpha": {
208
- src: "https://.../manifest.mpd",
209
- licenseUri: "https://.../license",
210
- licenseRequestHeader: { Authorization: "Bearer ..." },
211
- },
212
- "com.apple.fps": {
213
- src: "https://.../master.m3u8",
214
- licenseUri: "https://.../fps-license",
215
- certificateUri: "https://.../fps-cert",
750
+ aspectRatio: "16/9",
751
+ autostart: true,
752
+ muted: true,
753
+ playlist: [
754
+ {
755
+ poster: "https://CDN_DOMAIN/example_poster.jpg",
756
+ description: {
757
+ title: "테스트 영상",
758
+ created_at: "2024.07.13",
759
+ profile_name: "VPE",
760
+ profile_image: "https://CDN_DOMAIN/profile.png",
761
+ },
762
+ drm: {
763
+ "com.widevine.alpha": {
764
+ src: "https://CDN_DOMAIN/manifest.mpd",
765
+ licenseUri: "https://multi-drm.apigw.ntruss.com/api/v1/license",
766
+ licenseRequestHeader: {
767
+ "x-ncp-region_code": "KR",
768
+ "x-ncp-iam-access-key": "YOUR_ACCESS_KEY",
769
+ "x-ncp-apigw-timestamp": 1770125949480,
770
+ "x-ncp-apigw-signature-v2": "YOUR_SIGNATURE",
771
+ "x-drm-token": "YOUR_DRM_TOKEN",
772
+ },
773
+ },
774
+ "com.microsoft.playready": {
775
+ src: "https://CDN_DOMAIN/manifest.mpd",
776
+ licenseUri: "https://multi-drm.apigw.ntruss.com/api/v1/license",
777
+ licenseRequestHeader: {
778
+ "x-ncp-region_code": "KR",
779
+ "x-ncp-iam-access-key": "YOUR_ACCESS_KEY",
780
+ "x-ncp-apigw-timestamp": 1770125949480,
781
+ "x-ncp-apigw-signature-v2": "YOUR_SIGNATURE",
782
+ "x-drm-token": "YOUR_DRM_TOKEN",
783
+ },
784
+ },
785
+ "com.apple.fps": {
786
+ src: "https://CDN_DOMAIN/index.m3u8",
787
+ certificateUri: "https://multi-drm.apigw.ntruss.com/api/v1/license/fairPlay",
788
+ certificateRequestHeader: {
789
+ "x-ncp-region_code": "KR",
790
+ "x-ncp-iam-access-key": "YOUR_ACCESS_KEY",
791
+ "x-ncp-apigw-timestamp": 1770125949480,
792
+ "x-ncp-apigw-signature-v2": "YOUR_SIGNATURE",
793
+ "x-drm-token": "YOUR_DRM_TOKEN",
794
+ "accept": "application/json",
795
+ },
796
+ licenseUri: "https://multi-drm.apigw.ntruss.com/api/v1/license",
797
+ licenseRequestHeader: {
798
+ "x-ncp-region_code": "KR",
799
+ "x-ncp-iam-access-key": "YOUR_ACCESS_KEY",
800
+ "x-ncp-apigw-timestamp": 1770125949481,
801
+ "x-ncp-apigw-signature-v2": "YOUR_SIGNATURE",
802
+ "x-drm-token": "YOUR_DRM_TOKEN",
803
+ },
804
+ },
805
+ },
216
806
  },
217
- },
218
- },
219
- ],
807
+ ],
220
808
  }}
221
809
  ```
222
-
223
- ### UMD
224
- ```html
225
- <link rel="stylesheet" href="./vpePlayer.css" />
226
- <script src="https://cdn.jsdelivr.net/npm/hls.js@1"></script>
227
- <script src="https://cdn.jsdelivr.net/npm/dashjs@4"></script>
228
- <script src="./vpePlayer.js?accessKey=YOUR_ACCESS_KEY"></script>
229
- <div id="video"></div>
230
- <script>
231
- ncplayer.use(window.Hls).use(window.dashjs);
232
- const player = new ncplayer("video", { aspectRatio: "16/9" });
233
- player.on("ready", (event) => console.log(event));
234
- // player.destroy() 로 해제 가능
235
- </script>
236
- ```
237
-
238
- ## UMD setup 함수
239
- ```html
240
- <script>
241
- const instance = window.vpe.setup("#video", "YOUR_ACCESS_KEY", {
242
- options: { aspectRatio: "16/9", playlist: [{ file: "..." }] },
243
- });
244
- // instance.render({ options: { ... } }) 로 재렌더 가능
245
- </script>
246
- ```