@moviie/player-expo 0.4.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.
- package/LICENSE +21 -0
- package/README.md +230 -0
- package/app.plugin.cjs +3 -0
- package/dist/cast.cjs +100 -0
- package/dist/cast.cjs.map +1 -0
- package/dist/cast.d.cts +15 -0
- package/dist/cast.d.ts +15 -0
- package/dist/cast.mjs +92 -0
- package/dist/cast.mjs.map +1 -0
- package/dist/chunk-67DJ7NOB.mjs +294 -0
- package/dist/chunk-67DJ7NOB.mjs.map +1 -0
- package/dist/chunk-7U2LKIGU.mjs +12 -0
- package/dist/chunk-7U2LKIGU.mjs.map +1 -0
- package/dist/chunk-BJTO5JO5.mjs +10 -0
- package/dist/chunk-BJTO5JO5.mjs.map +1 -0
- package/dist/index.cjs +3934 -0
- package/dist/index.cjs.map +1 -0
- package/dist/index.d.cts +450 -0
- package/dist/index.d.ts +450 -0
- package/dist/index.mjs +3571 -0
- package/dist/index.mjs.map +1 -0
- package/dist/layout.cjs +217 -0
- package/dist/layout.cjs.map +1 -0
- package/dist/layout.d.cts +20 -0
- package/dist/layout.d.ts +20 -0
- package/dist/layout.mjs +4 -0
- package/dist/layout.mjs.map +1 -0
- package/dist/moviie-cast-adapter-DmSU2u3j.d.cts +53 -0
- package/dist/moviie-cast-adapter-DmSU2u3j.d.ts +53 -0
- package/dist/plugin/with-moviie.cjs +88 -0
- package/dist/plugin/with-moviie.cjs.map +1 -0
- package/dist/plugin/with-moviie.d.cts +52 -0
- package/dist/plugin/with-moviie.d.ts +52 -0
- package/dist/plugin/with-moviie.mjs +76 -0
- package/dist/plugin/with-moviie.mjs.map +1 -0
- package/package.json +134 -0
- package/plugin/validate-options.ts +31 -0
- package/plugin/with-moviie-types.ts +21 -0
- package/plugin/with-moviie.ts +84 -0
- package/src/apply-expo-moviie-endpoints.ts +47 -0
- package/src/cast/google-cast-adapter.ts +111 -0
- package/src/cast/index.ts +12 -0
- package/src/components/controls/moviie-bottom-timeline.tsx +477 -0
- package/src/components/controls/moviie-cast-buttons.tsx +96 -0
- package/src/components/controls/moviie-chrome-edge-gradients.tsx +162 -0
- package/src/components/controls/moviie-controls.tsx +585 -0
- package/src/components/controls/moviie-skin-chrome-context.tsx +374 -0
- package/src/components/controls/moviie-skin-smart-progress.tsx +157 -0
- package/src/components/icons/embed-media-icons.tsx +282 -0
- package/src/components/icons/moviie-embed-brand-mark.tsx +58 -0
- package/src/components/moviie-error-boundary.tsx +80 -0
- package/src/components/moviie-player-error-shell.tsx +143 -0
- package/src/components/moviie-player-loading-shell.tsx +59 -0
- package/src/components/moviie-skin-custom-fullscreen-modal.tsx +232 -0
- package/src/components/moviie-video-props.ts +134 -0
- package/src/components/moviie-video.tsx +568 -0
- package/src/components/moviie-video.web.tsx +167 -0
- package/src/components/overlays/moviie-watermark.tsx +53 -0
- package/src/constants.ts +374 -0
- package/src/hooks/use-moviie-event.ts +103 -0
- package/src/hooks/use-moviie-playback-ended.ts +14 -0
- package/src/hooks/use-moviie-playback-resume-persistence.ts +76 -0
- package/src/hooks/use-moviie-playback.ts +99 -0
- package/src/hooks/use-moviie-player-types.ts +55 -0
- package/src/hooks/use-moviie-player.ts +236 -0
- package/src/hooks/use-moviie-player.web.ts +57 -0
- package/src/hooks/use-moviie-telemetry.ts +133 -0
- package/src/index.ts +90 -0
- package/src/layout.ts +4 -0
- package/src/lib/add-moviie-playback-ended-listener.ts +16 -0
- package/src/lib/build-moviie-branding-marketing-url.ts +14 -0
- package/src/lib/build-moviie-embed-brand-home-url.ts +16 -0
- package/src/lib/build-moviie-skin-layout-metrics.ts +166 -0
- package/src/lib/build-moviie-video-presentation.ts +42 -0
- package/src/lib/build-moviie-watch-embed-url.ts +30 -0
- package/src/lib/cast-adapter-registry.ts +13 -0
- package/src/lib/clamp-unit-interval.ts +3 -0
- package/src/lib/compute-custom-fullscreen-stage-dimensions.ts +39 -0
- package/src/lib/compute-moviie-playback-ended.ts +31 -0
- package/src/lib/compute-playback-buffering.ts +41 -0
- package/src/lib/compute-playback-progress-ratio.ts +33 -0
- package/src/lib/compute-timeline-scrub-commit-time.ts +40 -0
- package/src/lib/custom-fullscreen-native-orientation.ts +88 -0
- package/src/lib/format-playback-clock.ts +27 -0
- package/src/lib/jsx-native-bridge.ts +45 -0
- package/src/lib/map-smart-progress-display-ratio.ts +43 -0
- package/src/lib/moviie-cast-adapter.ts +53 -0
- package/src/lib/moviie-error-display.ts +149 -0
- package/src/lib/moviie-shell-tokens.ts +27 -0
- package/src/lib/moviie-telemetry-callbacks.ts +76 -0
- package/src/lib/optional-status-bar.ts +48 -0
- package/src/lib/partition-moviie-video-host-style.ts +54 -0
- package/src/lib/remember-playback-position-storage.ts +98 -0
- package/src/lib/resolve-moviie-skin-layout-scale.ts +17 -0
- package/src/lib/resolve-orientation-lock-for-rotate-z-deg.ts +21 -0
- package/src/lib/resolve-skin-accent-color.ts +10 -0
- package/src/lib/resolve-web-embed-iframe-src.ts +17 -0
- package/src/lib/warn-once.ts +23 -0
- package/src/platform/native-application-id.ts +10 -0
- package/src/platform/platform-client-info.ts +31 -0
- package/src/playback/fetch-playback-fresh.ts +27 -0
- package/src/playback/playback-memory-cache.ts +52 -0
- package/src/provider/moviie-provider.tsx +99 -0
- package/src/secure-store-viewer-token-store.ts +80 -0
|
@@ -0,0 +1,232 @@
|
|
|
1
|
+
import {
|
|
2
|
+
forwardRef,
|
|
3
|
+
type ReactNode,
|
|
4
|
+
useCallback,
|
|
5
|
+
useEffect,
|
|
6
|
+
useImperativeHandle,
|
|
7
|
+
useMemo,
|
|
8
|
+
useRef,
|
|
9
|
+
} from 'react'
|
|
10
|
+
import { Modal, Platform, StyleSheet, useWindowDimensions, View } from 'react-native'
|
|
11
|
+
import Animated, {
|
|
12
|
+
runOnJS,
|
|
13
|
+
useAnimatedStyle,
|
|
14
|
+
useSharedValue,
|
|
15
|
+
withTiming,
|
|
16
|
+
} from 'react-native-reanimated'
|
|
17
|
+
import { SafeAreaProvider, useSafeAreaInsets } from 'react-native-safe-area-context'
|
|
18
|
+
import { moviieSetStatusBarHidden } from '../lib/optional-status-bar'
|
|
19
|
+
|
|
20
|
+
import {
|
|
21
|
+
MOVIIE_SKIN_CUSTOM_FULLSCREEN_ENTER_SCALE_START,
|
|
22
|
+
MOVIIE_SKIN_CUSTOM_FULLSCREEN_ROTATE_Z_DEGREES,
|
|
23
|
+
MOVIIE_SKIN_CUSTOM_FULLSCREEN_STAGE_BACKGROUND_HEX,
|
|
24
|
+
MOVIIE_SKIN_CUSTOM_FULLSCREEN_STAGE_OVERSCAN_PX,
|
|
25
|
+
MOVIIE_SKIN_CUSTOM_FULLSCREEN_TRANSITION_MS,
|
|
26
|
+
} from '../constants'
|
|
27
|
+
import { computeCustomFullscreenStageDimensions } from '../lib/compute-custom-fullscreen-stage-dimensions'
|
|
28
|
+
import { subscribeCustomFullscreenNativeOrientation } from '../lib/custom-fullscreen-native-orientation'
|
|
29
|
+
import { ReanimatedView } from '../lib/jsx-native-bridge'
|
|
30
|
+
import { resolveOrientationLockValueForRotateZDeg } from '../lib/resolve-orientation-lock-for-rotate-z-deg'
|
|
31
|
+
|
|
32
|
+
const CUSTOM_FULLSCREEN_TIMING = {
|
|
33
|
+
duration: MOVIIE_SKIN_CUSTOM_FULLSCREEN_TRANSITION_MS,
|
|
34
|
+
} as const
|
|
35
|
+
|
|
36
|
+
/**
|
|
37
|
+
* Em iOS/Android o fullscreen usa `expo-screen-orientation`: o referencial da janela passa a landscape.
|
|
38
|
+
* Rotação Z adicional somaria com a orientação nativa e invertia o resultado.
|
|
39
|
+
* Na web mantemos rotação só em JS (sem lock nativo fiável no nosso fluxo).
|
|
40
|
+
*/
|
|
41
|
+
const CUSTOM_FULLSCREEN_USE_JS_STAGE_ROTATION = Platform.OS === 'web'
|
|
42
|
+
|
|
43
|
+
export type MoviieSkinCustomFullscreenModalHandle = {
|
|
44
|
+
animateExit: () => void
|
|
45
|
+
}
|
|
46
|
+
|
|
47
|
+
export type MoviieSkinCustomFullscreenModalProps = {
|
|
48
|
+
visible: boolean
|
|
49
|
+
onExitComplete: () => void
|
|
50
|
+
children: ReactNode
|
|
51
|
+
}
|
|
52
|
+
|
|
53
|
+
const MoviieSkinCustomFullscreenModalInner = forwardRef<
|
|
54
|
+
MoviieSkinCustomFullscreenModalHandle,
|
|
55
|
+
MoviieSkinCustomFullscreenModalProps
|
|
56
|
+
>(function MoviieSkinCustomFullscreenModalInner(props, ref) {
|
|
57
|
+
const orientationFinishRef = useRef<(() => Promise<void>) | null>(null)
|
|
58
|
+
|
|
59
|
+
const insets = useSafeAreaInsets()
|
|
60
|
+
const { height: winH, width: winW } = useWindowDimensions()
|
|
61
|
+
|
|
62
|
+
const { longSide, shortSide } = useMemo(
|
|
63
|
+
() =>
|
|
64
|
+
computeCustomFullscreenStageDimensions({
|
|
65
|
+
windowHeight: winH,
|
|
66
|
+
safeInsets: insets,
|
|
67
|
+
stageOverscanPx: MOVIIE_SKIN_CUSTOM_FULLSCREEN_STAGE_OVERSCAN_PX,
|
|
68
|
+
windowWidth: winW,
|
|
69
|
+
}),
|
|
70
|
+
[winW, winH, insets.bottom, insets.left, insets.right, insets.top]
|
|
71
|
+
)
|
|
72
|
+
|
|
73
|
+
const rotateZDeg = useSharedValue(0)
|
|
74
|
+
const scale = useSharedValue(1)
|
|
75
|
+
|
|
76
|
+
const emitExitComplete = useCallback(() => {
|
|
77
|
+
props.onExitComplete()
|
|
78
|
+
}, [props.onExitComplete])
|
|
79
|
+
|
|
80
|
+
const completeExitAfterNativeOrientationRestore = useCallback(() => {
|
|
81
|
+
void (async () => {
|
|
82
|
+
await orientationFinishRef.current?.()
|
|
83
|
+
emitExitComplete()
|
|
84
|
+
})()
|
|
85
|
+
}, [emitExitComplete])
|
|
86
|
+
|
|
87
|
+
const animateExit = useCallback(() => {
|
|
88
|
+
scale.value = withTiming(
|
|
89
|
+
MOVIIE_SKIN_CUSTOM_FULLSCREEN_ENTER_SCALE_START,
|
|
90
|
+
CUSTOM_FULLSCREEN_TIMING,
|
|
91
|
+
(finishedScale) => {
|
|
92
|
+
if (!CUSTOM_FULLSCREEN_USE_JS_STAGE_ROTATION && finishedScale) {
|
|
93
|
+
runOnJS(completeExitAfterNativeOrientationRestore)()
|
|
94
|
+
}
|
|
95
|
+
}
|
|
96
|
+
)
|
|
97
|
+
|
|
98
|
+
if (CUSTOM_FULLSCREEN_USE_JS_STAGE_ROTATION) {
|
|
99
|
+
rotateZDeg.value = withTiming(0, CUSTOM_FULLSCREEN_TIMING, (finished) => {
|
|
100
|
+
if (finished) {
|
|
101
|
+
runOnJS(emitExitComplete)()
|
|
102
|
+
}
|
|
103
|
+
})
|
|
104
|
+
return
|
|
105
|
+
}
|
|
106
|
+
|
|
107
|
+
rotateZDeg.value = 0
|
|
108
|
+
}, [completeExitAfterNativeOrientationRestore, emitExitComplete, rotateZDeg, scale])
|
|
109
|
+
|
|
110
|
+
useImperativeHandle(ref, () => ({ animateExit }), [animateExit])
|
|
111
|
+
|
|
112
|
+
useEffect(() => {
|
|
113
|
+
if (!props.visible) {
|
|
114
|
+
return
|
|
115
|
+
}
|
|
116
|
+
rotateZDeg.value = 0
|
|
117
|
+
scale.value = MOVIIE_SKIN_CUSTOM_FULLSCREEN_ENTER_SCALE_START
|
|
118
|
+
if (CUSTOM_FULLSCREEN_USE_JS_STAGE_ROTATION) {
|
|
119
|
+
rotateZDeg.value = withTiming(
|
|
120
|
+
MOVIIE_SKIN_CUSTOM_FULLSCREEN_ROTATE_Z_DEGREES,
|
|
121
|
+
CUSTOM_FULLSCREEN_TIMING
|
|
122
|
+
)
|
|
123
|
+
}
|
|
124
|
+
scale.value = withTiming(1, CUSTOM_FULLSCREEN_TIMING)
|
|
125
|
+
}, [props.visible, rotateZDeg, scale])
|
|
126
|
+
|
|
127
|
+
useEffect(() => {
|
|
128
|
+
if (!props.visible) {
|
|
129
|
+
return
|
|
130
|
+
}
|
|
131
|
+
moviieSetStatusBarHidden(true, 'fade')
|
|
132
|
+
return () => {
|
|
133
|
+
moviieSetStatusBarHidden(false, 'fade')
|
|
134
|
+
}
|
|
135
|
+
}, [props.visible])
|
|
136
|
+
|
|
137
|
+
useEffect(() => {
|
|
138
|
+
if (!props.visible || CUSTOM_FULLSCREEN_USE_JS_STAGE_ROTATION) {
|
|
139
|
+
orientationFinishRef.current = null
|
|
140
|
+
return
|
|
141
|
+
}
|
|
142
|
+
|
|
143
|
+
const targetLock = resolveOrientationLockValueForRotateZDeg(
|
|
144
|
+
MOVIIE_SKIN_CUSTOM_FULLSCREEN_ROTATE_Z_DEGREES
|
|
145
|
+
)
|
|
146
|
+
const sub = subscribeCustomFullscreenNativeOrientation(targetLock)
|
|
147
|
+
orientationFinishRef.current = () => sub.finish()
|
|
148
|
+
|
|
149
|
+
return () => {
|
|
150
|
+
orientationFinishRef.current = null
|
|
151
|
+
void sub.finish()
|
|
152
|
+
}
|
|
153
|
+
}, [props.visible])
|
|
154
|
+
|
|
155
|
+
const animatedStyle = useAnimatedStyle(() => {
|
|
156
|
+
if (CUSTOM_FULLSCREEN_USE_JS_STAGE_ROTATION) {
|
|
157
|
+
return {
|
|
158
|
+
transform: [{ rotateZ: `${rotateZDeg.value}deg` }, { scale: scale.value }],
|
|
159
|
+
}
|
|
160
|
+
}
|
|
161
|
+
|
|
162
|
+
return {
|
|
163
|
+
transform: [{ scale: scale.value }],
|
|
164
|
+
}
|
|
165
|
+
})
|
|
166
|
+
|
|
167
|
+
const stageStaticStyle = useMemo(
|
|
168
|
+
() => ({
|
|
169
|
+
height: shortSide,
|
|
170
|
+
width: longSide,
|
|
171
|
+
}),
|
|
172
|
+
[longSide, shortSide]
|
|
173
|
+
)
|
|
174
|
+
|
|
175
|
+
return (
|
|
176
|
+
<View
|
|
177
|
+
style={[styles.root, { backgroundColor: MOVIIE_SKIN_CUSTOM_FULLSCREEN_STAGE_BACKGROUND_HEX }]}
|
|
178
|
+
>
|
|
179
|
+
<View style={styles.centerSheet}>
|
|
180
|
+
<ReanimatedView style={[styles.rotatingStage, stageStaticStyle, animatedStyle]}>
|
|
181
|
+
{props.children}
|
|
182
|
+
</ReanimatedView>
|
|
183
|
+
</View>
|
|
184
|
+
</View>
|
|
185
|
+
)
|
|
186
|
+
})
|
|
187
|
+
|
|
188
|
+
export const MoviieSkinCustomFullscreenModal = forwardRef<
|
|
189
|
+
MoviieSkinCustomFullscreenModalHandle,
|
|
190
|
+
MoviieSkinCustomFullscreenModalProps
|
|
191
|
+
>(function MoviieSkinCustomFullscreenModal(props, ref) {
|
|
192
|
+
return (
|
|
193
|
+
<Modal
|
|
194
|
+
animationType="none"
|
|
195
|
+
hardwareAccelerated={Platform.OS === 'android'}
|
|
196
|
+
onRequestClose={() => {
|
|
197
|
+
if (ref != null && typeof ref !== 'function') {
|
|
198
|
+
ref.current?.animateExit()
|
|
199
|
+
}
|
|
200
|
+
}}
|
|
201
|
+
presentationStyle="fullScreen"
|
|
202
|
+
statusBarTranslucent={Platform.OS === 'android'}
|
|
203
|
+
supportedOrientations={[
|
|
204
|
+
'portrait',
|
|
205
|
+
'portrait-upside-down',
|
|
206
|
+
'landscape',
|
|
207
|
+
'landscape-left',
|
|
208
|
+
'landscape-right',
|
|
209
|
+
]}
|
|
210
|
+
visible={props.visible}
|
|
211
|
+
>
|
|
212
|
+
<SafeAreaProvider>
|
|
213
|
+
<MoviieSkinCustomFullscreenModalInner ref={ref} {...props} />
|
|
214
|
+
</SafeAreaProvider>
|
|
215
|
+
</Modal>
|
|
216
|
+
)
|
|
217
|
+
})
|
|
218
|
+
|
|
219
|
+
const styles = StyleSheet.create({
|
|
220
|
+
root: {
|
|
221
|
+
flex: 1,
|
|
222
|
+
},
|
|
223
|
+
centerSheet: {
|
|
224
|
+
alignItems: 'center',
|
|
225
|
+
flex: 1,
|
|
226
|
+
justifyContent: 'center',
|
|
227
|
+
overflow: 'visible',
|
|
228
|
+
},
|
|
229
|
+
rotatingStage: {
|
|
230
|
+
position: 'relative',
|
|
231
|
+
},
|
|
232
|
+
})
|
|
@@ -0,0 +1,134 @@
|
|
|
1
|
+
import type { ReactNode } from 'react'
|
|
2
|
+
|
|
3
|
+
import type { VideoPlayer, VideoViewProps } from 'expo-video'
|
|
4
|
+
|
|
5
|
+
import type { MoviiePlaybackData } from '@moviie/player-sdk'
|
|
6
|
+
|
|
7
|
+
import type { MoviieCastAdapter } from '../lib/moviie-cast-adapter'
|
|
8
|
+
import type {
|
|
9
|
+
MoviieTelemetryOnError,
|
|
10
|
+
MoviieTelemetryOnEvent,
|
|
11
|
+
} from '../lib/moviie-telemetry-callbacks'
|
|
12
|
+
|
|
13
|
+
/**
|
|
14
|
+
* Subconjunto do elemento iframe usado na integração web (embed watch).
|
|
15
|
+
* Evita acoplar o pacote à lib DOM completa no tsconfig.
|
|
16
|
+
*/
|
|
17
|
+
export type MoviieWatchEmbedIframeHandle = {
|
|
18
|
+
readonly contentWindow: {
|
|
19
|
+
postMessage(message: unknown, targetOrigin: string): void
|
|
20
|
+
} | null
|
|
21
|
+
}
|
|
22
|
+
|
|
23
|
+
export type MoviieWatchEmbedIframeRefCallback = (
|
|
24
|
+
iframe: MoviieWatchEmbedIframeHandle | null
|
|
25
|
+
) => void
|
|
26
|
+
|
|
27
|
+
export type MoviieVideoProps = Omit<VideoViewProps, 'player'> & {
|
|
28
|
+
/**
|
|
29
|
+
* Instância `VideoPlayer` do expo-video (iOS / Android).
|
|
30
|
+
* Na web, `useMoviiePlayer` devolve `null` e `MoviieVideo` usa iframe do embed.
|
|
31
|
+
*/
|
|
32
|
+
player: VideoPlayer | null
|
|
33
|
+
nativeControls?: boolean
|
|
34
|
+
/**
|
|
35
|
+
* When `true`, uses the platform `VideoView` chrome. When `false` or omitted, uses the Moviie custom chrome (default).
|
|
36
|
+
*/
|
|
37
|
+
native?: boolean
|
|
38
|
+
playback?: MoviiePlaybackData | null
|
|
39
|
+
/**
|
|
40
|
+
* Optional override: when set, replaces embed `showPip` for PiP capability (with {@link pictureInPictureAutoStart}).
|
|
41
|
+
* Raw `VideoView` props (`allowsPictureInPicture`, …) still win when passed explicitly.
|
|
42
|
+
*/
|
|
43
|
+
pictureInPicture?: boolean
|
|
44
|
+
/**
|
|
45
|
+
* Optional override for auto-start PiP. Embed has no field for this; omit for `false` unless set here or on the hook.
|
|
46
|
+
*/
|
|
47
|
+
pictureInPictureAutoStart?: boolean
|
|
48
|
+
/**
|
|
49
|
+
* Ignorado quando `native` é omitido ou `false`: o chrome Moviie não usa temporizador para ocultar.
|
|
50
|
+
*/
|
|
51
|
+
controlsAutoHideMs?: number
|
|
52
|
+
controlsVisibleByDefault?: boolean
|
|
53
|
+
children?: ReactNode
|
|
54
|
+
/**
|
|
55
|
+
* Web: callback com referência ao iframe após montagem, para `Moviie.getPlayer(iframe)` (`embed.js`).
|
|
56
|
+
*/
|
|
57
|
+
onEmbedIframeRef?: MoviieWatchEmbedIframeRefCallback
|
|
58
|
+
/**
|
|
59
|
+
* Web: injeta `<script src="{watchOrigin}/embed.js">` uma vez. Ignorado em nativo. Default `true`.
|
|
60
|
+
*/
|
|
61
|
+
loadEmbedScript?: boolean
|
|
62
|
+
/**
|
|
63
|
+
* Erro vindo de `useMoviiePlayer`/`useMoviiePlayback`. Quando preenchido (e sem `playback`),
|
|
64
|
+
* a shell built-in mostra feedback de erro com CTA mapeado por código.
|
|
65
|
+
*/
|
|
66
|
+
error?: Error | null
|
|
67
|
+
/**
|
|
68
|
+
* Indica que o fetch de playback está em curso. Quando `true` (e sem `playback`), a shell
|
|
69
|
+
* built-in mostra estado de carregamento.
|
|
70
|
+
*/
|
|
71
|
+
isLoading?: boolean
|
|
72
|
+
/**
|
|
73
|
+
* Aspect ratio do container reservado pelo player enquanto não há dimensões intrínsecas do
|
|
74
|
+
* vídeo. Default `16/9`. Após `playback` chegar, o container passa a usar `videoWidthPx/videoHeightPx`.
|
|
75
|
+
*/
|
|
76
|
+
aspectRatio?: number
|
|
77
|
+
/**
|
|
78
|
+
* Callback opcional para erros transientes (network/rate_limit). Override do retry built-in.
|
|
79
|
+
* Tem precedência sobre {@link retry}.
|
|
80
|
+
*/
|
|
81
|
+
onRetry?: () => void
|
|
82
|
+
/**
|
|
83
|
+
* Função de retry built-in fornecida por `useMoviiePlayer().retry`. Aceita o spread do hook
|
|
84
|
+
* sem boilerplate. Quando `onRetry` é fornecido, este é ignorado.
|
|
85
|
+
*/
|
|
86
|
+
retry?: () => void
|
|
87
|
+
/**
|
|
88
|
+
* Adapter opcional para cast (Chromecast). Crie via factory do subpath
|
|
89
|
+
* `@moviie/player-expo/cast` (`createGoogleCastAdapter()`) e passe aqui.
|
|
90
|
+
*
|
|
91
|
+
* Quando omitido, o botão de cast não aparece. Se o embed pede cast
|
|
92
|
+
* (`playback.controls.chromecast === true`) e o adapter não foi fornecido,
|
|
93
|
+
* dispara um `console.warn` único com instruções.
|
|
94
|
+
*/
|
|
95
|
+
castAdapter?: MoviieCastAdapter | null
|
|
96
|
+
/**
|
|
97
|
+
* Override explícito do flag `playback.controls.chromecast`. Quando definido,
|
|
98
|
+
* vence o painel:
|
|
99
|
+
* - `true`: força exibir botão (se adapter estiver disponível);
|
|
100
|
+
* - `false`: força esconder e silencia warning;
|
|
101
|
+
* - omitido: usa o flag do painel.
|
|
102
|
+
*/
|
|
103
|
+
cast?: boolean
|
|
104
|
+
/**
|
|
105
|
+
* Callback opt-in invocado quando um erro relevante ocorre — para integração
|
|
106
|
+
* com Sentry/PostHog/Datadog do consumer.
|
|
107
|
+
*
|
|
108
|
+
* Não substitui nem expande a telemetria interna enviada ao backend Moviie.
|
|
109
|
+
* Exceções lançadas dentro do callback são engolidas e logged via warn.
|
|
110
|
+
*
|
|
111
|
+
* @example
|
|
112
|
+
* ```tsx
|
|
113
|
+
* <MoviieVideo
|
|
114
|
+
* {...moviie}
|
|
115
|
+
* onTelemetryError={(error, ctx) => Sentry.captureException(error, { tags: ctx })}
|
|
116
|
+
* />
|
|
117
|
+
* ```
|
|
118
|
+
*/
|
|
119
|
+
onTelemetryError?: MoviieTelemetryOnError
|
|
120
|
+
/**
|
|
121
|
+
* Callback opt-in invocado em eventos de ciclo de vida do player
|
|
122
|
+
* (play, pause, seek, fullscreen, cast). Útil para correlacionar UX com erros
|
|
123
|
+
* em ferramentas de observability do consumer.
|
|
124
|
+
*
|
|
125
|
+
* @example
|
|
126
|
+
* ```tsx
|
|
127
|
+
* <MoviieVideo
|
|
128
|
+
* {...moviie}
|
|
129
|
+
* onTelemetryEvent={(e) => posthog.capture(`player.${e.name}`, e)}
|
|
130
|
+
* />
|
|
131
|
+
* ```
|
|
132
|
+
*/
|
|
133
|
+
onTelemetryEvent?: MoviieTelemetryOnEvent
|
|
134
|
+
}
|