step 5-6: compose experience

This commit is contained in:
talksik
2026-04-29 13:29:02 -07:00
parent ddfcf1ee12
commit a974fa50b0
46 changed files with 3305 additions and 75 deletions
+5
View File
@@ -123,6 +123,11 @@ export const MediaPropertiesSchema = z.object({
size_bytes: z.number(),
transcript: TranscriptSchema.optional(),
source: z.enum(["camera", "screen"]).optional(),
// Set by the particle processor worker once an iOS-playable MP4/m4a variant
// has been produced from a non-iOS-playable original (e.g. WebM from desktop).
// When present, clients should prefer these over object_id/mime_type for playback.
transcoded_object_id: z.string().optional(),
transcoded_mime_type: z.string().optional(),
});
export type MediaProperties = z.infer<typeof MediaPropertiesSchema>;
@@ -33,12 +33,18 @@ export const MediaParticleView = forwardRef<MediaParticleHandle, MediaParticleVi
onEnded,
onProgress,
}, ref) {
const { data: url, error } = useDownloadUrl(particle.properties.object_id);
// Prefer the worker-produced iOS-playable variant when present so desktop
// and mobile read the same canonical asset. Falls back to the original.
const activeObjectId =
particle.properties.transcoded_object_id ?? particle.properties.object_id;
const activeMime =
particle.properties.transcoded_mime_type ?? particle.properties.mime_type;
const { data: url, error } = useDownloadUrl(activeObjectId);
const { attachments } = useParticleAttachments(streamPath, particle.id);
const videoRef = useRef<HTMLVideoElement>(null);
const audioRef = useRef<HTMLAudioElement>(null);
const isAudio = particle.properties.mime_type?.startsWith("audio/");
const isAudio = activeMime?.startsWith("audio/");
useImperativeHandle(ref, () => ({
seek(deltaSec: number) {