auto detect video time and update agenda item with said time, and all…#449
Draft
karenunify wants to merge 7 commits into
Draft
auto detect video time and update agenda item with said time, and all…#449karenunify wants to merge 7 commits into
karenunify wants to merge 7 commits into
Conversation
…ow for youtube and vimeo videos
Contributor
There was a problem hiding this comment.
Pull request overview
This PR adds automatic video-duration detection (Cloudinary uploads + Vimeo oEmbed + YouTube player metadata) and uses that duration to auto-update agenda slot times and hostless waiting room/buffer timings, improving scheduling accuracy when video media is added.
Changes:
- Extend
MediaHelperServiceto return upload duration for Cloudinary uploads and fetch Vimeo durations via oEmbed; improve YouTube URL parsing. - Wire duration callbacks into agenda item video editing and event waiting room media sections to auto-update time fields and show user feedback.
- Update time input behavior to reflect external duration changes (controllers update when
durationprop changes).
Reviewed changes
Copilot reviewed 10 out of 10 changed files in this pull request and generated 7 comments.
Show a summary per file
| File | Description |
|---|---|
| client/test/mocked_classes.mocks.dart | Updates mocks for new media helper return types and duration APIs. |
| client/lib/features/events/features/live_meeting/features/meeting_agenda/presentation/widgets/time_input_form.dart | Keeps text controllers in sync when duration changes. |
| client/lib/features/events/features/live_meeting/features/meeting_agenda/presentation/views/agenda_item_video.dart | Adds duration detection hooks (Cloudinary + YouTube) and URL preview routing (YouTube/Vimeo vs generic URL). |
| client/lib/features/events/features/live_meeting/features/meeting_agenda/presentation/views/agenda_item_video_contract.dart | Extends the view contract with a duration-detected notification. |
| client/lib/features/events/features/live_meeting/features/meeting_agenda/presentation/views/agenda_item_card.dart | Auto-updates agenda slot duration when video duration is detected and shows a toast. |
| client/lib/features/events/features/live_meeting/features/meeting_agenda/presentation/agenda_item_video_presenter.dart | Auto-detects YouTube/Vimeo types from pasted URLs and triggers Vimeo duration fetch. |
| client/lib/features/events/features/event_page/presentation/widgets/media_item_section.dart | Returns Cloudinary upload duration and forwards it to callers when the picked media is a video. |
| client/lib/features/events/features/event_page/presentation/waiting_room_widget_presenter.dart | Refactors waiting room time updates to accept Duration instead of minute/second strings. |
| client/lib/features/events/features/event_page/presentation/views/waiting_room_widget.dart | Uses TimeInputForm for durations and auto-updates buffer/intro timings when video duration is detected. |
| client/lib/core/data/services/media_helper_service.dart | Adds duration-carrying return types, improved YouTube ID regex, and Vimeo duration lookup via HTTP. |
💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.
Comment on lines
+70
to
+77
| if (_mediaHelperService.getYoutubeVideoId(trimmedUrl) != null) { | ||
| _model.agendaItemVideoData.type = AgendaItemVideoType.youtube; | ||
| } else { | ||
| final vimeoId = _mediaHelperService.getVimeoVideoId(trimmedUrl); | ||
| if (vimeoId != null) { | ||
| _model.agendaItemVideoData.type = AgendaItemVideoType.vimeo; | ||
| _fetchAndNotifyVimeoDuration(vimeoId); | ||
| } |
Comment on lines
+101
to
+110
| onVideoDurationDetected: (durationInSeconds) { | ||
| _presenter.updateWaitingBufferDuration( | ||
| Duration(seconds: durationInSeconds), | ||
| ); | ||
| showRegularToast( | ||
| context, | ||
| 'Buffer time updated to ${ prettyDuration(Duration(seconds: durationInSeconds)).replaceAll('minute', 'min').replaceAll('second', 'sec')} to match video length.', | ||
| toastType: ToastType.neutral, | ||
| ); | ||
| }, |
Comment on lines
+165
to
+172
| onVideoDurationDetected: (durationInSeconds) { | ||
| _presenter.updateDuration(Duration(seconds: durationInSeconds)); | ||
| showRegularToast( | ||
| context, | ||
| 'Intro Length updated to ${prettyDuration(Duration(seconds: durationInSeconds)).replaceAll('minute', 'min').replaceAll('second', 'sec')} to match video length.', | ||
| toastType: ToastType.neutral, | ||
| ); | ||
| }, |
Comment on lines
+308
to
+316
| onVideoDurationDetected: (durationInSeconds) { | ||
| final duration = Duration(seconds: durationInSeconds); | ||
| _presenter.updateTime(duration); | ||
| showRegularToast( | ||
| context, | ||
| 'Slot time updated to ${_presenter.getFormattedDuration(duration)} to match video length.', | ||
| toastType: ToastType.neutral, | ||
| ); | ||
| }, |
Co-authored-by: Copilot Autofix powered by AI <175728472+Copilot@users.noreply.github.com>
Comment on lines
+182
to
185
| TimeInputForm( | ||
| duration: introLengthDuration, | ||
| onUpdate: (d) => _presenter.updateDuration(d), | ||
| ), |
Comment on lines
+106
to
+116
| final info = await _pickMediaInfo( | ||
| uploadPreset: uploadPreset, | ||
| clientAllowedFormats: clientAllowedFormats, | ||
| cropping: cropping, | ||
| croppingAspectRatio: croppingAspectRatio, | ||
| ); | ||
| if (info == null) return null; | ||
| return PickedVideoResult( | ||
| url: info.url, | ||
| durationInSeconds: info.duration?.round(), | ||
| ); |
Comment on lines
64
to
+91
| void updateVideoUrl(String url) { | ||
| _model.agendaItemVideoData.url = url.trim(); | ||
| _view.updateView(); | ||
| final trimmedUrl = url.trim(); | ||
| _model.agendaItemVideoData.url = trimmedUrl; | ||
|
|
||
| // Auto-detect YouTube/Vimeo links so the saved type is correct even when | ||
| // the user pastes a link into the generic URL tab. | ||
| if (_mediaHelperService.getYoutubeVideoId(trimmedUrl) != null) { | ||
| _model.agendaItemVideoData.type = AgendaItemVideoType.youtube; | ||
| } else { | ||
| final vimeoId = _mediaHelperService.getVimeoVideoId(trimmedUrl); | ||
| if (vimeoId != null) { | ||
| _model.agendaItemVideoData.type = AgendaItemVideoType.vimeo; | ||
| _fetchAndNotifyVimeoDuration(vimeoId); | ||
| } else { | ||
| _model.agendaItemVideoData.type = AgendaItemVideoType.url; | ||
| } | ||
| } | ||
|
|
||
| _view.updateView(); | ||
| _helper.updateParent(_model); | ||
| } | ||
|
|
||
| void _fetchAndNotifyVimeoDuration(String vimeoId) async { | ||
| final duration = await _mediaHelperService.fetchVimeoDuration(vimeoId); | ||
| if (duration != null) { | ||
| _view.notifyVideoDurationDetected(duration); | ||
| } | ||
| } |
Co-authored-by: Copilot Autofix powered by AI <175728472+Copilot@users.noreply.github.com>
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
…ow for youtube and vimeo videos
What is in this PR?
This PR autodetects video length when uploaded to a template, event agenda, or as the waiting room/intro item of a hostless event.
Changes in the codebase
When a video URL is linked, or uploaded via Cloudinary, either to a template, event agenda, or as the waiting room/intro item of a hostless event, the video duration is retrieved from the video service metadata. That time in whole seconds is then automatically added to that template/agenda/waiting room item for hostless events.
In the case of the waiting room on hostless events, the time is now factored in to the breakout room timing, and users will not be sent off to the breakout rooms until after the auto detected video duration, of both the waiting and into videos, if applicable.
If the video duration data isn't readily available, users are prompted to remember to set the slot time to match the video length.
The previously implemented regex for YouTube video detection was somewhat incomplete, and should now be resolved.
Testing this PR
.
Additional information
AI tools used (if applicable):
Claude Code extension in VS code for best practices and debugging