fix(clip-video): correct false 'Clipped' state on network failure + error UI

get_object() returns false on network failure; the .then() handler was
running with result=false and accessing result.hosted_file_id (evaluates
to undefined, valid JS key, no throw) so all success state was set even
though the request failed.

- Guard result in .then(): if !result.hosted_file_id → set status='error'
- Add 'Failed — Retry?' button state in error branch
- Raise client-side AbortController timeout 300s → 1800s (30 min)
- Add comment explaining root cause (get_object returns false, not throw)

Root cause of the connection drop is proxy_send_timeout or NAT hairpin
timeout (both default 60s) — not a frontend issue; tracked separately.

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
This commit is contained in:
Scott Idem
2026-03-26 12:16:07 -04:00
parent b63f8eed0c
commit f950c22a59

View File

@@ -147,7 +147,7 @@ function handle_clip_video(event: Event) {
api_cfg: $ae_api,
endpoint: endpoint,
params: params,
timeout: 300000, // 5 minutes
timeout: 1800000, // 30 minutes — clip_video runs ffmpeg which can take 5-15 min for long recordings
// return_blob: true,
// filename: event.target.new_filename.value,
// auto_download: false,
@@ -157,12 +157,24 @@ function handle_clip_video(event: Event) {
.then(function (result) {
console.log(result);
// WHY: get_object() returns false/null on network failure (CORS drop,
// timeout, Gunicorn worker killed). Without this guard, result.hosted_file_id
// is undefined — JS uses it as an object key without throwing, so all the
// success state below would run and show "Clipped" on a failed request.
if (!result || !result.hosted_file_id) {
console.log('clip_video: request failed or returned no result');
$ae_sess.files.processed_file_kv[hosted_file_id].submit_status =
'error';
$ae_loc.files.processed_file_kv[hosted_file_id].submit_status =
'error';
submit_status = 'error';
clip_complete = false;
return false;
}
video_clip_file_kv[result.hosted_file_id] = {};
video_clip_file_kv[result.hosted_file_id] = result;
// $ae_loc.files.video_clip_file_kv[result.hosted_file_id] = {};
// $ae_loc.files.video_clip_file_kv[result.hosted_file_id] = result;
$ae_sess.files.processed_file_kv[hosted_file_id].submit_status =
'clipped';
$ae_sess.files.processed_file_kv[hosted_file_id].clip_complete =
@@ -176,13 +188,6 @@ function handle_clip_video(event: Event) {
submit_status = 'clipped';
clip_complete = true;
// let file_blob = new Blob([result.data]);
// // console.log(file_blob);
// let file_obj_url = window.URL.createObjectURL(file_blob); // The img src
// // const url = window.URL.createObjectURL(new Blob([result.data]));
// download_clip_src = file_obj_url;
// // download_filename = file_obj_url;
return true;
});
}
@@ -363,21 +368,25 @@ function handle_clip_video(event: Event) {
<button
type="submit"
class="btn btn-lg btn-primary preset-tonal-primary border-primary-500 hover:preset-filled-primary-500 border transition-colors"
class="btn btn-lg btn-primary border transition-colors"
class:preset-tonal-primary={submit_status !== 'error'}
class:border-primary-500={submit_status !== 'error'}
class:hover:preset-filled-primary-500={submit_status !== 'error'}
class:preset-tonal-error={submit_status === 'error'}
class:border-error-500={submit_status === 'error'}
disabled={submit_status == 'clipping'}>
<!-- {#await ae_promises[hosted_file_id]} -->
{#if $ae_loc.files.processed_file_kv[hosted_file_id] && $ae_loc.files.processed_file_kv[hosted_file_id].submit_status == 'clipping'}
<LoaderCircle size="1em" class="m-1 animate-spin" />
<span class="highlight">Clipping...</span>
{:else if $ae_loc.files.processed_file_kv[hosted_file_id] && $ae_loc.files.processed_file_kv[hosted_file_id].submit_status == 'error'}
<span class="fas fa-exclamation-triangle m-1"></span>
Failed Retry?
{:else if $ae_loc.files.processed_file_kv[hosted_file_id] && $ae_loc.files.processed_file_kv[hosted_file_id].submit_status == 'clipped'}
<Check size="1em" class="m-1" />
Clipped
{:else}
<!-- {#if ae_promises[hosted_file_id]} -->
{#if $ae_loc.files.processed_file_kv[hosted_file_id] && $ae_loc.files.processed_file_kv[hosted_file_id].submit_status == 'clipped'}
<Check size="1em" class="m-1" />
Clipped
{:else}
<Scissors size="1em" class="m-1" />
Clip Video
{/if}
<Scissors size="1em" class="m-1" />
Clip Video
{/if}
<!-- <span class="fas fa-cut m-1"></span>
Clip Video -->