From 127d0288b476f9978287290f830ebc2289357d4c Mon Sep 17 00:00:00 2001 From: vineyardbovines Date: Thu, 25 Jun 2026 18:10:11 -0400 Subject: [PATCH] Instrument video probe with raw-value metrics for bitrate/HDR validation --- src/analytics/metrics/types.ts | 17 +++++++++++++++++ src/lib/media/video/compress.ts | 14 ++++++++++++-- src/view/com/composer/Composer.tsx | 6 ++++-- src/view/com/composer/state/video.ts | 23 +++++++++++++++++++++++ 4 files changed, 56 insertions(+), 4 deletions(-) diff --git a/src/analytics/metrics/types.ts b/src/analytics/metrics/types.ts index a9d7f7bb17..3e9a9559d6 100644 --- a/src/analytics/metrics/types.ts +++ b/src/analytics/metrics/types.ts @@ -252,6 +252,23 @@ export type Events = { 'composer:image:edit': { platform: Platform['OS'] } + 'composer:video:probe': { + mimeType: string + codec: string + width: number + height: number + duration: number + bitrate: number + fileSize: number + hasAudio: boolean + frameRate: number + rotation: number + isHDR: boolean + wouldCompress: boolean + } + 'composer:video:probeFailed': { + safeMessage: string + } 'composerPrompt:press': {} 'composerPrompt:camera:press': {} 'composerPrompt:gallery:press': {} diff --git a/src/lib/media/video/compress.ts b/src/lib/media/video/compress.ts index 826419e789..5771d352ab 100644 --- a/src/lib/media/video/compress.ts +++ b/src/lib/media/video/compress.ts @@ -6,7 +6,11 @@ import { VIDEO_MAX_SIZE, } from '#/lib/constants' import {logger} from '#/logger' -import {compress, probe} from '../../../../modules/expo-bluesky-video-compress' +import { + compress, + probe, + type VideoMetadata, +} from '../../../../modules/expo-bluesky-video-compress' import { COMPRESSION_MAX_DIMENSION, COMPRESSION_PASSTHROUGH_BITRATE, @@ -19,6 +23,8 @@ export async function compressVideo( opts?: { signal?: AbortSignal onProgress?: (progress: number) => void + onProbe?: (metadata: VideoMetadata, wouldCompress: boolean) => void + onProbeFailed?: (error: unknown) => void }, ): Promise { if (file.mimeType === 'image/gif') { @@ -36,6 +42,7 @@ export async function compressVideo( logger.debug('probe failed, falling through to passthrough', { safeMessage: e, }) + opts?.onProbeFailed?.(e) return { uri: file.uri, size: file.fileSize ?? -1, @@ -43,7 +50,10 @@ export async function compressVideo( } } - if (!shouldCompress(metadata, isAcceptableFormat)) { + const willCompress = shouldCompress(metadata, isAcceptableFormat) + opts?.onProbe?.(metadata, willCompress) + + if (!willCompress) { return { uri: file.uri, size: metadata.fileSize, diff --git a/src/view/com/composer/Composer.tsx b/src/view/com/composer/Composer.tsx index 78a78a22a8..0025a69d51 100644 --- a/src/view/com/composer/Composer.tsx +++ b/src/view/com/composer/Composer.tsx @@ -412,9 +412,10 @@ export const ComposePost = ({ currentDid, abortController.signal, i18n, + ax.metric, ) }, - [i18n, agent, currentDid, composerDispatch], + [i18n, agent, currentDid, composerDispatch, ax.metric], ) const onInitVideo = useNonReactiveCallback(() => { @@ -559,6 +560,7 @@ export const ComposePost = ({ currentDid, abortController.signal, i18n, + ax.metric, ) } catch (e) { logger.error('Failed to restore video from draft', { @@ -567,7 +569,7 @@ export const ComposePost = ({ }) } }, - [i18n, agent, currentDid, composerDispatch], + [i18n, agent, currentDid, composerDispatch, ax.metric], ) const handleSelectDraft = useCallback( diff --git a/src/view/com/composer/state/video.ts b/src/view/com/composer/state/video.ts index 54bfcd67af..76593d50de 100644 --- a/src/view/com/composer/state/video.ts +++ b/src/view/com/composer/state/video.ts @@ -16,6 +16,7 @@ import {uploadVideo} from '#/lib/media/video/upload' import {createVideoAgent} from '#/lib/media/video/util' import {isNetworkError} from '#/lib/strings/errors' import {logger} from '#/logger' +import {type AnalyticsContextType} from '#/analytics' type CaptionsTrack = {lang: string; file: File} @@ -265,6 +266,7 @@ export async function processVideo( did: string, signal: AbortSignal, i18n: I18n, + metric: AnalyticsContextType['metric'], ) { let video: CompressedVideo | undefined try { @@ -273,6 +275,27 @@ export async function processVideo( dispatch({type: 'update_progress', progress: trunc2dp(num), signal}) }, signal, + onProbe: (metadata, wouldCompress) => { + metric('composer:video:probe', { + mimeType: metadata.mimeType, + codec: metadata.codec, + width: metadata.width, + height: metadata.height, + duration: metadata.duration, + bitrate: metadata.bitrate, + fileSize: metadata.fileSize, + hasAudio: metadata.hasAudio, + frameRate: metadata.frameRate, + rotation: metadata.rotation, + isHDR: metadata.isHDR, + wouldCompress, + }) + }, + onProbeFailed: e => { + metric('composer:video:probeFailed', { + safeMessage: e instanceof Error ? e.message : String(e), + }) + }, }) } catch (e) { const message = getCompressErrorMessage(e, i18n)