From 81a7a8c2157a400f709c15ee5aa9f6ddb3efc489 Mon Sep 17 00:00:00 2001 From: muhammadali-imran Date: Wed, 14 Oct 2026 08:00:55 +0500 Subject: [PATCH 1/2] feat: async video upload and fetch. toast system. --- frontend/README.md | 17 ++- frontend/docs/architecture.md | 28 ++++- frontend/src/components/BasePlayer.jsx | 8 +- frontend/src/components/UploadToaster.jsx | 42 +++++++ frontend/src/context/LibraryProvider.jsx | 27 ++-- frontend/src/context/UploadQueueContext.js | 9 ++ frontend/src/context/UploadQueueProvider.jsx | 122 +++++++++++++++++++ frontend/src/hooks/useCachedVideo.js | 37 ++++++ frontend/src/main.jsx | 13 +- frontend/src/pages/Player.jsx | 30 ++++- frontend/src/pages/RecordingEditor.jsx | 34 +++--- frontend/src/services/api.js | 82 +++++++++++++ frontend/src/styles/player.css | 16 +++ frontend/src/utils/videoCache.js | 86 +++++++++++++ frontend/test/UploadQueueProvider.test.jsx | 85 +++++++++++++ 15 files changed, 585 insertions(+), 51 deletions(-) create mode 100644 frontend/src/components/UploadToaster.jsx create mode 100644 frontend/src/context/UploadQueueContext.js create mode 100644 frontend/src/context/UploadQueueProvider.jsx create mode 100644 frontend/src/hooks/useCachedVideo.js create mode 100644 frontend/src/utils/videoCache.js create mode 100644 frontend/test/UploadQueueProvider.test.jsx diff --git a/frontend/README.md b/frontend/README.md index 774027c..c3d2eba 100644 --- a/frontend/README.md +++ b/frontend/README.md @@ -68,8 +68,19 @@ Contributor recordings stay in memory as a `Blob` while the user moves between the player and editor; closing the tab discards an unsubmitted take. On submission, the frontend uploads the recording and trim/mirror metadata to the backend. The backend validates and stores the recording and enforces the -submission cooldown. Admins prepare reference and demo videos in the browser -before upload: they can remove audio and trim the clip, with processing performed +submission cooldown. After submission, the recording uploads in the background: +one upload can run while one waits, and the contributor can continue browsing. +Failed uploads remain in the queue until retried or discarded. The queue is +memory-only, so the browser warns before a pending upload is lost; switching +accounts clears that account's queue. + +Reference videos are downloaded into an in-memory cache for five minutes after +download completes, and the next video in the category is prefetched. Individual +videos larger than 100 MB bypass the cache, and cached entries are limited to +250 MB total; videos still playing are not revoked mid-playback. + +Admins prepare reference and demo videos in the browser before upload: they can +remove audio and trim the clip, with processing performed locally by ffmpeg.wasm when changes are applied. The browser also reports the video's displayed dimensions and duration; the backend stores these values for responsive playback and display. No video-processing worker is required on the @@ -90,7 +101,7 @@ src/ main.jsx Browser entry point and provider setup components/ Shared layouts, controls, navigation, and route guards config/ UI configuration - context/ Auth, library, recording, notification, and theme state + context/ Auth, library, recording, upload queue, notification, and theme state hooks/ Reusable hooks, including camera/MediaRecorder handling pages/ Public and contributor pages pages/admin/ Admin workspace pages diff --git a/frontend/docs/architecture.md b/frontend/docs/architecture.md index 72a1e7f..6e9b34a 100644 --- a/frontend/docs/architecture.md +++ b/frontend/docs/architecture.md @@ -54,6 +54,7 @@ management library. | `AuthProvider` | Loads the current session from the API and exposes login, signup, email verification, logout, and connection updates. | | `LibraryProvider` | Loads categories, visible videos, and the current user's submissions; provides derived category, contribution, and cooldown state plus admin mutations. | | `RecordingProvider` | Holds unsubmitted recording blobs and trim/mirror edits in memory, keyed by video ID. These drafts are discarded on submit, replacement, user change, or tab close. | +| `UploadQueueProvider` | Holds up to two submitted recordings in an in-memory queue (one uploading and one waiting). Failed uploads keep their slot for retry or discard; the queue is cleared when the signed-in user changes. | | `NotificationProvider` | Stores per-user notification items and read state in browser `localStorage`; notifications do not sync across devices. | | `ThemeProvider` | Follows the OS theme until a user selects one, then persists the selection locally. | @@ -88,9 +89,24 @@ interface hint; the backend independently enforces the cooldown. `useRecorder` captures camera and microphone media through browser media APIs. The `RecordingProvider` keeps the current take available while a contributor moves between `/watch` and `/watch/edit`. The editor applies trim and mirror -settings as submission metadata, then uploads the recording blob and metadata -through the API service. The backend stores the uploaded recording and metadata; -it does not physically trim or transcode contributor recordings. +settings as submission metadata, then hands the recording blob and metadata to +`UploadQueueProvider`. Uploads run one at a time through an XMLHttpRequest so +the UI can report byte progress and abort on account changes. The editor returns +to the player immediately; a page-level toaster reports waiting, active, failed, +and completed uploads. Failed uploads retain their queue slot until retried or +discarded. Queue data is memory-only, and a `beforeunload` prompt warns if the +tab is closed or reloaded while work remains. The backend stores contributor +recordings and metadata; it does not physically trim or transcode them. + +### Reference-video cache + +`useCachedVideo` loads reference videos into an in-memory Blob cache and falls +back to the normal media URL if the download fails or exceeds the per-video +100 MB cap. Entries expire five minutes after download and the cache evicts +oldest entries to stay within a 250 MB total budget. A player holds its entry +while it is in use so an expired or evicted object URL is not revoked during +playback. The player also prefetches the next video in its category after the +current video's load attempt finishes. ### Admin video preparation and responsive playback @@ -164,10 +180,10 @@ frontend/ seo/ # SEO metadata and helpers styles/ # Theme tokens and feature styles utils/ # Shared browser and media utilities - test/ - RecorderPanel.test.jsx # Recorder workflow component tests docs/ - ARCHITECTURE.md # This guide + architecture.md # This guide + test/ + RecorderPanel.test.jsx # Recorder workflow component tests scripts/ generateSeoAssets.js # Sitemap, robots, and prerender route generation runReactSnap.js # Static route prerendering diff --git a/frontend/src/components/BasePlayer.jsx b/frontend/src/components/BasePlayer.jsx index e2c6de1..47a0272 100644 --- a/frontend/src/components/BasePlayer.jsx +++ b/frontend/src/components/BasePlayer.jsx @@ -6,7 +6,7 @@ import ResponsiveVideo from './ResponsiveVideo' const SPEEDS = [0.5, 0.75, 1] /** Base video player: play/pause, replay, seek, speed and fullscreen. The parent owns the