npm package discovery and stats viewer.

Discover Tips

  • General search

    [free text search, go nuts!]

  • Package details

    pkg:[package-name]

  • User packages

    @[username]

Sponsor

Optimize Toolset

I’ve always been into building performant and accessible sites, but lately I’ve been taking it extremely seriously. So much so that I’ve been building a tool to help me optimize and monitor the sites that I build to make sure that I’m making an attempt to offer the best experience to those who visit them. If you’re into performant, accessible and SEO friendly sites, you might like it too! You can check it out at Optimize Toolset.

About

Hi, 👋, I’m Ryan Hefner  and I built this site for me, and you! The goal of this site was to provide an easy way for me to check the stats on my npm packages, both for prioritizing issues and updates, and to give me a little kick in the pants to keep up on stuff.

As I was building it, I realized that I was actually using the tool to build the tool, and figured I might as well put this out there and hopefully others will find it to be a fast and useful way to search and browse npm packages as I have.

If you’re interested in other things I’m working on, follow me on Twitter or check out the open source projects I’ve been publishing on GitHub.

I am also working on a Twitter bot for this site to tweet the most popular, newest, random packages from npm. Please follow that account now and it will start sending out packages soon–ish.

Open Software & Tools

This site wouldn’t be possible without the immense generosity and tireless efforts from the people who make contributions to the world and share their work via open source initiatives. Thank you 🙏

© 2026 – Pkg Stats / Ryan Hefner

@sgrsoft/vpe-react-sdk

v2.4.24

Published

<img src="https://tkmenfxu2702.edge.naverncp.com/profile/202602/76303c7f18eb7e2e70c0e1a152419545.png" style="max-width:600px">

Readme

Video Player Enhancement React SDK

React 를 지원하는 Video Player Enhancement SDK입니다. hls.js/dashjs는 번들에 포함되지 않으며 외부에서 주입합니다.

개발자 가이드: https://developer.vpe.naverncp.com/ UI 레이아웃 에디터: https://vpe-player-editor.web.app/ 콘솔: https://console.ncloud.com/vpe/playerManagement

주요 기능

  • JSON 레이아웃 시스템: PC/모바일/전체화면 × VOD/Live 분기, 런타임 머지·전환
  • 커스텀 컴포넌트 삽입: React 컴포넌트/HTML을 컨트롤바에 직접 배치
  • 기본 동작 오버라이드: 재생·일시정지·탐색 등 기본 동작 가로채기
  • HLS & DASH 외부 주입: hls.js, dashjs를 props로 주입
  • 멀티 DRM: Widevine, PlayReady, FairPlay 통합 (One Click Multi DRM / DoveRunner)
  • 자막: WebVTT / SRT 외부 자막, HTML·native 렌더링
  • OTT 기능: 인트로/오프닝/엔딩 스킵, 연령등급·콘텐츠 경고, 시리즈 메타데이터
  • Pre-roll 광고: Google IMA (VAST/VMAP) 연동
  • 워터마크 / Signed URL 토큰 갱신

지원 런타임 및 패키지

Video Player Enhancement V2는 Web / Mobile / TV에서 동일한 API로 동작합니다. 본 저장소는 그중 Web(React) SDK입니다.

| 패키지 | 환경 | | --- | --- | | @sgrsoft/vpe-react-sdk | React / Next.js 플레이어 컴포넌트 (본 패키지) | | vpe-react-native | iOS / Android React Native 플레이어 | | @sgrsoft/vpe-reactnative-tv-sdk | Android TV / Apple TV / Fire TV | | vpe-drm-helper | 멀티 DRM 라이선스 토큰 생성 헬퍼 |

지원 버전

  • React 최소 버전: 18.0.0 (React 18.x/19.x 지원)
  • Next.js 권장 버전:
  • React 18 사용 시: 14.2+
  • React 19 사용 시: 15.x+

Modules 이용하기

npm 이용한 설치

npm install @sgrsoft/vpe-react-sdk

yarn 이용한 설치

yarn add @sgrsoft/vpe-react-sdk

pnpm 이용한 설치

pnpm add @sgrsoft/vpe-react-sdk

스트리밍 라이브러리 설치(선택)

npm install hls.js dashjs

플레이어 생성

React (ESM)

import Hls from "hls.js";
import dashjs from "dashjs";
import { VpePlayer } from "@sgrsoft/vpe-react-sdk";

export function App() {
    return (
        <VpePlayer
            accessKey="YOUR_ACCESS_KEY"
            hls={Hls}
            dashjs={dashjs}
            options={{
                aspectRatio: "16/9",
                playlist: [
                    {
                        file: "https://CDN_DOMAIN/example_video_01.mp4",
                        poster: "https://CDN_DOMAIN/example_video_01.png",
                    },
                ],
            }}
        />
    );
}

컴포넌트 Props

VpePlayer에 직접 전달하는 최상위 props입니다. 재생 동작 세부 설정은 options로 전달합니다.

| Prop | 타입 | 필수 | 설명 | | --- | --- | --- | --- | | accessKey | string | Yes | NCP Sub Account access key (Master API key 사용 금지) | | platform | "pub" \| "gov" | No | 재생 환경 (민간/공공). 기본 pub | | stage | "prod" \| "stg" | No | 호출 스테이지. 기본 prod | | hls | Hls | No | hls.js 라이브러리 주입 (HLS 재생 시) | | dashjs | dashjs | No | dashjs 라이브러리 주입 (DASH 재생 시) | | options | PlayerOptions | No | 플레이어 옵션 객체 | | layout | ControlBarLayout | No | 컨트롤바 레이아웃 | | onEvent | (event) => void | No | 이벤트 콜백 | | ref | PlayerHandle | No | 명령형 제어 핸들 |

보안: accessKey는 반드시 Sub Account 키를 사용하세요. Master API key가 노출되면 NCP 전체 리소스가 탈취될 수 있습니다.

Next.js (App Router)

클라이언트 컴포넌트("use client")에서 사용합니다. hls.js는 top-level import해도 안전하지만, dashjs는 SSR 충돌을 피하기 위해 useEffect 내 dynamic import로 주입하세요.

"use client";
import { useEffect, useState } from "react";
import { VpePlayer } from "@sgrsoft/vpe-react-sdk";

export default function Player() {
    const [dashjs, setDashjs] = useState<unknown>(null);

    useEffect(() => {
        import("dashjs").then((m) => setDashjs(m.default ?? m));
    }, []);

    if (!dashjs) return null;
    return (
        <VpePlayer
            accessKey="YOUR_ACCESS_KEY"
            dashjs={dashjs}
            options={{ playlist: [{ file: "https://CDN_DOMAIN/manifest.mpd" }] }}
        />
    );
}

platform 안내

platform은 재생 환경을 구분하는 필수 설정입니다.

  • pub: 민간 클라우드 환경
  • gov: 공공 클라우드 환경
<VpePlayer
    accessKey="YOUR_ACCESS_KEY"
    platform="pub"
    hls={Hls}
    dashjs={dashjs}

    options={{
        playlist: [
            {
                file: "https://CDN_DOMAIN/example_video_01.mp4"
            }
        ],
    }}
/>

옵션 레퍼런스

optionsvpe-core-sdk에서 검증/보정됩니다. 기본값은 코어에서 결정되는 항목이 많아, 명시되지 않은 경우는 “vpe-core-sdk 기본값”으로 표기합니다.

| 옵션 | 타입 | 기본값 | 필수 | 설명 | | --- | --- | --- | --- | --- | | autostart | boolean | vpe-core-sdk 기본값 | No | 자동 재생 여부 | | muted | boolean | vpe-core-sdk 기본값 | No | 시작 시 음소거 | | aspectRatio | string | vpe-core-sdk 기본값 | No | 비율 ("16/9", "9/16" 등) | | objectFit | "contain" \| "cover" \| "fill" \| "scale-down" \| "stretch" | vpe-core-sdk 기본값 | No | 비디오 fit 방식 | | controls | boolean | vpe-core-sdk 기본값 | No | 기본 컨트롤 표시 | | keyboardShortcut | boolean | vpe-core-sdk 기본값 | No | 키보드 단축키 | | seekingPreview | boolean | vpe-core-sdk 기본값 | No | 시킹 프리뷰 표시 | | touchGestures | boolean | vpe-core-sdk 기본값 | No | 터치 제스처 사용 | | startMutedInfoNotVisible | boolean | vpe-core-sdk 기본값 | No | 시작 음소거 안내 표시 여부 | | lang | string | vpe-core-sdk 기본값 | No | UI 언어 | | ui | string | vpe-core-sdk 기본값 | No | UI 모드/스킨 키 | | controlBtn | object | vpe-core-sdk 기본값 | No | 버튼 표시 on/off 설정 | | progressBarColor | string | vpe-core-sdk 기본값 | No | 진행바 색상 | | controlActiveTime | number | 3000 | No | 컨트롤 자동 숨김(ms) | | playIndex | number | 0 | No | 플레이리스트 시작 인덱스 | | modalFullscreen | boolean | vpe-core-sdk 기본값 | No | 모달 형태 전체화면 (Fullscreen API 미사용) | | captionType | "html" \| "native" | "html" | No | 자막 렌더링 방식 (자막 섹션 참고) | | captionStyle | object | vpe-core-sdk 기본값 | No | 자막 스타일 (html 모드에서만 전체 적용) | | retry | boolean | object | vpe-core-sdk 기본값 | No | 에러 시 재시도 ({ count, delay }) | | icon | IconOverrides | - | No | 컨트롤 아이콘 커스터마이징 | | playRateSetting | number[] | vpe-core-sdk 기본값 | No | 재생 속도 리스트 | | autoPause | boolean | vpe-core-sdk 기본값 | No | 자동 정지 | | repeat | boolean | vpe-core-sdk 기본값 | No | 반복 재생 | | setStartTime | string | null | vpe-core-sdk 기본값 | No | 시작 시간 (문자열) | | lowLatencyMode | boolean | vpe-core-sdk 기본값 | No | 저지연 모드 | | descriptionNotVisible | boolean | vpe-core-sdk 기본값 | No | 메타 설명 숨김 | | iosFullscreenNativeMode | boolean | vpe-core-sdk 기본값 | No | iOS 네이티브 전체화면 | | visibleWatermark | boolean | vpe-core-sdk 기본값 | No | 워터마크 표시 | | watermarkText | string | vpe-core-sdk 기본값 | No | 워터마크 텍스트 | | watermarkConfig | object | vpe-core-sdk 기본값 | No | 워터마크 상세 설정 | | devTestAppId | string | vpe-core-sdk 기본값 | No | 개발 테스트용 AppId | | token | string | vpe-core-sdk 기본값 | No | 스트림 URL 토큰 | | override | object | vpe-core-sdk 기본값 | No | 이벤트/동작 오버라이드 | | ads | AdOptions | - | No | Pre-roll 광고 설정 (Google IMA) | | layout | ControlBarLayout | Variant | Responsive | SDK 기본 레이아웃 | No | 컨트롤바 레이아웃 |

참고

  • playlist 등 재생 관련 옵션은 vpe-core-sdk에서 확장 처리됩니다. 예시는 위 “플레이어 생성” 섹션을 참고하세요.

옵션 사용 예시

아래 예시는 각 옵션을 단독으로 적용하는 형태입니다. 공통으로 accessKeyplaylist를 포함한 실행 코드를 제공합니다.

autostart

  • 자동 재생 여부를 설정합니다.
<VpePlayer
    accessKey="YOUR_ACCESS_KEY"
    options={{
        playlist: [
                {
                    file: "https://CDN_DOMAIN/example_video_01.mp4"
                }
        ],
        autostart: true,
    }}
/>

muted

  • 시작 시 음소거를 적용합니다.
<VpePlayer
    accessKey="YOUR_ACCESS_KEY"
    options={{
        playlist: [
            {
                file: "https://CDN_DOMAIN/example_video_01.mp4"
            }
        ],
        muted: true,
    }}
/>

aspectRatio

  • 플레이어 비율을 지정합니다.
<VpePlayer
    accessKey="YOUR_ACCESS_KEY"
    options={{
        playlist: [
            {
                file: "https://CDN_DOMAIN/example_video_01.mp4"
            }
        ],
        aspectRatio: "16/9",
    }}
/>

objectFit

  • 비디오 표시 방식을 설정합니다.
  • cover | contain | fill | stretch
<VpePlayer
    accessKey="YOUR_ACCESS_KEY"
    options={{
        playlist: [
            {
                file: "https://CDN_DOMAIN/example_video_01.mp4"
            }
        ],
        objectFit: "cover",
    }}
/>

controls

  • 기본 컨트롤 표시 여부를 설정합니다.
<VpePlayer
    accessKey="YOUR_ACCESS_KEY"
    options={{
        playlist: [
            {
                file: "https://CDN_DOMAIN/example_video_01.mp4"
            }
        ],
        controls: true
    }}
/>

keyboardShortcut

  • 키보드 단축키를 활성화합니다.
<VpePlayer
    accessKey="YOUR_ACCESS_KEY"
    options={{
        playlist: [
            {
                file: "https://CDN_DOMAIN/example_video_01.mp4"
            }
        ],
        keyboardShortcut: true,
    }}
/>

seekingPreview

  • 시킹 프리뷰 표시 여부를 설정합니다.
<VpePlayer
    accessKey="YOUR_ACCESS_KEY"
    options={{
        playlist: [
            {
                file: "https://CDN_DOMAIN/example_video_01.mp4"
            }
        ],
        seekingPreview: true,
    }}
/>

touchGestures

  • 터치 제스처 사용 여부를 설정합니다.
<VpePlayer
    accessKey="YOUR_ACCESS_KEY"
    options={{
        playlist: [
            {
                file: "https://CDN_DOMAIN/example_video_01.mp4"
            }
        ],
        touchGestures: true,
    }}
/>

startMutedInfoNotVisible

  • 시작 음소거 안내 문구 표시 여부를 설정합니다.
<VpePlayer
    accessKey="YOUR_ACCESS_KEY"
    options={{
        playlist: [
            {
                file: "https://CDN_DOMAIN/example_video_01.mp4"
            }
        ],
        startMutedInfoNotVisible: true,
    }}
/>

lang

  • UI 언어를 설정합니다.
  • 설정하지 않거나 'auto'로 설정되면 브라우저 or 기기설정을 따라갑니다.
<VpePlayer
    accessKey="YOUR_ACCESS_KEY"
    options={{
        playlist: [
            {
                file: "https://CDN_DOMAIN/example_video_01.mp4"
            }
        ],
        lang: "ko",
    }}
/>

ui

  • UI 모드/스킨 키를 설정합니다.
  • auto | pc | mobile
  • 설정하지 않거나 'auto'로 설정되면 브라우저 가로폭이나 기기를 따라갑니다.
<VpePlayer
    accessKey="YOUR_ACCESS_KEY"
    options={{
        playlist: [
            {
                file: "https://CDN_DOMAIN/example_video_01.mp4"
            }
        ],
        ui: "auto",
    }}
/>

controlBtn

  • 컨트롤 버튼 표시 여부를 설정합니다.
<VpePlayer
    accessKey="YOUR_ACCESS_KEY"
    options={{
        playlist: [
            {
                file: "https://CDN_DOMAIN/example_video_01.mp4"
            }
        ],
        controlBtn: {
            play: true,
            fullscreen: true,
            progressBar: true,
            volume: true,
            times: true,
            pictureInPicture: true,
            setting: true,
            subtitle: true,
        },
    }}
/>

progressBarColor

  • 진행바 색상을 설정합니다.
<VpePlayer
    accessKey="YOUR_ACCESS_KEY"
    options={{
        playlist: [
            {
                file: "https://CDN_DOMAIN/example_video_01.mp4"
            }
        ],
        progressBarColor: "#00E0FF",
    }}
/>

controlActiveTime

  • 컨트롤 자동 숨김 시간을 설정합니다(ms).
<VpePlayer
    accessKey="YOUR_ACCESS_KEY"
    options={{
        playlist: [
            {
                file: "https://CDN_DOMAIN/example_video_01.mp4"
            }
        ],
        controlActiveTime: 3000,
    }}
/>

playRateSetting

  • 재생 속도 옵션을 설정합니다.
<VpePlayer
    accessKey="YOUR_ACCESS_KEY"
    options={{
        playlist: [
            {
                file: "https://CDN_DOMAIN/example_video_01.mp4"
            }
        ],
        playRateSetting: [0.5, 1, 1.5, 2],
    }}
/>

autoPause

  • 탭 전환/창 최소화 시 자동 정지를 설정합니다.
  • 인앱의 웹뷰 상황에서는 정상동작하지 않습니다. (앱의 백그라운드 상황은 지원하지 않습니다.)
<VpePlayer
    accessKey="YOUR_ACCESS_KEY"
    options={{
        playlist: [
            {
                file: "https://CDN_DOMAIN/example_video_01.mp4"
            }
        ],
        autoPause: true,
    }}
/>

repeat

  • 반복 재생을 설정합니다.
  • 여러 영상의 플레이리스트 상태라면 모든 영상이 재생 후 맨처음 영상으로 이동하여 반복 재생됩니다.
<VpePlayer
    accessKey="YOUR_ACCESS_KEY"
    options={{
        playlist: [
            {
                file: "https://CDN_DOMAIN/example_video_01.mp4"
            }
        ],
        repeat: true,
    }}
/>

setStartTime

  • 시작 시간을 지정합니다(문자열).
  • 기존적으로 UTC 시간을 지원하지만, 로컬포멧도 지원합니다.
<VpePlayer
    accessKey="YOUR_ACCESS_KEY"
    options={{
        playlist: [
            {
                file: "https://CDN_DOMAIN/example_video_01.mp4"
            }
        ],
        setStartTime: "2026-02-03T09:00:00Z",
    }}
/>

lowLatencyMode

  • 저지연 모드를 활성화합니다.
  • LL-HLS를 제대로 재생하려면 해당 옵션이 필수입니다.
<VpePlayer
    accessKey="YOUR_ACCESS_KEY"
    options={{
        playlist: [
            {
                file: "https://CDN_DOMAIN/example_video_01.mp4"
            }
        ],
        lowLatencyMode: true,
    }}
/>

descriptionNotVisible

  • 메타 설명 표시 여부를 설정합니다.
  • 기본값은 false 이며 ture 설정시 화면에 표시되지 않습니다.
<VpePlayer
    accessKey="YOUR_ACCESS_KEY"
    options={{
        playlist: [
            {
                file: "https://CDN_DOMAIN/example_video_01.mp4"
            }
        ],
        descriptionNotVisible: true,
    }}
/>

iosFullscreenNativeMode

  • iOS 네이티브 전체화면 모드를 사용합니다.
<VpePlayer
    accessKey="YOUR_ACCESS_KEY"
    options={{
        playlist: [
            {
                file: "https://CDN_DOMAIN/example_video_01.mp4"
            }
        ],
        iosFullscreenNativeMode: true,
    }}
/>

visibleWatermark

  • 워터마크 표시 여부를 설정합니다.
  • 이 옵션은 Video Player Enhancement 콘솔 옵션에서만 적용 가능합니다.
  • 코드사에서 이 옵션을 수정할 수 없습니다.
<VpePlayer
    accessKey="YOUR_ACCESS_KEY"
    options={{
        playlist: [
            {
                file: "https://CDN_DOMAIN/example_video_01.mp4"
            }
        ],
        visibleWatermark: true,
    }}
/>

watermarkText

  • 워터마크 텍스트를 지정합니다.
<VpePlayer
    accessKey="YOUR_ACCESS_KEY"
    options={{
        playlist: [
            {
                file: "https://CDN_DOMAIN/example_video_01.mp4"
            }
        ],
        watermarkText: "[email protected]",
    }}
/>

watermarkConfig

  • 워터마크 상세 설정을 지정합니다.
<VpePlayer
    accessKey="YOUR_ACCESS_KEY"
    options={{
        playlist: [
            {
                file: "https://CDN_DOMAIN/example_video_01.mp4"
            }
        ],
        watermarkConfig: {
            randPosition: true, //위치 랜덤 여부
            randPositionInterVal: 5000, //랜덤 주기 (ms)
            x: 10, //randPosition 이 false 라면 워터마크 위치 고정시 X값 (단위 %)
            y: 10, //randPosition 이 false 라면 워터마크 위치 고정시 Y값 (단위 %)
            opacity: 0.4, //워터마크 투명도
        },
    }}
/>

token

  • 스트림 URL에 자동으로 붙일 토큰을 설정합니다.
  • 글로벌엣지 CDN 보안 토큰을 설정합니다. hls/dash 적용시 하위 ts 파일까지 함께 적용됩니다.
<VpePlayer
    accessKey="YOUR_ACCESS_KEY"
    options={{
        playlist: [
            {
                file: "https://CDN_DOMAIN/example_video_01.mp4"
            }
        ],
        token: "token=...",
    }}
/>

override

  • 내부 동작을 오버라이드합니다.
<VpePlayer
    accessKey="YOUR_ACCESS_KEY"
    options={{
        playlist: [
            {
                file: "https://CDN_DOMAIN/example_video_01.mp4"
            }
        ],
        override: {
            error: (error) => console.log(error), //에러 발생시 실행
            nextSource: () => {}, //다음 동영상 이동시 실행
            prevSource: () => {}, //이전 동영상 이동시 실행
            pip: { //pip 오버라이드, pip를 직접 구현할때 사용
                on: () => {},
                off: () => {},
            },
        },

    }}
/>

ads

  • Pre-roll 광고를 설정합니다. Google IMA SDK 기반으로 동작합니다.
  • tagUrl에 VAST 태그 URL을 전달하면 콘텐츠 재생 전에 광고가 자동 재생됩니다.
  • 광고 재생 중 콘텐츠 비디오는 자동으로 일시정지되고, 컨트롤바가 숨겨집니다.
  • 광고 완료/스킵/에러 후 콘텐츠가 자동 재생됩니다.
<VpePlayer
    accessKey="YOUR_ACCESS_KEY"
    hls={Hls}
    options={{
        playlist: [
            {
                file: "https://CDN_DOMAIN/example.m3u8"
            }
        ],
        autostart: true,
        muted: true,
        ads: {
            tagUrl: "https://pubads.g.doubleclick.net/gampad/ads?iu=/21775744923/external/single_preroll_skippable&sz=640x480&ciu_szs=300x250%2C728x90&gdfp_req=1&output=vast&unviewed_position_start=1&env=vp&impl=s&correlator=",
            enabled: true, // 기본값: true. false로 설정하면 광고 비활성화
        },
    }}
/>

AdOptions 타입

| 옵션 | 타입 | 기본값 | 필수 | 설명 | | --- | --- | --- | --- | --- | | tagUrl | string | - | Yes | VAST/VMAP 광고 태그 URL | | enabled | boolean | true | No | 광고 활성화 여부 |


layout

  • 레이아웃을 옵션으로 전달해 컨트롤바를 변경합니다.
  • 레이아웃 Video Player Enhancement 시스템은 콘솔에 UI 편집툴을 이용하여 작성할 수 있습니다.
  • PC | Mobile | FullScreen 상태에 vod | live 별로 레이아웃 구성 지원합니다.
  • 전체 레이아웃이 아닌 일부만 입력한다면 기존 레이아웃과 머지되어 동작합니다.
  • 자세한건 하위 레이아웃 시스템에 기술되어 있습니다.
<VpePlayer
    accessKey="YOUR_ACCESS_KEY"
    options={{
        playlist: [
            {
                file: "https://CDN_DOMAIN/example_video_01.mp4"
            }
        ],
        layout: {
            pc:{
                vod: {
                    bottom: [{ key: "play", items: ["PlayBtn"] }],
                },
                live:{
                    bottom: [{ key: "play", items: ["PlayBtn"] }],
                }
            }
        },
    }}
/>

레이아웃 시스템

layout props로 컨트롤바를 커스터마이즈할 수 있습니다.

기본 레이아웃

const layout = {
    top: [],
    center: [{ key: "bigPlayBtn", items: ["BigPlayBtn"] }],
    bottom: [
        { key: "play", items: ["PlayBtn"], wrapper: "Group", noPadding: true },
        { key: "volume", items: ["VolumeBtn"], wrapper: "Group" },
        { key: "time", items: ["TimeBtn"], wrapper: "Group" },
        { key: "blank", wrapper: "Blank", items: [] },
        { key: "right", items: ["SubtitleBtn", "FullscreenBtn"], cap: 2, wrapper: "Group" },
    ],
};

<VpePlayer layout={layout} />;

라이브/다시보기 분기

const layoutVariant = {
    live: { /* live 전용 레이아웃 */ },
    vod: { /* vod 전용 레이아웃 */ },
};

<VpePlayer layout={layoutVariant} />;

반응형 레이아웃

const responsiveLayout = {
    pc: {
        live: { /* pc live */ },
        vod: { /* pc vod */ },
    },
    mobile: {
        live: { /* mobile live */ },
        vod: { /* mobile vod */ },
    },
    fullscreen: {
        live: { /* fullscreen live */ },
        vod: { /* fullscreen vod */ },
    },
    breakpoint: 768,
};

<VpePlayer layout={responsiveLayout} />;

레이아웃 실시간 변경

Ref 인스턴스에서 layout(nextLayout, merge?)를 호출하면 즉시 반영됩니다.

import { setup } from "@sgrsoft/vpe-react-sdk";

const instance = setup("#video", "YOUR_ACCESS_KEY", {
    options: {
        playlist: [
            {
                file: "https://CDN_DOMAIN/example_video_01.mp4"
            }
        ],
    },
});

instance.layout({
    bottom: [{ key: "custom", items: ["SettingBtn"] }],
});

자막 (Caption)

외부 자막 파일(WebVTT / SRT)은 반드시 playlist[].vtt 또는 playlist[].srt 배열에 등록합니다. options.subtitles, options.captions, <track> 요소 등은 동작하지 않습니다.

WebVTT 자막 등록

<VpePlayer
    accessKey="YOUR_ACCESS_KEY"
    hls={Hls}
    options={{
        playlist: [
            {
                file: "https://CDN_DOMAIN/master.m3u8",
                vtt: [
                    { id: "ko", src: "https://CDN_DOMAIN/ko.vtt", label: "한국어", default: true },
                    { id: "en", src: "https://CDN_DOMAIN/en.vtt", label: "English" },
                    { id: "ja", src: "https://CDN_DOMAIN/ja.vtt", label: "日本語" },
                ],
            },
        ],
    }}
/>

| 필드 | 타입 | 필수 | 설명 | | --- | --- | --- | --- | | src | string | Yes | 자막 파일 URL | | id | string | No | 언어 코드 등 식별자 ("ko", "en") | | label | string | No | 설정 메뉴에 표시될 라벨 | | default | boolean | No | 초기 선택 자막 (배열 중 1개만) | | file | string | No | V1 호환 alias. src가 없을 때만 사용 |

SRT 자막 등록

playlist[].srt 배열에 등록하면 SDK가 런타임에 SRT를 WebVTT로 변환합니다. 브라우저는 SRT를 native로 인식하지 못하므로, SRT 사용 시 captionType"html"로 강제됩니다. vttsrt를 동시에 지정하면 vtt가 우선합니다.

options={{
    playlist: [
        {
            file: "https://CDN_DOMAIN/master.m3u8",
            srt: [
                { id: "ko", src: "https://CDN_DOMAIN/ko.srt", label: "한국어", default: true },
            ],
        },
    ],
}}

자막 렌더링 방식 (captionType)

captionType은 자막 소스 등록이 아니라 렌더링 방식을 결정합니다.

| 항목 | "html" (기본) | "native" | | --- | --- | --- | | 렌더링 | 플레이어 위 별도 div 오버레이 | 브라우저 기본 ::cue | | captionStyle | 모두 적용 | 무시됨 | | OS 접근성 설정 | 무시 (일관된 스타일) | OS 설정 따름 (iOS/Android) | | 추천 케이스 | 디자인 일관성, 다크모드 | 접근성 우선 |

자막 스타일 (captionStyle)

captionType: "html"에서만 전체 적용됩니다. fontSize, lineHeight, bottomOffset, sidePadding은 단일값 또는 { pc, mobile } 객체를 지원합니다.

options={{
    playlist: [{ file: "https://CDN_DOMAIN/master.m3u8", vtt: [/* ... */] }],
    captionType: "html",
    captionStyle: {
        fontSize: { pc: 20, mobile: 14 },
        fontFamily: "Pretendard, sans-serif",
        color: "#ffffff",
        backgroundColor: "rgba(0,0,0,0.5)",
        opacity: 1,
        lineHeight: { pc: 1.4, mobile: 1.3 },
        edgeStyle: "uniform", // none | dropshadow | raised | depressed | uniform
        bottomOffset: { pc: 50, mobile: 20 },
        sidePadding: { pc: 80, mobile: 40 },
        padding: "5px 10px",
    },
}}

OTT 기능

playlist 아이템에 OTT 메타데이터를 추가하면 스킵 버튼, 진입 안내, 시리즈 UI가 자동으로 표시됩니다.

구간 스킵 (인트로/오프닝/엔딩)

start("HH:MM:SS")부터 duration(초) 구간에 스킵 버튼이 노출되며, 클릭 시 start + duration 시점으로 이동합니다.

options={{
    playlist: [
        {
            file: "https://CDN_DOMAIN/episode_01.m3u8",
            intro:   { start: "00:00:00", duration: 10 },   // 인트로 스킵
            opening: { start: "00:00:30", duration: 90 },   // 오프닝 스킵
            ending:  { start: "00:42:00", duration: 180 },  // 다음화/엔딩
        },
    ],
}}

각 스킵 발생 시 introSkip / openingSkip / endingSkip 이벤트가 발생합니다.

연령등급 / 콘텐츠 경고

영상 진입 시 오버레이로 자동 표시됩니다.

options={{
    playlist: [
        {
            file: "https://CDN_DOMAIN/episode_01.m3u8",
            ageRating: "15", // "all" | "12" | "15" | "19"
            contentWarnings: ["violence", "language"],
            // sexuality | violence | language | drugs | horror | imitation | provocative
        },
    ],
}}

시리즈 메타데이터 (description)

title, profile_name은 다국어 객체({ ko, en, ja })도 지원합니다.

options={{
    playlist: [
        {
            file: "https://CDN_DOMAIN/episode_01.m3u8",
            description: {
                title: { ko: "시즌1 1화: 첫 만남", en: "S1 E1: First Meeting" },
                profile_name: "OTT 스튜디오",
                profile_image: "https://CDN_DOMAIN/logo.png",
                created_at: "2026-05-15",
            },
        },
    ],
}}

자동재생 정책 안내

autostart: true 만으로는 모든 진입 방식에서 자동재생이 보장되지 않습니다. 브라우저 정책상 사용자 제스처 없이 소리가 있는 자동재생은 차단됩니다.

| 진입 방식 | 음소거 자동재생 | 무음소거 자동재생 | | --- | --- | --- | | 새로고침 / URL 직접 입력 / 새 탭 | 가능 | 차단 | | 링크 클릭 진입 | 가능 | 브라우저별 상이 | | iOS Safari | 가능 (playsInline) | 항상 차단 |

모든 환경에서 자동재생을 보장하려면 autostartmuted를 함께 사용하세요.

options={{
    playlist: [{ file: "https://CDN_DOMAIN/master.m3u8" }],
    autostart: true,
    muted: true, // 모든 환경에서 자동재생 허용
}}

무음소거 자동재생을 시도하다 실패하면 error 이벤트에서 음소거 폴백 후 "소리 켜기" 버튼을 노출하는 패턴을 권장합니다.

전체화면 동작 안내

플랫폼별 전체화면 동작이 다릅니다.

| 플랫폼 | 동작 | | --- | --- | | Desktop / Android Chrome | 표준 Fullscreen API. SDK 커스텀 컨트롤 유지 | | iPadOS (13.4+) | 표준 Fullscreen API 지원 | | iPhone Safari | Fullscreen API 미지원 → iOS 네이티브 비디오 플레이어로 전환. SDK 커스텀 컨트롤바가 iOS 기본 컨트롤로 대체됨 |

iosFullscreenNativeMode(기본 동작)와 modalFullscreen 옵션으로 iOS 전체화면 방식을 조정할 수 있습니다.

DoveRunner(Pallycon) DRM 예제

NCP One Click Multi DRM 외에 DoveRunner(Pallycon) 라이선스 서버도 사용할 수 있습니다. pallycon-customdata-v2 토큰은 백엔드에서 생성해 전달합니다(SiteKey 노출 금지).

options={{
    playlist: [
        {
            file: "https://contents.pallycon.com/.../stream.mpd",
            drm: {
                "com.widevine.alpha": {
                    licenseUri: "https://license-global.pallycon.com/ri/licenseManager.do",
                    licenseRequestHeader: {
                        "pallycon-customdata-v2": "BACKEND_ISSUED_TOKEN",
                    },
                },
                "com.apple.fps": {
                    src: "https://contents.pallycon.com/.../master.m3u8",
                    certificateUri: "https://license-global.pallycon.com/ri/fpsKeyManager.do?siteId=SITE_ID",
                    licenseUri: "https://license-global.pallycon.com/ri/licenseManager.do",
                    licenseRequestHeader: {
                        "Content-type": "application/x-www-form-urlencoded",
                        "pallycon-customdata-v2": "BACKEND_ISSUED_TOKEN",
                    },
                },
            },
        },
    ],
}}

DRM 라이선스 서명/토큰은 항상 백엔드에서 생성하세요. NCP DRM은 DRM 권한 전용 Sub Account 키만 사용합니다.

플레이어 메소드 (Ref)

ref로 전달되는 PlayerHandle에서 아래 메소드를 사용할 수 있습니다.

import { useRef } from "react";
import { VpePlayer, type PlayerHandle } from "@sgrsoft/vpe-react-sdk";

export function App() {
    const playerRef = useRef<PlayerHandle>(null);

    return (
        <>
            <VpePlayer
                ref={playerRef}
                accessKey="YOUR_ACCESS_KEY"
                options={{
                    playlist: [
                        {
                            file: "https://CDN_DOMAIN/example_video_01.mp4"
                        }
                    ],
                }}
            />
            <button onClick={() => playerRef.current?.play()}>Play</button>
            <button onClick={() => playerRef.current?.pause()}>Pause</button>
        </>
    );
}

지원 메소드

| 메소드 | 시그니처 | 설명 | | --- | --- | --- | | play | play() | 재생 시작 | | pause | pause() | 재생 일시정지 | | mute | mute() | 음소거 | | prev | prev() | 이전 플레이리스트 아이템 | | next | next() | 다음 플레이리스트 아이템 | | fullscreen | fullscreen() | 전체화면 토글 | | fullscreenOn | fullscreenOn() | 전체화면 진입 | | fullScreenOff | fullScreenOff() | 전체화면 종료 | | pip | pip() | PIP 토글 | | volume | volume(vol?) | 볼륨 설정 | | uiHidden | uiHidden() | UI 숨김 | | uiVisible | uiVisible() | UI 표시 | | currentTime | currentTime(time?) | 현재 재생 시간 설정 | | controlBarActive | controlBarActive() | 컨트롤바 활성화 | | controlBarDeactive | controlBarDeactive() | 컨트롤바 비활성화 | | tokenChange | tokenChange(token) | 토큰 변경 | | layout | layout(nextLayout, merge?) | 레이아웃 변경 | | changeUiMode | changeUiMode(mode) | UI 모드 변경 | | changePlayMode | changePlayMode(mode) | 재생 모드 변경 | | addNextSource | addNextSource(source) | 다음 영상 플레이리스트에 추가 | | addPrevSource | addPrevSource(source) | 이전 영상 플레이리스트에 추가 | | changeOptions | changeOptions(nextOptions) | 옵션 부분 변경 (런타임 적용) | | on | on(type, callback) | 특정 이벤트 구독 (해제 함수 반환, "*"는 전체 구독) | | destroy | destroy() | 플레이어 인스턴스 정리 |

addNextSource / addPrevSource

현재 재생 중인 영상의 다음/이전 위치에 새로운 영상을 동적으로 추가합니다.

// 단일 영상 추가
playerRef.current?.addNextSource({
    file: "https://CDN_DOMAIN/new_video.mp4",
    poster: "https://CDN_DOMAIN/new_poster.jpg",
});

// 여러 영상 동시 추가
playerRef.current?.addPrevSource([
    { file: "https://CDN_DOMAIN/video_1.mp4" },
    { file: "https://CDN_DOMAIN/video_2.mp4" },
]);

이벤트

onEvent로 이벤트를 수신합니다.

<VpePlayer
    accessKey="YOUR_ACCESS_KEY"
    options={{
        playlist: [
            {
                file: "https://CDN_DOMAIN/example_video_01.mp4"
            }
        ],
    }}
    onEvent={(event) => {
        if (event.type === "error") {
            console.log(event.data);
        }
    }}
/>;

지원 이벤트

| 이벤트 | 설명 | | --- | --- | | stateChange | 플레이어 상태 스냅샷 변경 | | ready | 초기화 완료 및 재생 준비 | | play | 재생 시작 | | pause | 재생 일시정지 | | ended | 재생 종료 | | fullscreen | 전체화면 진입 | | fullscreenExit | 전체화면 종료 | | loadingStart | 로딩 시작 | | loadingEnd | 로딩 종료 | | bufferingStart | 버퍼링 시작 | | bufferingEnd | 버퍼링 종료 | | seeking | 탐색 시작 | | seeked | 탐색 종료 | | waiting | 재생 대기 상태 | | volumechange | 볼륨 변경 | | timeupdate | 재생 시간 변경 | | controlbarActive | 컨트롤바 활성화 | | controlbarDeactive | 컨트롤바 비활성화 | | next | 다음 아이템으로 이동 | | prev | 이전 아이템으로 이동 | | skipForward | 앞으로 건너뜀 | | skipBack | 뒤로 건너뜀 | | playlistChange | 플레이리스트 변경 | | ratechange | 재생 속도 변경 | | introSkip | 인트로 구간 스킵 | | openingSkip | 오프닝 구간 스킵 | | endingSkip | 엔딩 구간 스킵 | | licenseRequest | DRM 라이선스 요청 | | licenseSuccess | DRM 라이선스 발급 성공 | | licenseError | DRM 라이선스 발급 실패 | | error | 오류 발생 | | adStart | 광고 재생 시작 | | adComplete | 광고 재생 완료 | | adSkip | 사용자가 광고 스킵 | | adError | 광고 로드/재생 에러 |

One Click Multi DRM 예제

options={{
    aspectRatio: "16/9",
    autostart: true,
    muted: true,
    playlist: [
        {
            poster: "https://CDN_DOMAIN/example_poster.jpg",
            description: {
                title: "테스트 영상",
                created_at: "2024.07.13",
                profile_name: "VPE",
                profile_image: "https://CDN_DOMAIN/profile.png",
            },
            drm: {
                "com.widevine.alpha": {
                    src: "https://CDN_DOMAIN/manifest.mpd",
                    licenseUri: "https://multi-drm.apigw.ntruss.com/api/v1/license",
                    licenseRequestHeader: {
                        "x-ncp-region_code": "KR",
                        "x-ncp-iam-access-key": "YOUR_ACCESS_KEY",
                        "x-ncp-apigw-timestamp": 1770125949480,
                        "x-ncp-apigw-signature-v2": "YOUR_SIGNATURE",
                        "x-drm-token": "YOUR_DRM_TOKEN",
                    },
                },
                "com.microsoft.playready": {
                    src: "https://CDN_DOMAIN/manifest.mpd",
                    licenseUri: "https://multi-drm.apigw.ntruss.com/api/v1/license",
                    licenseRequestHeader: {
                        "x-ncp-region_code": "KR",
                        "x-ncp-iam-access-key": "YOUR_ACCESS_KEY",
                        "x-ncp-apigw-timestamp": 1770125949480,
                        "x-ncp-apigw-signature-v2": "YOUR_SIGNATURE",
                        "x-drm-token": "YOUR_DRM_TOKEN",
                    },
                },
                "com.apple.fps": {
                    src: "https://CDN_DOMAIN/index.m3u8",
                    certificateUri: "https://multi-drm.apigw.ntruss.com/api/v1/license/fairPlay",
                    certificateRequestHeader: {
                        "x-ncp-region_code": "KR",
                        "x-ncp-iam-access-key": "YOUR_ACCESS_KEY",
                        "x-ncp-apigw-timestamp": 1770125949480,
                        "x-ncp-apigw-signature-v2": "YOUR_SIGNATURE",
                        "x-drm-token": "YOUR_DRM_TOKEN",
                        "accept": "application/json",
                    },
                    licenseUri: "https://multi-drm.apigw.ntruss.com/api/v1/license",
                    licenseRequestHeader: {
                        "x-ncp-region_code": "KR",
                        "x-ncp-iam-access-key": "YOUR_ACCESS_KEY",
                        "x-ncp-apigw-timestamp": 1770125949481,
                        "x-ncp-apigw-signature-v2": "YOUR_SIGNATURE",
                        "x-drm-token": "YOUR_DRM_TOKEN",
                    },
                },
            },
        },
    ],
}}

Pre-roll 광고 (Google IMA)

Google IMA SDK를 사용한 Pre-roll 영상 광고를 지원합니다. options.ads.tagUrl에 VAST 태그 URL을 전달하면 콘텐츠 재생 전에 광고가 자동으로 재생됩니다.

  • Google IMA SDK는 외부에서 자동 로드됩니다 (번들에 포함되지 않음)
  • 광고 재생 중 콘텐츠 비디오는 자동으로 일시정지되고, 컨트롤바가 숨겨집니다
  • 광고 완료/스킵/에러 후 콘텐츠가 자동 재생됩니다
  • ads 옵션이 없으면 기존과 동일하게 동작합니다

React (ESM) 예제

"use client";

import Hls from "hls.js";
import { VpePlayer } from "@sgrsoft/vpe-react-sdk";

export default function AdPlayer() {
    return (
        <VpePlayer
            accessKey="YOUR_ACCESS_KEY"
            hls={Hls}
            options={{
                playlist: [
                    {
                        file: "https://CDN_DOMAIN/example.m3u8",
                        poster: "https://CDN_DOMAIN/poster.jpg",
                    },
                ],
                autostart: true,
                muted: true,
                ads: {
                    tagUrl: "https://pubads.g.doubleclick.net/gampad/ads?iu=/21775744923/external/single_preroll_skippable&sz=640x480&ciu_szs=300x250%2C728x90&gdfp_req=1&output=vast&unviewed_position_start=1&env=vp&impl=s&correlator=",
                },
            }}
            onEvent={(event) => {
                switch (event.type) {
                    case "adStart":
                        console.log("광고 시작");
                        break;
                    case "adComplete":
                        console.log("광고 완료");
                        break;
                    case "adSkip":
                        console.log("광고 스킵");
                        break;
                    case "adError":
                        console.log("광고 에러", event.data?.message);
                        break;
                }
            }}
        />
    );
}

UMD 예제

<script src="https://player.vpe.naverncp.com/v2/ncplayer.js?access_key=YOUR_ACCESS_KEY"></script>
<script src="https://cdn.jsdelivr.net/npm/hls.js@1"></script>

<div id="video"></div>

<script>
    const player = new ncplayer("video", {
        playlist: [
            { file: "https://CDN_DOMAIN/example.m3u8" },
        ],
        autostart: true,
        muted: true,
        ads: {
            tagUrl: "https://pubads.g.doubleclick.net/gampad/ads?iu=/21775744923/external/single_preroll_skippable&sz=640x480&ciu_szs=300x250%2C728x90&gdfp_req=1&output=vast&unviewed_position_start=1&env=vp&impl=s&correlator=",
        },
    });

    player.on("adStart", function(e) { console.log("광고 시작"); });
    player.on("adComplete", function(e) { console.log("광고 완료"); });
    player.on("adSkip", function(e) { console.log("광고 스킵"); });
    player.on("adError", function(e) { console.log("광고 에러", e.data?.message); });
</script>

광고 이벤트

| 이벤트 | 설명 | | --- | --- | | adStart | 광고 재생 시작 | | adComplete | 광고 재생 완료 | | adSkip | 사용자가 광고 스킵 | | adError | 광고 로드/재생 에러 (event.data.message에 상세 메시지) |