{"record":{"id":"347673764d3c8790","repo":"tonhowtf/omniget","slug":"a-janela-de-corte-ficou-vazia-o-v-deo-tem-1-s","errorCode":null,"errorMessage":"a janela de corte ficou vazia — o vídeo tem {:.1}s","messagePattern":"a janela de corte ficou vazia — o vídeo tem (.+?)s","errorType":"exception","errorClass":null,"httpStatus":null,"severity":"error","filePath":"src-tauri/src/platforms/bilibili/danmaku/burn.rs","lineNumber":102,"sourceCode":"\n    report(\n        progress,\n        ID,\n        \"progress\",\n        0,\n        Some(3),\n        Some(\"lendo o vídeo\".into()),\n    );\n    let probe = omniget_core::core::ffmpeg::probe(&video).await?;\n    let has_audio = probe.streams.iter().any(|s| s.codec_type == \"audio\");\n    let start = opts.start.max(0.0);\n    let window = if opts.duration > 0.0 {\n        opts.duration\n    } else {\n        (probe.duration_seconds - start).max(0.0)\n    };\n    if window <= 0.0 {\n        return Err(anyhow!(\n            \"a janela de corte ficou vazia — o vídeo tem {:.1}s\",\n            probe.duration_seconds\n        ));\n    }\n\n    let text = read_text(&sub)?;\n    let (body, dialogues) = if is_ass(&sub) {\n        shift_ass(&text, start, window)\n    } else {\n        shift_other(&text, start, window)?\n    };\n    if dialogues == 0 {\n        return Err(anyhow!(\n            \"nenhum comentário cai entre {:.1}s e {:.1}s\",\n            start,\n            start + window\n        ));\n    }","sourceCodeStart":84,"sourceCodeEnd":120,"githubUrl":"https://github.com/tonhowtf/omniget/blob/8600b91f4246848bac346874daa9e61c1fc5677a/src-tauri/src/platforms/bilibili/danmaku/burn.rs#L84-L120","documentation":"run() computes the cut window as opts.duration if positive, otherwise remaining video time (probe.duration_seconds - start). If the resulting window is <= 0 the clip would be empty, so it throws 'a janela de corte ficou vazia — o vídeo tem <D>s'. This protects FFmpeg from a nonsensical zero/negative duration.","triggerScenarios":"opts.start (or the resolved seek point) is >= the probed video duration; a video shorter than the requested trim offset; a bogus probe report with duration_seconds near 0 combined with a non-zero start.","commonSituations":"User asks for a clip from a timestamp beyond the end of a short video; corrupted or partially downloaded file whose ffprobe duration is wrong; duration passed as 0 while start >= real duration.","solutions":["Clamp start to be strictly less than the probed duration before calling run","Verify the video file is complete (its ffprobe duration should match the expected length)","If passing opts.duration explicitly, ensure start + duration stays within the video"],"exampleFix":"// before\nlet opts = BurnOptions { start: 120.0, ..base_opts }; // video is 90s\n// after\nlet dur = ffprobe_duration(&video)?;\nanyhow::ensure!(opts.start < dur, \"início {:.1}s além da duração {:.1}s\", opts.start, dur);\nlet opts = BurnOptions { start: opts.start.min(dur - 1.0), ..base_opts };","handlingStrategy":"validation","validationCode":"fn window_ok(start: f64, duration: f64, probe: f64) -> bool {\n    let w = if duration > 0.0 { duration } else { probe - start };\n    w > 0.0 && start < probe\n}","typeGuard":null,"tryCatchPattern":"match burn::run(&opts, &progress).await {\n    Err(e) if e.to_string().contains(\"janela de corte ficou vazia\") => clamp_start_and_retry(&opts),\n    Err(e) => propagate(e)?,\n    Ok(res) => use_result(res),\n}","preventionTips":["Probe the real duration with ffprobe before choosing start/duration","Clamp start to duration - epsilon for short videos","Reject user timestamps beyond the video length in the UI"],"tags":["validation","duration","ffmpeg","range"],"backgroundTag":"value-out-of-range","analyzedSha":"8600b91f4246848bac346874daa9e61c1fc5677a","analyzedAt":"2026-09-12T14:29:19.317Z","contentChangedAt":"2026-09-12T14:29:19.317Z","schemaVersion":2},"datasetVersion":"2026-09-23T08:17:48.524Z"}