Skip to content

feat: add blurred background to empty spaces for vertical videos #539

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Draft
wants to merge 3 commits into
base: main
Choose a base branch
from

Conversation

junhyoung-ryu
Copy link
Collaborator

@junhyoung-ryu junhyoung-ryu commented May 8, 2025

PR Type

Enhancement


Description

  • Add blurred background to vertical video previews

  • Sync background video with main video

  • Hoist upload helper and remove duplicate

  • Memoize storedPrompt localStorage access


Changes walkthrough 📝

Relevant files
Enhancement
page.tsx
Extract upload helper and remove duplicate                             

apps/app/app/admin/tools/clip-approval-queue/page.tsx

  • Hoist uploadWithPresignedUrl function to top level
  • Remove duplicate uploadWithPresignedUrl implementation
  • Preserve upload error handling
  • +12/-14 
    ClipSummaryContent.tsx
    Blurred background video and sync logic                                   

    apps/app/components/daydream/Clipping/ClipSummaryContent.tsx

  • Add blurred background video for vertical mode
  • Sync background video playback with main video
  • Memoize storedPrompt with useMemo
  • Adjust container classNames for overflow handling
  • +51/-8   

    Need help?
  • Type /help how to ... in the comments thread for any questions about PR-Agent usage.
  • Check out the documentation for more information.
  • Copy link

    vercel bot commented May 8, 2025

    The latest updates on your projects. Learn more about Vercel for Git ↗︎

    Name Status Preview Comments Updated (UTC)
    pipelines-app ✅ Ready (Inspect) Visit Preview 💬 Add feedback May 8, 2025 5:54am

    Copy link

    github-actions bot commented May 8, 2025

    PR Reviewer Guide 🔍

    Here are some key observations to aid the review process:

    ⏱️ Estimated effort to review: 3 🔵🔵🔵⚪⚪
    🧪 No relevant tests
    🔒 No security concerns identified
    ⚡ Recommended focus areas for review

    Unused Variable

    The storedPrompt value is computed via useMemo but never used thereafter, leading to dead code and potential lint errors. Remove or integrate this variable.

    const storedPrompt = useMemo(() => {
      return typeof window !== "undefined"
        ? localStorage.getItem("daydream_pending_clip_prompt")
        : null;
    }, []);
    SSR Hydration

    Reading from localStorage inside useMemo runs on both server and client, risking hydration mismatches (server yields null, client yields actual value). Consider moving this logic into a useEffect or lazy-init it only on the client.

    const storedPrompt = useMemo(() => {
      return typeof window !== "undefined"
        ? localStorage.getItem("daydream_pending_clip_prompt")
        : null;
    }, []);

    Copy link

    github-actions bot commented May 8, 2025

    PR Code Suggestions ✨

    Explore these optional code suggestions:

    CategorySuggestion                                                                                                                                    Impact
    General
    Continuous time sync

    Add a continuous timeupdate listener and pre-sync on play to keep the blurred
    background in tighter lockstep with the main video. This prevents drift during
    playback.

    apps/app/components/daydream/Clipping/ClipSummaryContent.tsx [153-179]

     useEffect(() => {
       if (mainVideoRef.current && bgVideoRef.current) {
         const mainVideo = mainVideoRef.current;
         const bgVideo = bgVideoRef.current;
     
    -    const syncPlay = () =>
    -      bgVideo.play().catch(e => console.error("Bg video play error:", e));
    -    const syncPause = () => bgVideo.pause();
         const syncTime = () => {
           if (Math.abs(mainVideo.currentTime - bgVideo.currentTime) > 0.1) {
             bgVideo.currentTime = mainVideo.currentTime;
           }
         };
    +    const syncPlay = () => {
    +      syncTime();
    +      return bgVideo.play().catch(e => console.error("Bg video play error:", e));
    +    };
    +    const syncPause = () => bgVideo.pause();
     
         mainVideo.addEventListener("play", syncPlay);
         mainVideo.addEventListener("pause", syncPause);
         mainVideo.addEventListener("seeked", syncTime);
         mainVideo.addEventListener("loadedmetadata", syncTime);
    +    mainVideo.addEventListener("timeupdate", syncTime);
     
         return () => {
           mainVideo.removeEventListener("play", syncPlay);
           mainVideo.removeEventListener("pause", syncPause);
           mainVideo.removeEventListener("seeked", syncTime);
           mainVideo.removeEventListener("loadedmetadata", syncTime);
    +      mainVideo.removeEventListener("timeupdate", syncTime);
         };
       }
     }, [clipData.clipUrl, clipData.recordingMode]);
    Suggestion importance[1-10]: 7

    __

    Why: Adding a timeupdate listener and syncing on play ensures the background video stays tightly in sync with mainVideoRef, reducing drift during playback.

    Medium
    Avoid SSR mismatch on prompt

    Move the localStorage read into a client-only effect and use state to avoid
    SSR/client render mismatches. This ensures the prompt is loaded only after mount.

    apps/app/components/daydream/Clipping/ClipSummaryContent.tsx [52-56]

    -const storedPrompt = useMemo(() => {
    -  return typeof window !== "undefined"
    -    ? localStorage.getItem("daydream_pending_clip_prompt")
    -    : null;
    +const [storedPrompt, setStoredPrompt] = useState<string | null>(null);
    +useEffect(() => {
    +  if (typeof window !== "undefined") {
    +    setStoredPrompt(localStorage.getItem("daydream_pending_clip_prompt"));
    +  }
     }, []);
    Suggestion importance[1-10]: 7

    __

    Why: Moving the localStorage access into a useEffect with useState prevents SSR/client hydration mismatches and ensures the prompt loads after mount.

    Medium
    Add network error handling

    Wrap the fetch call in a try/catch to surface network-level errors distinctly from
    HTTP errors. This ensures any thrown exceptions on failed connections are caught and
    rethrown with a clear message.

    apps/app/app/admin/tools/clip-approval-queue/page.tsx [11-21]

     const uploadWithPresignedUrl = async (url: string, blob: Blob) => {
    -  const response = await fetch(url, {
    -    method: "PUT",
    -    body: blob,
    -    headers: { "Content-Type": blob.type },
    -  });
    -  if (!response.ok) {
    -    throw new Error(`Upload failed: ${response.status} ${response.statusText}`);
    +  try {
    +    const response = await fetch(url, {
    +      method: "PUT",
    +      body: blob,
    +      headers: { "Content-Type": blob.type },
    +    });
    +    if (!response.ok) {
    +      throw new Error(`Upload failed: ${response.status} ${response.statusText}`);
    +    }
    +    return response;
    +  } catch (err: any) {
    +    throw new Error(`Network error during upload: ${err.message}`);
       }
    -  return response;
     };
    Suggestion importance[1-10]: 6

    __

    Why: Wrapping fetch in a try/catch surfaces network errors distinctly from HTTP errors, improving error visibility without altering core logic.

    Low

    Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
    Projects
    None yet
    Development

    Successfully merging this pull request may close these issues.

    1 participant