moonlantern1 commited on
Commit
ab3c93e
·
verified ·
1 Parent(s): 342c541

Filter submitted session clips by current take

Browse files
src/app/api/public/reviews/submit-session/route.ts CHANGED
@@ -11,6 +11,24 @@ const sanitizeText = (value: FormDataEntryValue | null, max = 200) => {
11
  return value.trim().slice(0, max);
12
  };
13
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
14
  export async function POST(req: NextRequest) {
15
  try {
16
  const form = await req.formData();
@@ -20,12 +38,16 @@ export async function POST(req: NextRequest) {
20
  const deviceKey = sanitizeText(form.get('deviceKey'), 200) || null;
21
  const tableId = sanitizeText(form.get('tableId'), 80) || null;
22
  const sessionId = sanitizeText(form.get('sessionId'), 100);
 
23
 
24
  if (!consentAccepted) {
25
  return NextResponse.json({ error: 'Consent is required' }, { status: 400 });
26
  }
27
 
28
- const clips = await listSessionClips(sessionId);
 
 
 
29
  const videoClips = clips
30
  .filter((clip) => clip.mediaType === 'video')
31
  .map((clip) => ({ filePath: clip.filePath, ext: clip.ext }));
 
11
  return value.trim().slice(0, max);
12
  };
13
 
14
+ function collectExpectedClips(form: FormData) {
15
+ const count = Number(sanitizeText(form.get('clipCount'), 10));
16
+ const total = Number.isFinite(count) ? Math.max(0, Math.min(20, count)) : 0;
17
+ const expected = new Map<string, number>();
18
+
19
+ for (let i = 0; i < total; i++) {
20
+ const step = Number(sanitizeText(form.get(`clipStep${i}`), 10));
21
+ const takeId = Number(sanitizeText(form.get(`clipTakeId${i}`), 20));
22
+ const mediaType = sanitizeText(form.get(`clipMediaType${i}`), 12);
23
+ if (!Number.isInteger(step) || step < 1 || step > 20) continue;
24
+ if (!Number.isSafeInteger(takeId) || takeId < 0) continue;
25
+ if (mediaType !== 'video' && mediaType !== 'audio') continue;
26
+ expected.set(`${step}:${mediaType}`, takeId);
27
+ }
28
+
29
+ return expected;
30
+ }
31
+
32
  export async function POST(req: NextRequest) {
33
  try {
34
  const form = await req.formData();
 
38
  const deviceKey = sanitizeText(form.get('deviceKey'), 200) || null;
39
  const tableId = sanitizeText(form.get('tableId'), 80) || null;
40
  const sessionId = sanitizeText(form.get('sessionId'), 100);
41
+ const expectedClips = collectExpectedClips(form);
42
 
43
  if (!consentAccepted) {
44
  return NextResponse.json({ error: 'Consent is required' }, { status: 400 });
45
  }
46
 
47
+ const clips = (await listSessionClips(sessionId)).filter((clip) => {
48
+ if (expectedClips.size === 0) return true;
49
+ return expectedClips.get(`${clip.step}:${clip.mediaType}`) === clip.takeId;
50
+ });
51
  const videoClips = clips
52
  .filter((clip) => clip.mediaType === 'video')
53
  .map((clip) => ({ filePath: clip.filePath, ext: clip.ext }));
src/app/preview/page.tsx CHANGED
@@ -122,6 +122,11 @@ export default function PreviewPage() {
122
  deviceKey: ensureDeviceKey(),
123
  tableId: store.tableId,
124
  sessionId: store.sessionId,
 
 
 
 
 
125
  });
126
 
127
  setPhase({ kind: 'polling', result });
 
122
  deviceKey: ensureDeviceKey(),
123
  tableId: store.tableId,
124
  sessionId: store.sessionId,
125
+ clips: clipsToUpload.map((clip) => ({
126
+ step: clip.step,
127
+ takeId: clip.takeId,
128
+ mediaType: clip.mediaType,
129
+ })),
130
  });
131
 
132
  setPhase({ kind: 'polling', result });
src/lib/humeoApi.ts CHANGED
@@ -85,6 +85,11 @@ export type SubmitSessionInput = Omit<
85
  'durationSeconds' | 'video' | 'videoFileName'
86
  > & {
87
  sessionId: string;
 
 
 
 
 
88
  };
89
 
90
  export async function submit(input: SubmitInput): Promise<PublicSubmitResult> {
@@ -171,6 +176,14 @@ export async function submitSession(input: SubmitSessionInput): Promise<PublicSu
171
  form.append('deviceKey', input.deviceKey);
172
  form.append('sessionId', input.sessionId);
173
  if (input.tableId) form.append('tableId', input.tableId);
 
 
 
 
 
 
 
 
174
 
175
  const res = await fetch(endpoint('/api/public/reviews/submit-session'), {
176
  method: 'POST',
 
85
  'durationSeconds' | 'video' | 'videoFileName'
86
  > & {
87
  sessionId: string;
88
+ clips?: Array<{
89
+ step: number;
90
+ takeId: number;
91
+ mediaType: 'video' | 'audio';
92
+ }>;
93
  };
94
 
95
  export async function submit(input: SubmitInput): Promise<PublicSubmitResult> {
 
176
  form.append('deviceKey', input.deviceKey);
177
  form.append('sessionId', input.sessionId);
178
  if (input.tableId) form.append('tableId', input.tableId);
179
+ if (input.clips) {
180
+ form.append('clipCount', String(input.clips.length));
181
+ input.clips.forEach((clip, index) => {
182
+ form.append(`clipStep${index}`, String(clip.step));
183
+ form.append(`clipTakeId${index}`, String(clip.takeId));
184
+ form.append(`clipMediaType${index}`, clip.mediaType);
185
+ });
186
+ }
187
 
188
  const res = await fetch(endpoint('/api/public/reviews/submit-session'), {
189
  method: 'POST',