@thewhateverapp/tile-sdk 0.12.0 → 0.12.2

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.
@@ -59,15 +59,19 @@ export interface CuePoint {
59
59
  data?: unknown;
60
60
  }
61
61
  export interface VideoPlayerProps {
62
- /** HLS playlist URL (m3u8) */
63
- src: string;
64
- /** Auto-start playback (default: true) */
62
+ /**
63
+ * Video source URL (HLS playlist or direct video URL).
64
+ * If not provided, VideoPlayer will auto-fetch from the tile's metadata
65
+ * using the tileId from NEXT_PUBLIC_TILE_ID environment variable.
66
+ */
67
+ src?: string;
68
+ /** Auto-start playback (default: true, or from tile metadata) */
65
69
  autoplay?: boolean;
66
70
  /** Loop video (default: false, but true in preview mode) */
67
71
  loop?: boolean;
68
72
  /** Start muted (default: true for autoplay compliance) */
69
73
  muted?: boolean;
70
- /** Poster image URL */
74
+ /** Poster image URL (auto-fetched from tile metadata if not provided) */
71
75
  poster?: string;
72
76
  /** Show native controls (default: false) */
73
77
  controls?: boolean;
@@ -93,8 +97,9 @@ export interface VideoPlayerProps {
93
97
  * - Time-based cue points for triggering overlays
94
98
  * - Visibility-aware playback (plays when visible, pauses when hidden)
95
99
  * - Auto-loops in preview mode for testing
100
+ * - Auto-fetches video URL from tile metadata when src is not provided
96
101
  */
97
- export declare function VideoPlayer({ src, autoplay, loop: loopProp, muted, poster, controls, children, className, videoClassName, cuePoints, onCuePoint, onTimeUpdate, }: VideoPlayerProps): React.JSX.Element;
102
+ export declare function VideoPlayer({ src: srcProp, autoplay: autoplayProp, loop: loopProp, muted: mutedProp, poster: posterProp, controls, children, className, videoClassName, cuePoints, onCuePoint, onTimeUpdate, }: VideoPlayerProps): React.JSX.Element;
98
103
  /**
99
104
  * Hook to access video state and controls from within VideoPlayer children.
100
105
  */
@@ -1 +1 @@
1
- {"version":3,"file":"VideoPlayer.d.ts","sourceRoot":"","sources":["../../../src/react/overlay/VideoPlayer.tsx"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"VideoPlayer.d.ts","sourceRoot":"","sources":["../../../src/react/overlay/VideoPlayer.tsx"],"names":[],"mappings":"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"}
@@ -1,6 +1,42 @@
1
1
  'use client';
2
2
  import React, { createContext, useContext, useEffect, useRef, useState, useCallback, } from 'react';
3
3
  import { getTileBridge } from '../../bridge/TileBridge';
4
+ // Cache for video metadata to avoid repeated fetches
5
+ const videoMetadataCache = new Map();
6
+ /**
7
+ * Get tileId from environment variable (set at build time)
8
+ */
9
+ function getTileId() {
10
+ if (typeof process !== 'undefined' && process.env?.NEXT_PUBLIC_TILE_ID) {
11
+ return process.env.NEXT_PUBLIC_TILE_ID;
12
+ }
13
+ return null;
14
+ }
15
+ /**
16
+ * Fetch video metadata for a tile from the platform API
17
+ */
18
+ async function fetchVideoMetadata(tileId) {
19
+ // Check cache first
20
+ if (videoMetadataCache.has(tileId)) {
21
+ return videoMetadataCache.get(tileId);
22
+ }
23
+ try {
24
+ // Use production API URL
25
+ const apiBase = 'https://api.thewhatever.app';
26
+ const response = await fetch(`${apiBase}/platform/tiles/${tileId}/video-metadata`);
27
+ if (!response.ok) {
28
+ console.error(`[VideoPlayer] Failed to fetch video metadata: ${response.status}`);
29
+ return null;
30
+ }
31
+ const metadata = await response.json();
32
+ videoMetadataCache.set(tileId, metadata);
33
+ return metadata;
34
+ }
35
+ catch (error) {
36
+ console.error('[VideoPlayer] Error fetching video metadata:', error);
37
+ return null;
38
+ }
39
+ }
4
40
  const VideoContext = createContext(null);
5
41
  // Detect if we're in preview mode (tile-preview sets this global)
6
42
  function isPreviewMode() {
@@ -17,14 +53,48 @@ function isPreviewMode() {
17
53
  * - Time-based cue points for triggering overlays
18
54
  * - Visibility-aware playback (plays when visible, pauses when hidden)
19
55
  * - Auto-loops in preview mode for testing
56
+ * - Auto-fetches video URL from tile metadata when src is not provided
20
57
  */
21
- export function VideoPlayer({ src, autoplay = true, loop: loopProp, muted = true, poster, controls = false, children, className = '', videoClassName = '', cuePoints = [], onCuePoint, onTimeUpdate, }) {
58
+ export function VideoPlayer({ src: srcProp, autoplay: autoplayProp, loop: loopProp, muted: mutedProp, poster: posterProp, controls = false, children, className = '', videoClassName = '', cuePoints = [], onCuePoint, onTimeUpdate, }) {
22
59
  const videoRef = useRef(null);
23
60
  const hlsRef = useRef(null);
24
61
  const triggeredCuePointsRef = useRef(new Set());
25
62
  const lastTimeRef = useRef(0);
63
+ // State for auto-fetched metadata
64
+ const [metadata, setMetadata] = useState(null);
65
+ const [metadataError, setMetadataError] = useState(null);
66
+ // Auto-fetch video metadata if no src provided
67
+ useEffect(() => {
68
+ if (srcProp) {
69
+ // src provided directly, no need to fetch
70
+ return;
71
+ }
72
+ const tileId = getTileId();
73
+ if (!tileId) {
74
+ setMetadataError('No video source: src prop not provided and NEXT_PUBLIC_TILE_ID not set');
75
+ return;
76
+ }
77
+ fetchVideoMetadata(tileId).then((data) => {
78
+ if (data) {
79
+ if (data.videoUrl) {
80
+ setMetadata(data);
81
+ }
82
+ else {
83
+ setMetadataError('No video URL found in tile metadata');
84
+ }
85
+ }
86
+ else {
87
+ setMetadataError('Failed to fetch video metadata');
88
+ }
89
+ });
90
+ }, [srcProp]);
91
+ // Resolve actual values from props or metadata
92
+ const src = srcProp || metadata?.videoUrl || null;
93
+ const autoplay = autoplayProp ?? metadata?.autoplay ?? true;
94
+ const muted = mutedProp ?? metadata?.muted ?? true;
95
+ const poster = posterProp || metadata?.thumbnail || undefined;
26
96
  // Auto-enable loop in preview mode unless explicitly set to false
27
- const loop = loopProp ?? isPreviewMode();
97
+ const loop = loopProp ?? metadata?.loop ?? isPreviewMode();
28
98
  const [state, setState] = useState({
29
99
  isPlaying: false,
30
100
  currentTime: 0,
@@ -141,8 +211,11 @@ export function VideoPlayer({ src, autoplay = true, loop: loopProp, muted = true
141
211
  const video = videoRef.current;
142
212
  if (!video)
143
213
  return;
144
- const handlePlay = () => setState(s => ({ ...s, isPlaying: true }));
214
+ const handlePlay = () => setState(s => ({ ...s, isPlaying: true, isLoading: false }));
145
215
  const handlePause = () => setState(s => ({ ...s, isPlaying: false }));
216
+ // Fallback for loading state - hide spinner when video can play
217
+ const handleCanPlay = () => setState(s => ({ ...s, isLoading: false }));
218
+ const handleLoadedData = () => setState(s => ({ ...s, isLoading: false }));
146
219
  const handleTimeUpdate = () => {
147
220
  const currentTime = video.currentTime;
148
221
  const duration = video.duration;
@@ -190,6 +263,8 @@ export function VideoPlayer({ src, autoplay = true, loop: loopProp, muted = true
190
263
  video.addEventListener('volumechange', handleVolumeChange);
191
264
  video.addEventListener('progress', handleProgress);
192
265
  video.addEventListener('error', handleError);
266
+ video.addEventListener('canplay', handleCanPlay);
267
+ video.addEventListener('loadeddata', handleLoadedData);
193
268
  return () => {
194
269
  video.removeEventListener('play', handlePlay);
195
270
  video.removeEventListener('pause', handlePause);
@@ -198,10 +273,13 @@ export function VideoPlayer({ src, autoplay = true, loop: loopProp, muted = true
198
273
  video.removeEventListener('volumechange', handleVolumeChange);
199
274
  video.removeEventListener('progress', handleProgress);
200
275
  video.removeEventListener('error', handleError);
276
+ video.removeEventListener('canplay', handleCanPlay);
277
+ video.removeEventListener('loadeddata', handleLoadedData);
201
278
  };
202
279
  }, [onTimeUpdate, onCuePoint, cuePoints]);
203
- // Visibility handling - play/pause based on tile visibility
280
+ // Visibility handling - play/pause AND mute/unmute based on tile visibility
204
281
  // Enables TikTok-style preloaded video tiles that only play when visible
282
+ // Audio is controlled here to ensure only the visible tile has sound
205
283
  useEffect(() => {
206
284
  const video = videoRef.current;
207
285
  if (!video || !autoplay)
@@ -211,17 +289,25 @@ export function VideoPlayer({ src, autoplay = true, loop: loopProp, muted = true
211
289
  // Handle visibility changes from parent (mobile app)
212
290
  const unsubscribe = bridge.onVisibilityChange((visibilityState) => {
213
291
  if (visibilityState.visible) {
214
- // Tile became visible - play the video
215
- video.play().catch(() => { });
292
+ // Tile became visible - unmute and play
293
+ // Unmute first so audio starts with the video
294
+ video.muted = false;
295
+ video.play().catch(() => {
296
+ // If play fails (e.g., autoplay policy), keep muted and retry
297
+ video.muted = true;
298
+ video.play().catch(() => { });
299
+ });
216
300
  }
217
301
  else {
218
- // Tile became hidden - pause the video
302
+ // Tile became hidden - mute first (immediate audio stop), then pause
303
+ video.muted = true;
219
304
  video.pause();
220
305
  }
221
306
  });
222
307
  // Check initial visibility state
223
308
  if (!bridge.isVisible()) {
224
- // If not visible on mount, pause any autoplay
309
+ // If not visible on mount, ensure muted and paused
310
+ video.muted = true;
225
311
  video.pause();
226
312
  }
227
313
  return () => {
@@ -230,7 +316,7 @@ export function VideoPlayer({ src, autoplay = true, loop: loopProp, muted = true
230
316
  }
231
317
  catch {
232
318
  // Bridge not available (e.g., in SSR or outside TileProvider)
233
- // Video will just use autoplay behavior
319
+ // Video will just use autoplay behavior (muted)
234
320
  }
235
321
  }, [autoplay]);
236
322
  const contextValue = {
@@ -240,11 +326,28 @@ export function VideoPlayer({ src, autoplay = true, loop: loopProp, muted = true
240
326
  };
241
327
  return (React.createElement(VideoContext.Provider, { value: contextValue },
242
328
  React.createElement("div", { className: `relative w-full h-full bg-black ${className}` },
243
- React.createElement("video", { ref: videoRef, className: `w-full h-full object-contain ${videoClassName}`, poster: poster, loop: loop, muted: muted, controls: controls, playsInline: true }),
329
+ React.createElement("video", { ref: videoRef, className: `w-full h-full object-contain ${videoClassName}`, poster: poster, loop: loop, muted: muted, controls: controls, playsInline: true,
330
+ // Hide iOS Safari's native poster play button
331
+ style: {
332
+ // @ts-expect-error - WebKit-specific property
333
+ WebkitMediaControlsStartPlaybackButton: 'none',
334
+ } }),
335
+ React.createElement("style", null, `
336
+ video::-webkit-media-controls-start-playback-button {
337
+ display: none !important;
338
+ -webkit-appearance: none;
339
+ }
340
+ video::-webkit-media-controls-panel {
341
+ display: none !important;
342
+ }
343
+ video::-webkit-media-controls {
344
+ display: none !important;
345
+ }
346
+ `),
244
347
  state.isLoading && (React.createElement("div", { className: "absolute inset-0 flex items-center justify-center" },
245
348
  React.createElement("div", { className: "w-10 h-10 border-3 border-white/30 border-t-white rounded-full animate-spin" }))),
246
- state.error && (React.createElement("div", { className: "absolute inset-0 flex items-center justify-center text-white/80" },
247
- React.createElement("p", null, state.error))),
349
+ (state.error || metadataError) && (React.createElement("div", { className: "absolute inset-0 flex items-center justify-center text-white/80" },
350
+ React.createElement("p", null, state.error || metadataError))),
248
351
  children)));
249
352
  }
250
353
  /**
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@thewhateverapp/tile-sdk",
3
- "version": "0.12.0",
3
+ "version": "0.12.2",
4
4
  "description": "SDK for building interactive tiles on The Whatever App platform",
5
5
  "main": "./dist/index.js",
6
6
  "types": "./dist/index.d.ts",