Classic/VPC 환경에서 이용 가능합니다.
OTT 서비스에 필요한 인트로/오프닝/엔딩 스킵, 연령 등급 표시, 콘텐츠 경고 기능을 제공합니다. 각 기능은 playlist 아이템 단위로 설정합니다.
인트로 / 오프닝 / 엔딩 스킵
각 PlaylistItem에 intro, opening, ending 구간을 지정하면 해당 시점에 스킵 버튼이 자동으로 표시됩니다.
옵션
모든 스킵 옵션은 playlist[] 아이템에 설정합니다.
| 이름 | 타입 | 기본값 | 설명 |
|---|---|---|---|
| intro | { start: string; duration: number } | undefined | 인트로 구간(재생 시작 시 스킵 버튼 표시) |
| opening | { start: string; duration: number } | undefined | 오프닝 구간(해당 구간 진입 시 자동 스킵 또는 스킵 버튼 표시) |
| ending | { start: string; duration: number } | undefined | 엔딩 구간(해당 구간 진입 시 자동 스킵 또는 스킵 버튼 표시) |
-
start: 구간 시작 시점("HH:MM:SS" 형식, 예: "00:00:05", "00:01:30") -
duration: 구간 지속 시간(초 단위 숫자)
사용 예제
스킵 구간을 설정하는 예제는 다음과 같습니다.
import { VpePlayer } from "@sgrsoft/vpe-reactnative-tv-sdk";
export default function OttPlayer() {
return (
<VpePlayer
accessKey="YOUR_ACCESS_KEY"
options={{
playlist: [
{
file: "https://CDN_DOMAIN/episode_01.m3u8",
poster: "https://CDN_DOMAIN/episode_01.jpg",
intro: {
start: "00:00:00",
duration: 5,
},
opening: {
start: "00:00:05",
duration: 90,
},
ending: {
start: "00:45:00",
duration: 60,
},
},
],
autostart: true,
}}
onBack={() => navigation.goBack()}
/>
);
}
자동 스킵 동작
- 사용자가 직접
seek하여 오프닝/엔딩 구간에 진입한 경우 — 자동 스킵이 우회됩니다(사용자 의도 존중). - 내부 스킵(인트로 스킵 등)으로 오프닝 구간에 진입한 경우 — 자동 스킵이 유지됩니다.
스킵 버튼 UI
- 컨트롤 바 표시 여부와 무관하게 고정 오버레이로 렌더링됩니다.
- 위치는
center레이아웃 하단 오프셋 기준으로 동기화됩니다. - 리모컨 D-pad로 스킵 버튼에 포커스 및 선택할 수 있습니다.
스킵 이벤트
스킵 동작 시 발생하는 이벤트는 다음과 같습니다.
| 이벤트 | 설명 |
|---|---|
| introSkip | 인트로 구간 스킵 시 발생 |
| openingSkip | 오프닝 구간 스킵 시 발생 |
| endingSkip | 엔딩 구간 스킵 시 발생 |
<VpePlayer
accessKey="YOUR_ACCESS_KEY"
options={{
playlist: [{
file: "https://CDN_DOMAIN/episode_01.m3u8",
intro: { start: "00:00:00", duration: 5 },
opening: { start: "00:00:05", duration: 90 },
ending: { start: "00:45:00", duration: 60 },
}],
}}
onEvent={(event) => {
switch (event.type) {
case "introSkip":
console.log("인트로 스킵됨");
break;
case "openingSkip":
console.log("오프닝 스킵됨");
break;
case "endingSkip":
console.log("엔딩 스킵됨");
break;
}
}}
onBack={() => navigation.goBack()}
/>
연령 등급 표시
PlaylistItem의 ageRating 값을 설정하면 재생 시작 후 연령 등급 오버레이가 자동으로 표시됩니다.
지원 등급
ageRating에 설정할 수 있는 값은 다음과 같습니다.
| 값 | 설명 |
|---|---|
| "all" | 전체 관람가 |
| "12" | 12세 이상 관람가 |
| "15" | 15세 이상 관람가 |
| "19" | 19세 이상 관람가(청소년 관람불가) |
오버레이 동작
- 재생 시작 후 3초 경과 시 1회 노출됩니다.
- fade + slide 모션으로 표시됩니다.
- 다국어 지원: ko / en / ja
사용 예제
ageRating을 설정하는 예제는 다음과 같습니다.
import { VpePlayer } from "@sgrsoft/vpe-reactnative-tv-sdk";
export default function AgeRatedPlayer() {
return (
<VpePlayer
accessKey="YOUR_ACCESS_KEY"
options={{
playlist: [{
file: "https://CDN_DOMAIN/episode_01.m3u8",
poster: "https://CDN_DOMAIN/episode_01.jpg",
description: {
title: "드라마 시즌1 EP.01",
profile_name: "OTT 채널",
},
ageRating: "15",
}],
autostart: true,
}}
onBack={() => navigation.goBack()}
/>
);
}
콘텐츠 경고
PlaylistItem의 contentWarnings 배열을 설정하면 재생 시작 시 해당 콘텐츠에 포함된 민감한 요소를 시청자에게 안내하는 경고 오버레이가 표시됩니다.
지원 경고 유형
contentWarnings에 설정할 수 있는 값은 다음과 같습니다.
| 값 | 설명 |
|---|---|
| "sexuality" | 선정성 |
| "violence" | 폭력성 |
| "language" | 언어(욕설/비속어) |
| "drugs" | 약물 |
| "horror" | 공포 |
| "imitation" | 모방 위험 |
| "provocative" | 선정적 자극 |
위 7개가 권장 키이며, 임의의 문자열도 사용할 수 있습니다.
사용 예제
contentWarnings를 설정하는 예제는 다음과 같습니다.
import { VpePlayer } from "@sgrsoft/vpe-reactnative-tv-sdk";
export default function ContentWarningPlayer() {
return (
<VpePlayer
accessKey="YOUR_ACCESS_KEY"
options={{
playlist: [{
file: "https://CDN_DOMAIN/episode_01.m3u8",
poster: "https://CDN_DOMAIN/episode_01.jpg",
contentWarnings: ["violence", "language"],
}],
autostart: true,
}}
onBack={() => navigation.goBack()}
/>
);
}
종합 예제
인트로/오프닝/엔딩 스킵, 연령 등급 표시, 콘텐츠 경고를 모두 적용한 예제는 다음과 같습니다.
import { VpePlayer, type PlayerHandle } from "@sgrsoft/vpe-reactnative-tv-sdk";
import { useRef, useCallback } from "react";
export default function FullOttPlayer() {
const playerRef = useRef<PlayerHandle>(null);
const handleEvent = useCallback((event: any) => {
switch (event.type) {
case "introSkip":
console.log("인트로 스킵됨");
break;
case "openingSkip":
console.log("오프닝 스킵됨");
break;
case "endingSkip":
console.log("엔딩 스킵됨 — 다음 에피소드로 이동");
// playerRef.current?.next();
break;
}
}, []);
return (
<VpePlayer
ref={playerRef}
accessKey="YOUR_ACCESS_KEY"
onEvent={handleEvent}
options={{
playlist: [
{
file: "https://CDN_DOMAIN/episode_01.m3u8",
poster: "https://CDN_DOMAIN/episode_01.jpg",
description: {
title: "드라마 시즌1 EP.01",
profile_name: "OTT 채널",
},
ageRating: "15",
contentWarnings: ["violence", "language"],
intro: { start: "00:00:00", duration: 5 },
opening: { start: "00:00:05", duration: 90 },
ending: { start: "00:45:00", duration: 60 },
},
{
file: "https://CDN_DOMAIN/episode_02.m3u8",
poster: "https://CDN_DOMAIN/episode_02.jpg",
description: {
title: "드라마 시즌1 EP.02",
profile_name: "OTT 채널",
},
ageRating: "15",
contentWarnings: ["violence"],
intro: { start: "00:00:00", duration: 5 },
opening: { start: "00:00:05", duration: 90 },
ending: { start: "00:45:00", duration: 60 },
},
],
autostart: true,
}}
onBack={() => navigation.goBack()}
/>
);
}