이어서 시청하기는 연속 클러스터를 활용하여 여러 앱의 완료되지 않은 동영상과 동일한 TV 시즌에서 시청할 다음 에피소드를 하나의 UI 그룹으로 표시합니다. 이 연속 클러스터에서 해당 항목을 추천할 수 있습니다. 이 가이드를 따라 Engage SDK를 사용하여 '이어보기' 환경을 통해 사용자 참여도를 높이는 방법을 알아보세요.
사전 작업
시작하기 전에 다음 단계를 완료하세요.
API 19 이상을 타겟팅하도록 업데이트
다음과 같이
com.google.android.engage
라이브러리를 앱에 추가합니다.통합에 사용할 SDK는 모바일 앱용과 TV 앱용으로 구분됩니다.
모바일
dependencies { implementation 'com.google.android.engage:engage-core:1.5.5 }
TV
dependencies { implementation 'com.google.android.engage:engage-tv:1.0.2 }
AndroidManifest.xml
파일에서 Engage 서비스 환경을 프로덕션으로 설정합니다.모바일
<meta-data android:name="com.google.android.engage.service.ENV" android:value="PRODUCTION" />
TV
<meta-data android:name="com.google.android.engage.service.ENV" android:value="PRODUCTION" />
TV APK에
WRITE_EPG_DATA
권한 추가<uses-permission android:name="com.android.providers.tv.permission.WRITE_EPG_DATA" />
androidx.work
와 같은 백그라운드 서비스를 사용하여 안정적인 콘텐츠 게시를 확인합니다.원활한 시청 환경을 제공하려면 다음 이벤트가 발생할 때 이어보기 데이터를 게시하세요.
- 첫 로그인: 사용자가 처음 로그인할 때 시청 기록을 즉시 사용할 수 있도록 데이터를 게시합니다.
- 프로필 생성 또는 전환 (다중 프로필 앱): 앱이 여러 프로필을 지원하는 경우 사용자가 프로필을 만들거나 전환할 때 데이터를 게시합니다.
- 동영상 재생 중단: 사용자가 중단한 지점부터 다시 시작할 수 있도록 사용자가 동영상을 일시중지하거나 중지할 때 또는 재생 중에 앱이 종료될 때 데이터를 게시합니다.
- 이어서 시청하기 트레이 업데이트 (지원되는 경우): 사용자가 이어서 시청하기 트레이에서 항목을 삭제하면 업데이트된 데이터를 게시하여 변경사항을 반영합니다.
- 동영상 완료:
- 영화의 경우 시청이 완료된 영화를 '이어서 시청하기' 트레이에서 삭제합니다. 영화가 시리즈에 속하는 경우 사용자의 참여를 유도하기 위해 다음 영화를 추가합니다.
- 에피소드의 경우 시청이 완료된 에피소드를 삭제하고 시리즈의 다음 에피소드를 추가하여 지속적인 시청을 유도합니다(사용 가능한 경우).
통합
AccountProfile
Google TV에서 맞춤형 '이어보기' 환경을 허용하려면 계정 및 프로필 정보를 제공하세요. AccountProfile을 사용하여 다음을 제공합니다.
계정 ID: 애플리케이션 내에서 사용자 계정을 나타내는 고유 식별자입니다. 실제 계정 ID 또는 적절하게 난독화된 버전일 수 있습니다.
프로필 ID (선택사항): 애플리케이션이 단일 계정 내에서 여러 프로필을 지원하는 경우 특정 사용자 프로필의 고유 식별자(실제 또는 난독화된)를 제공합니다.
// If your app only supports account
val accountProfile = AccountProfile.Builder()
.setAccountId("your_users_account_id")
.build()
// If your app supports both account and profile
val accountProfile = AccountProfile.Builder()
.setAccountId("your_users_account_id")
.setProfileId("your_users_profile_id")
.build()
항목 만들기
SDK는 각 항목 유형을 나타내는 여러 항목을 정의했습니다. 연속 클러스터는 다음 항목을 지원합니다.
이러한 항목의 플랫폼별 URI와 포스터 이미지를 지정합니다.
아직 만들지 않은 경우 Android TV, Android, iOS와 같은 각 플랫폼의 재생 URI도 만듭니다. 따라서 사용자가 각 플랫폼에서 계속 시청하면 앱은 타겟팅된 재생 URI를 사용하여 동영상 콘텐츠를 재생합니다.
// Required. Set this when you want continue watching entities to show up on
// Google TV
val playbackUriTv = PlatformSpecificUri.Builder()
.setPlatformType(PlatformType.TYPE_ANDROID_TV)
.setActionUri(Uri.parse("https://www.example.com/entity_uri_for_tv"))
.build()
// Required. Set this when you want continue watching entities to show up on
// Google TV Android app, Entertainment Space, Playstore Widget
val playbackUriAndroid = PlatformSpecificUri.Builder()
.setPlatformType(PlatformType.TYPE_ANDROID_MOBILE)
.setActionUri(Uri.parse("https://www.example.com/entity_uri_for_android"))
.build()
// Optional. Set this when you want continue watching entities to show up on
// Google TV iOS app
val playbackUriIos = PlatformSpecificUri.Builder()
.setPlatformType(PlatformType.TYPE_IOS)
.setActionUri(Uri.parse("https://www.example.com/entity_uri_for_ios"))
.build()
val platformSpecificPlaybackUris =
Arrays.asList(playbackUriTv, playbackUriAndroid, playbackUriIos)
포스터 이미지에는 URI와 픽셀 크기 (높이 및 너비)가 필요합니다. 여러 포스터 이미지를 제공하여 다양한 폼 팩터를 타겟팅하되, 특히 Google의 엔터테인먼트 스페이스 내에서 '계속 시청' 항목이 올바르게 표시되도록 모든 이미지가 16:9 가로세로 비율과 최소 높이 200픽셀을 유지하는지 확인하세요. 높이가 200픽셀 미만인 이미지는 표시되지 않을 수 있습니다.
val images = Arrays.asList(
Image.Builder()
.setImageUri(Uri.parse("http://www.example.com/entity_image1.png"))
.setImageHeightInPixel(300)
.setImageWidthInPixel(169)
.build(),
Image.Builder()
.setImageUri(Uri.parse("http://www.example.com/entity_image2.png"))
.setImageHeightInPixel(640)
.setImageWidthInPixel(360)
.build()
// Consider adding other images for different form factors
)
MovieEntity
이 예에서는 모든 필수 필드를 사용하여 MovieEntity
를 만드는 방법을 보여줍니다.
val movieEntity = MovieEntity.Builder()
.setWatchNextType(WatchNextType.TYPE_CONTINUE)
.setName("Movie name")
.addPlatformSpecificPlaybackUri(platformSpecificPlaybackUris)
.addPosterImages(images)
// Timestamp in millis for sample last engagement time 12/1/2023 00:00:00
.setLastEngagementTimeMillis(1701388800000)
// Suppose the duration is 2 hours, it is 72000000 in milliseconds
.setDurationMills(72000000)
// Suppose last playback offset is 1 hour, 36000000 in milliseconds
.setLastPlayBackPositionTimeMillis(36000000)
.build()
장르 및 콘텐츠 등급과 같은 세부정보를 제공하면 Google TV에서 콘텐츠를 더욱 동적으로 표시하고 적합한 시청자에게 연결할 수 있습니다.
val genres = Arrays.asList("Action", "Science fiction")
val rating1 = RatingSystem.Builder().setAgencyName("MPAA").setRating("PG-13").build()
val contentRatings = Arrays.asList(rating1)
val movieEntity = MovieEntity.Builder()
...
.addGenres(genres)
.addContentRatings(contentRatings)
.build()
만료 시간을 더 짧게 지정하지 않는 한 엔티티는 자동으로 60일 동안 사용할 수 있습니다. 이 기본 기간 전에 항목을 삭제해야 하는 경우에만 맞춤 만료를 설정하세요.
// Set the expiration time to be now plus 30 days in milliseconds
val expirationTime = DisplayTimeWindow.Builder()
.setEndTimestampMillis(now().toMillis()+2592000000).build()
val movieEntity = MovieEntity.Builder()
...
.addAvailabilityTimeWindow(expirationTime)
.build()
TvEpisodeEntity
이 예에서는 필수 필드가 모두 포함된 TvEpisodeEntity
를 만드는 방법을 보여줍니다.
val tvEpisodeEntity = TvEpisodeEntity.Builder()
.setWatchNextType(WatchNextType.TYPE_CONTINUE)
.setName("Episode name")
.addPlatformSpecificPlaybackUri(platformSpecificPlaybackUris)
.addPosterImages(images)
// Timestamp in millis for sample last engagement time 12/1/2023 00:00:00
.setLastEngagementTimeMillis(1701388800000)
.setDurationMills(72000000) // 2 hours in milliseconds
// 45 minutes and 15 seconds in milliseconds is 2715000
.setLastPlayBackPositionTimeMillis(2715000)
.setEpisodeNumber("2")
.setSeasonNumber("1")
.setShowTitle("Title of the show")
.build()
에피소드 번호 문자열 (예: "2"
)과 시즌 번호 문자열 (예: "1"
)은 계속 시청 카드에 표시되기 전에 적절한 형식으로 확장됩니다. 숫자 문자열이어야 합니다. 'e2' 또는 'episode 2', 's1' 또는 'season 1'을 입력하지 마세요.
특정 TV 프로그램에 시즌이 하나만 있는 경우 시즌 번호를 1로 설정합니다.
시청자가 Google TV에서 내 콘텐츠를 찾을 가능성을 극대화하려면 장르, 콘텐츠 등급, 사용 가능 시간대와 같은 추가 데이터를 제공하는 것이 좋습니다. 이러한 세부정보는 표시 및 필터링 옵션을 개선할 수 있기 때문입니다.
val genres = Arrays.asList("Action", "Science fiction")
val rating1 = RatingSystem.Builder().setAgencyName("MPAA").setRating("PG-13").build()
val contentRatings = Arrays.asList(rating1)
val tvEpisodeEntity = TvEpisodeEntity.Builder()
...
.addGenres(genres)
.addContentRatings(contentRatings)
.setSeasonTitle("Season Title")
.setShowTitle("Show Title")
.build()
VideoClipEntity
다음은 모든 필수 입력란을 사용하여 VideoClipEntity
를 만드는 예입니다.
VideoClipEntity
는 YouTube 동영상과 같은 사용자 생성 클립을 나타냅니다.
val videoClipEntity = VideoClipEntity.Builder()
.setPlaybackUri(Uri.parse("https://www.example.com/uri_for_current_platform")
.setWatchNextType(WatchNextType.TYPE_CONTINUE)
.setName("Video clip name")
.addPlatformSpecificPlaybackUri(platformSpecificPlaybackUris)
.addPosterImages(images)
// Timestamp in millis for sample last engagement time 12/1/2023 00:00:00
.setLastEngagementTimeMillis(1701388800000)
.setDurationMills(600000) //10 minutes in milliseconds
.setLastPlayBackPositionTimeMillis(300000) //5 minutes in milliseconds
.addContentRating(contentRating)
.build()
선택적으로 작성자, 작성자 이미지, 생성 시간(밀리초) 또는 사용 가능 시간 창을 설정할 수 있습니다 .
LiveStreamingVideoEntity
다음은 필수 입력란이 모두 포함된 LiveStreamingVideoEntity
를 만드는 예입니다.
val liveStreamingVideoEntity = LiveStreamingVideoEntity.Builder()
.setPlaybackUri(Uri.parse("https://www.example.com/uri_for_current_platform")
.setWatchNextType(WatchNextType.TYPE_CONTINUE)
.setName("Live streaming name")
.addPlatformSpecificPlaybackUri(platformSpecificPlaybackUris)
.addPosterImages(images)
// Timestamp in millis for sample last engagement time 12/1/2023 00:00:00
.setLastEngagementTimeMillis(1701388800000)
.setDurationMills(72000000) //2 hours in milliseconds
.setLastPlayBackPositionTimeMillis(36000000) //1 hour in milliseconds
.addContentRating(contentRating)
.build()
원하는 경우 라이브 스트리밍 항목의 시작 시간, 방송인, 방송인 아이콘 또는 사용 가능 시간대를 설정할 수 있습니다.
속성 및 요구사항에 관한 자세한 내용은 API 참조를 확인하세요.
연속 클러스터 데이터 제공
AppEngagePublishClient
는 연속 클러스터 게시를 담당합니다.
publishContinuationCluster()
메서드를 사용하여 ContinuationCluster
객체를 게시합니다.
먼저 isServiceAvailable()을 사용하여 서비스를 통합에 사용할 수 있는지 확인해야 합니다.
client.publishContinuationCluster(
PublishContinuationClusterRequest
.Builder()
.setContinuationCluster(
ContinuationCluster.Builder()
.setAccountProfile(accountProfile)
.addEntity(movieEntity1)
.addEntity(movieEntity2)
.addEntity(tvEpisodeEntity1)
.addEntity(tvEpisodeEntity2)
.setSyncAcrossDevices(true)
.build()
)
.build()
)
서비스가 요청을 수신하면 다음 작업이 한 트랜잭션 내에서 발생합니다.
- 개발자 파트너의 기존
ContinuationCluster
데이터가 삭제됩니다. - 요청 데이터가 파싱되어 업데이트된
ContinuationCluster
에 저장됩니다.
오류가 발생하면 전체 요청이 거부되고 기존 상태가 유지됩니다.
게시 API는 upsert API입니다. 기존 콘텐츠를 대체합니다. ContinuationCluster에서 특정 항목을 업데이트해야 하는 경우 모든 항목을 다시 게시해야 합니다.
ContinuationCluster 데이터는 성인 계정에만 제공해야 합니다. AccountProfile이 성인에 속하는 경우에만 게시합니다.
교차 기기 동기화
SyncAcrossDevices
플래그는 사용자의 ContinuationCluster
데이터가 TV, 휴대전화, 태블릿 등의 기기 간에 동기화되는지 여부를 제어합니다. 기기 간 동기화는 기본적으로 사용 중지되어 있습니다.
값:
- true: 원활한 시청 환경을 위해 ContinuationCluster 데이터가 모든 사용자의 기기에서 공유됩니다. 최적의 교차 기기 환경을 위해 이 옵션을 적극 권장합니다.
- false: ContinuationCluster 데이터는 현재 기기로 제한됩니다.
동의 얻기:
미디어 애플리케이션은 기기 간 동기화를 사용 설정/중지하는 명확한 설정을 제공해야 합니다. 사용자에게 이점을 설명하고 사용자의 환경설정을 한 번 저장한 후 publishContinuationCluster에 적절히 적용합니다.
// Example to allow cross device syncing.
client.publishContinuationCluster(
PublishContinuationClusterRequest
.Builder()
.setContinuationCluster(
ContinuationCluster.Builder()
.setAccountProfile(accountProfile)
.setSyncAcrossDevices(true)
.build()
)
.build()
)
교차 기기 기능을 최대한 활용하려면 앱이 사용자 동의를 얻고 SyncAcrossDevices
를 true
로 사용 설정해야 합니다. 이를 통해 콘텐츠가 기기 간에 원활하게 동기화되어 사용자 환경이 개선되고 참여도가 높아집니다. 예를 들어 이 기능을 구현한 파트너는 콘텐츠가 여러 기기에 표시되어 '이어보기' 클릭수가 40% 증가했습니다.
동영상 디스커버리 데이터 삭제
표준 60일 보관 기간 전에 Google TV 서버에서 사용자의 데이터를 수동으로 삭제하려면 client.deleteClusters() 메서드를 사용하세요. 요청을 수신하면 서비스는 계정 프로필 또는 전체 계정의 기존 동영상 탐색 데이터를 모두 삭제합니다.
DeleteReason
enum은 데이터 삭제 이유를 정의합니다.
다음 코드는 로그아웃 시 이어보기 데이터를 삭제합니다.
// If the user logs out from your media app, you must make the following call
// to remove continue watching data from the current google TV device,
// otherwise, the continue watching data will persist on the current
// google TV device until 60 days later.
client.deleteClusters(
DeleteClustersRequest.Builder()
.setAccountProfile(AccountProfile())
.setReason(DeleteReason.DELETE_REASON_USER_LOG_OUT)
.setSyncAcrossDevices(true)
.build()
)
테스트
인증 앱을 사용하여 Engage SDK 통합이 올바르게 작동하는지 확인합니다. 이 Android 애플리케이션은 데이터를 확인하고 브로드캐스트 인텐트가 올바르게 처리되고 있는지 확인할 수 있는 도구를 제공합니다.
게시 API를 호출한 후 확인 앱을 확인하여 데이터가 올바르게 게시되었는지 확인합니다. 연속 클러스터는 앱 인터페이스 내에 별도의 행으로 표시되어야 합니다.
- 앱의 Android 매니페스트 파일에서 비프로덕션 빌드에만 서비스 참여 플래그를 설정합니다.
- Engage Verify 앱 설치 및 열기
isServiceAvailable
이false
이면 '전환' 버튼을 클릭하여 사용 설정합니다.- 게시를 시작하면 게시된 데이터를 자동으로 볼 수 있도록 앱의 패키지 이름을 입력합니다.
- 앱에서 다음 작업을 테스트합니다.
- 로그인합니다.
- 프로필 간 전환(해당하는 경우)
- 동영상을 시작한 다음 일시중지하거나 홈페이지로 돌아갑니다.
- 동영상 재생 중에 앱을 닫습니다.
- '계속 시청' 행에서 항목을 삭제합니다 (지원되는 경우).
- 각 작업 후 앱이
publishContinuationClusters
API를 호출하고 데이터가 확인 앱에 올바르게 표시되는지 확인합니다. 인증 앱에는 올바르게 구현된 항목에 대해 녹색 'All Good' 체크가 표시됩니다.
그림 1. 인증 앱 성공 확인 앱은 문제가 있는 항목을 표시합니다.
그림 2. 인증 앱 오류 오류가 있는 항목을 해결하려면 TV 리모컨을 사용하여 확인 앱에서 항목을 선택하고 클릭합니다. 특정 문제가 표시되고 검토를 위해 빨간색으로 강조 표시됩니다 (아래 예 참고).
그림 3. 인증 앱 오류 세부정보
REST API
Engage SDK는 iOS, Roku TV와 같은 Android가 아닌 플랫폼에서 일관된 이어보기 환경을 제공하는 REST API를 제공합니다. 이 API를 사용하면 개발자가 Android 이외의 플랫폼에서 선택한 사용자의 '이어보기' 상태를 업데이트할 수 있습니다.
기본 요건
- 먼저 온디바이스 Engage SDK 기반 통합을 완료해야 합니다.
이 중요한 단계를 통해 Google의 사용자 ID와 앱의
AccountProfile
간에 필요한 연결이 설정됩니다. - API 액세스 및 인증: Google Cloud 프로젝트에서 API를 보고 사용 설정하려면 허용 목록 프로세스를 거쳐야 합니다. 모든 API 요청에는 인증이 필요합니다.
액세스 권한 얻기
Google Cloud 콘솔에서 API를 보고 사용 설정하려면 계정이 등록되어 있어야 합니다.
- Google Workspace 고객 ID를 사용할 수 있어야 합니다. 사용할 수 없는 경우 Google Workspace와 API를 호출하는 데 사용할 Google 계정을 설정해야 할 수 있습니다.
- Google Workspace와 연결된 이메일을 사용하여 Google Cloud 콘솔로 계정을 설정합니다.
- 새 프로젝트 생성
- API 인증을 위한 서비스 계정을 만듭니다. 서비스 계정을 만들면 다음 두 항목이 표시됩니다.
- 서비스 계정 ID입니다.
- 서비스 계정 키가 포함된 JSON 파일 나중에 클라이언트를 API에 인증하는 데 필요하므로 이 파일을 안전하게 보관하세요.
- 이제 Workspace 및 연결된 Google 계정에서 REST API를 사용할 수 있습니다. 변경사항이 전파되면 서비스 계정에서 API를 호출할 준비가 되었는지 알림이 전송됩니다.
- 위임된 API 호출을 준비하려면 다음 단계를 따르세요.
연속 클러스터 게시
동영상 탐색 데이터를 게시하려면 다음 구문을 사용하여 publishContinuationCluster
API에 POST 요청을 실행합니다.
https://tvvideodiscovery.googleapis.com/v1/packages/{package_name}/accounts/{account_id}/profiles/{profile_id}/publishContinuationCluster
각각의 의미는 다음과 같습니다.
package_name
: 미디어 제공업체 패키지 이름accountId
: 시스템에 있는 사용자 계정의 고유 ID입니다. 온디바이스 경로에 사용된accountId
와 일치해야 합니다.profileId
: 시스템 내 계정의 사용자 프로필에 대한 고유 ID입니다. 온디바이스 경로에 사용된 profileId와 일치해야 합니다.
프로필이 없는 계정의 URL은 다음과 같습니다.
https://tvvideodiscovery.googleapis.com/v1/packages/{package_name}/accounts/{account_id}/publishContinuationCluster
요청 페이로드는 entities
필드에 표시됩니다. entities
는 MovieEntity
또는 TVEpisodeEntity
일 수 있는 콘텐츠 항목 목록을 나타냅니다. 필수 입력란입니다.
요청 본문
입력란 |
유형 |
필수 항목 |
설명 |
entities |
MediaEntity 객체 목록 |
예 |
콘텐츠 항목 목록 (최대 5개). 상위 5개만 유지되고 나머지는 삭제됩니다. 사용자가 모든 항목을 시청했음을 나타내기 위해 빈 목록이 허용됩니다. |
entities
필드에는 개별 movieEntity
및 tvEpisodeEntity
가 포함됩니다.
입력란 |
유형 |
필수 항목 |
설명 |
movieEntity |
MovieEntity |
예 |
ContinuationCluster 내의 영화를 나타내는 객체입니다. |
tvEpisodeEntity |
TvEpisodeEntity |
예 |
ContinuationCluster 내의 TV 에피소드를 나타내는 객체입니다. |
entities 배열의 각 객체는 공통 필드 및 유형별 필드와 함께 사용 가능한 MediaEntity 유형(MovieEntity
및 TvEpisodeEntity
) 중 하나여야 합니다.
다음 코드 스니펫은 publishContinuationCluster
API의 요청 본문 페이로드를 보여줍니다.
{
"entities": [
{
"movieEntity": {
"watch_next_type": "WATCH_NEXT_TYPE_CONTINUE",
"name": "Movie1",
"platform_specific_playback_uris": [
"https://www.example.com/entity_uri_for_android",
"https://www.example.com/entity_uri_for_iOS"
],
"poster_images": [
"http://www.example.com/movie1_img1.png",
"http://www.example.com/movie1_imag2.png"
],
"last_engagement_time_millis": 864600000,
"duration_millis": 5400000,
"last_play_back_position_time_millis": 3241111
}
},
{
"tvEpisodeEntity": {
"watch_next_type": "WATCH_NEXT_TYPE_CONTINUE",
"name": "TV SERIES EPISODE 1",
"platform_specific_playback_uris": [
"https://www.example.com/entity_uri_for_android",
"https://www.example.com/entity_uri_for_iOS"
],
"poster_images": [
"http://www.example.com/episode1_img1.png",
"http://www.example.com/episode1_imag2.png"
],
"last_engagement_time_millis": 864600000,
"duration_millis": 1800000,
"last_play_back_position_time_millis": 2141231,
"episode_display_number": "1",
"season_number": "1",
"show_title": "title"
}
}
]
}
동영상 디스커버리 데이터 삭제
clearClusters
API를 사용하여 동영상 탐색 데이터를 삭제합니다.
POST URL을 사용하여 동영상 검색 데이터에서 항목을 삭제합니다.
연속 클러스터 데이터를 삭제하려면 다음 구문을 사용하여 clearClusters
API에 POST 요청을 실행합니다.
https://tvvideodiscovery.googleapis.com/v1/packages/{package_name}/accounts/{account_id}/profiles/{profile_id}/clearClusters
각각의 의미는 다음과 같습니다.
package_name
: 미디어 제공업체 패키지 이름입니다.accountId
: 시스템에 있는 사용자 계정의 고유 ID입니다. 온디바이스 경로에 사용된accountId
와 일치해야 합니다.profileId
: 시스템 내 계정의 사용자 프로필에 대한 고유 ID입니다. 온디바이스 경로에 사용된 profileId와 일치해야 합니다.
clearClusters
API의 페이로드에는 데이터 삭제 이유를 지정하는 DeleteReason
가 포함된 reason
필드 하나만 포함됩니다.
{
"reason": "DELETE_REASON_LOSS_OF_CONSENT"
}
테스트
데이터를 성공적으로 게시한 후 사용자 테스트 계정을 사용하여 Google TV, Android 및 iOS Google TV 모바일 앱과 같은 타겟 Google 표시 경로의 '이어보기' 행에 예상 콘텐츠가 표시되는지 확인합니다.
테스트에서는 몇 분 정도의 적절한 전파 지연을 허용하고 영화의 일부를 시청하거나 에피소드를 완료하는 등 시청 요구사항을 준수하세요. 자세한 내용은 앱 개발자를 위한 다음 볼만한 동영상 가이드라인을 참고하세요.