Add delayed trailer playback preview to media cards#40
Conversation
|
The latest updates on your projects. Learn more about Vercel for GitHub.
|
📝 WalkthroughWalkthroughEnhanced the media card component with a Changes
Sequence Diagram(s)sequenceDiagram
participant User
participant Card as HorizontalCard/<br/>VerticalCard
participant Preview as TrailerPreview
participant Query as useQuery
participant API as getVideos API
participant YouTube as YouTube iframe
User->>Card: onMouseEnter
Card->>Card: Set hoverTimeoutRef (2s delay)
User->>Card: Wait 2 seconds
Card->>Preview: Activate preview (isPreviewActive=true)
Preview->>Query: Execute query for videos
Query->>API: getVideos({id, type})
API-->>Query: Return video list
Query->>Preview: Select first YouTube<br/>Trailer/Teaser item
Preview->>YouTube: Render iframe<br/>(looping, autoplaying, muted)
YouTube-->>Preview: Display overlay on card
User->>Card: onMouseLeave
Card->>Card: Clear hoverTimeoutRef
Card->>Preview: Deactivate preview<br/>(isPreviewActive=false)
Preview->>YouTube: Remove iframe
Estimated code review effort🎯 4 (Complex) | ⏱️ ~45 minutes 🚥 Pre-merge checks | ✅ 3✅ Passed checks (3 passed)
✏️ Tip: You can configure your own custom pre-merge checks in the settings. ✨ Finishing Touches📝 Generate docstrings
🧪 Generate unit tests (beta)
Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out. Comment |
There was a problem hiding this comment.
Actionable comments posted: 2
🤖 Prompt for all review comments with AI agents
Verify each finding against the current code and only fix it if needed.
Inline comments:
In `@src/components/media-card.tsx`:
- Around line 164-178: The hover enter/leave timers are currently attached to
the <Link> element (handlers using hoverTimeoutRef, setIsPreviewActive) which
causes the preview to collapse when moving to sibling elements like the
watchlist button; move the onMouseEnter/onMouseLeave logic (the hoverTimeoutRef
clear/set and setIsPreviewActive calls) from the Link to the outer card
container element (or to the TrailerPreview surface component) so the hover
region covers the entire visual card (and also update the same pattern at the
other occurrence around lines with the duplicate handlers). Ensure
hoverTimeoutRef is still used the same way and cleared on leave, and that the
watchlist button remains outside the Link but inside the new hover container so
preview persists while interacting with it.
- Around line 118-119: The iframe in the MediaCard component currently loads
from www.youtube.com when isPreviewActive becomes true, which permits immediate
cookies/tracking; update the src template used where trailerKey is injected (the
src prop in the iframe inside MediaCard) to use the privacy-enhanced domain
youtube-nocookie.com instead of www.youtube.com while preserving all query
params (autoplay, mute, controls, playsinline, loop, playlist, rel,
modestbranding) so the hover preview behavior and trailerKey usage remain
identical but without preloading YouTube cookies.
🪄 Autofix (Beta)
Fix all unresolved CodeRabbit comments on this PR:
- Push a commit to this branch (recommended)
- Create a new PR with the fixes
ℹ️ Review info
⚙️ Run configuration
Configuration used: Organization UI
Review profile: ASSERTIVE
Plan: Pro
Run ID: 6de0face-8693-4345-af37-0ddf3dbe6531
📒 Files selected for processing (1)
src/components/media-card.tsx
| src={`https://www.youtube.com/embed/${trailerKey}?autoplay=1&mute=1&controls=0&playsinline=1&loop=1&playlist=${trailerKey}&rel=0&modestbranding=1`} | ||
| allow="autoplay; encrypted-media; picture-in-picture" |
There was a problem hiding this comment.
🧩 Analysis chain
🏁 Script executed:
find . -name "media-card.tsx" -type fRepository: Swastikdan/Pebbly
Length of output: 92
🏁 Script executed:
cat -n ./src/components/media-card.tsx | head -150Repository: Swastikdan/Pebbly
Length of output: 5068
🏁 Script executed:
sed -n '130,200p' ./src/components/media-card.tsx | cat -nRepository: Swastikdan/Pebbly
Length of output: 2910
🏁 Script executed:
sed -n '100,127p' ./src/components/media-card.tsx | cat -nRepository: Swastikdan/Pebbly
Length of output: 1080
🏁 Script executed:
web_search
What is the privacy difference between youtube.com and youtube-nocookie.com embed URLsRepository: Swastikdan/Pebbly
Length of output: 154
🌐 Web query:
YouTube youtube-nocookie.com privacy embed differences
💡 Result:
-
youtube.com/embed/...(standard embed): Loads the regular YouTube embedded player and is more likely to allow YouTube-related storage/cookies and personalization signals to be used as soon as the embed loads (even before the user presses play). [3] -
youtube-nocookie.com/embed/...(“Privacy-Enhanced Mode”):- It’s the same embed player, but served from a different domain that YouTube documents as “Privacy Enhanced Mode.” [1]
- Personalization impact: Views from this embedded player won’t be used to personalize the viewer’s YouTube browsing experience, and ads shown in this embedded player are non-personalized. Those views also won’t be used to personalize ads shown to the viewer outside your site/app. [1]
- Cookie behavior: Commonly described as not setting cookies until the user starts playback / interacts (i.e., no cookie on initial page load). [2][3]
- How to use it: Replace
https://www.youtube.comwithhttps://www.youtube-nocookie.comin the iframesrc(and allowlistyoutube-nocookie.comif you use a firewall/allowlist). [1]
Sources:
[1] YouTube Help — “Embed videos & playlists” (Privacy Enhanced Mode section) (support.google.com)
[2] Ignite.video — explanation of NoCookie / privacy-enhanced embeds (ignite.video)
[3] Stack Overflow — summary that nocookie waits until playback before dropping cookies (stackoverflow.com)
Citations:
- 1: https://support.google.com/youtube/answer/171780?hl=en
- 2: https://ignite.video/en/articles/basics/youtube-no-cookie?utm_source=openai
- 3: https://stackoverflow.com/questions/49750257/how-to-embed-a-youtube-iframe-with-cookie-consent-control?utm_source=openai
Use the privacy-enhanced YouTube embed for hover previews.
The iframe is rendered when isPreviewActive becomes true (after a 2-second hover delay), which creates a www.youtube.com connection before any click. This allows YouTube to set cookies and track the user immediately on load. Using www.youtube-nocookie.com defers cookie/personalization tracking until the user actually interacts with the player.
Suggested change
- src={`https://www.youtube.com/embed/${trailerKey}?autoplay=1&mute=1&controls=0&playsinline=1&loop=1&playlist=${trailerKey}&rel=0&modestbranding=1`}
+ src={`https://www.youtube-nocookie.com/embed/${trailerKey}?autoplay=1&mute=1&controls=0&playsinline=1&loop=1&playlist=${trailerKey}&rel=0&modestbranding=1`}
+ referrerPolicy="strict-origin-when-cross-origin"📝 Committable suggestion
‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.
| src={`https://www.youtube.com/embed/${trailerKey}?autoplay=1&mute=1&controls=0&playsinline=1&loop=1&playlist=${trailerKey}&rel=0&modestbranding=1`} | |
| allow="autoplay; encrypted-media; picture-in-picture" | |
| src={`https://www.youtube-nocookie.com/embed/${trailerKey}?autoplay=1&mute=1&controls=0&playsinline=1&loop=1&playlist=${trailerKey}&rel=0&modestbranding=1`} | |
| referrerPolicy="strict-origin-when-cross-origin" | |
| allow="autoplay; encrypted-media; picture-in-picture" |
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.
In `@src/components/media-card.tsx` around lines 118 - 119, The iframe in the
MediaCard component currently loads from www.youtube.com when isPreviewActive
becomes true, which permits immediate cookies/tracking; update the src template
used where trailerKey is injected (the src prop in the iframe inside MediaCard)
to use the privacy-enhanced domain youtube-nocookie.com instead of
www.youtube.com while preserving all query params (autoplay, mute, controls,
playsinline, loop, playlist, rel, modestbranding) so the hover preview behavior
and trailerKey usage remain identical but without preloading YouTube cookies.
| onMouseEnter={() => { | ||
| if (hoverTimeoutRef.current) { | ||
| clearTimeout(hoverTimeoutRef.current); | ||
| } | ||
| hoverTimeoutRef.current = setTimeout(() => { | ||
| setIsPreviewActive(true); | ||
| }, 2000); | ||
| }} | ||
| onMouseLeave={() => { | ||
| if (hoverTimeoutRef.current) { | ||
| clearTimeout(hoverTimeoutRef.current); | ||
| hoverTimeoutRef.current = null; | ||
| } | ||
| setIsPreviewActive(false); | ||
| }} |
There was a problem hiding this comment.
Attach the hover timer to the card shell instead of the link.
The preview is scoped to <Link>, but the watchlist button still sits outside it. Moving from the artwork onto that button fires onMouseLeave and tears the preview down even though the pointer is still over the same visual card. Put the enter/leave handlers on the outer card container or the TrailerPreview surface so the hover region matches what users see.
Also applies to: 271-285
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.
In `@src/components/media-card.tsx` around lines 164 - 178, The hover enter/leave
timers are currently attached to the <Link> element (handlers using
hoverTimeoutRef, setIsPreviewActive) which causes the preview to collapse when
moving to sibling elements like the watchlist button; move the
onMouseEnter/onMouseLeave logic (the hoverTimeoutRef clear/set and
setIsPreviewActive calls) from the Link to the outer card container element (or
to the TrailerPreview surface component) so the hover region covers the entire
visual card (and also update the same pattern at the other occurrence around
lines with the duplicate handlers). Ensure hoverTimeoutRef is still used the
same way and cleared on leave, and that the watchlist button remains outside the
Link but inside the new hover container so preview persists while interacting
with it.
Motivation
Description
TrailerPreviewwrapper component insidesrc/components/media-card.tsxthat fetches TMDB videos viagetVideosand selects a YouTubeTrailerorTeaserto use as the preview iframe.isPreviewActivestate, with proper timeout cleanup on unmount and on mouse leave.Imagefor an autoplaying, muted, looping YouTubeiframewhile preview is active and restores the image when hover ends.MediaCardvariants; person cards remain unchanged.Testing
pnpm -s exec biome check src/components/media-card.tsxand the check completed successfully.pnpm -s exec tsc --noEmitand TypeScript checks completed successfully for the modified file.Codex Task
Summary by CodeRabbit