{"record":{"id":"5d559d280e458b85","repo":"tonhowtf/omniget","slug":"trecho-passa-do-fim-do-v-deo","errorCode":null,"errorMessage":"trecho {}: passa do fim do vídeo","messagePattern":"trecho (.+?): passa do fim do vídeo","errorType":"validation","errorClass":null,"httpStatus":null,"severity":"error","filePath":"src-tauri/omniget-core/src/core/tools/sponsorblock.rs","lineNumber":243,"sourceCode":"        if !ACTION_TYPES.contains(&s.action_type.as_str()) {\n            return Err(anyhow!(\n                \"trecho {}: tipo de ação desconhecido ({})\",\n                n,\n                s.action_type\n            ));\n        }\n        if !s.start.is_finite() || !s.end.is_finite() || s.start < 0.0 || s.end < 0.0 {\n            return Err(anyhow!(\"trecho {}: tempo inválido\", n));\n        }\n        let pontual = s.action_type == \"poi\" || s.action_type == \"full\";\n        if !pontual && s.end <= s.start {\n            return Err(anyhow!(\"trecho {}: o fim tem de vir depois do começo\", n));\n        }\n        if s.action_type == \"chapter\" && s.description.trim().is_empty() {\n            return Err(anyhow!(\"trecho {}: capítulo precisa de um título\", n));\n        }\n        if duration > 0.0 && s.end > duration + 1.0 {\n            return Err(anyhow!(\"trecho {}: passa do fim do vídeo\", n));\n        }\n    }\n    // Sobreposição só importa entre trechos que pulam pedaço.\n    let mut cortes: Vec<&NewSegment> = segments\n        .iter()\n        .filter(|s| s.action_type == \"skip\" || s.action_type == \"mute\")\n        .collect();\n    cortes.sort_by(|a, b| a.start.total_cmp(&b.start));\n    for par in cortes.windows(2) {\n        if par[1].start < par[0].end {\n            return Err(anyhow!(\"dois trechos se sobrepõem em {:.1}s\", par[1].start));\n        }\n    }\n    Ok(())\n}\n\n/// O corpo exato do `POST /api/skipSegments`.\npub fn build_payload(","sourceCodeStart":225,"sourceCodeEnd":261,"githubUrl":"https://github.com/tonhowtf/omniget/blob/8600b91f4246848bac346874daa9e61c1fc5677a/src-tauri/omniget-core/src/core/tools/sponsorblock.rs#L225-L261","documentation":"validate_segments rejects any segment whose end time exceeds the video duration by more than a 1.0s tolerance. SponsorBlock would otherwise store a segment pointing past the end of the video, which cannot be skipped. The 1s slack absorbs small rounding differences in user-reported durations.","triggerScenarios":"Calling build_payload/submit with opts.video_duration set to the real length while a segment's end is larger than duration + 1.0 (or duration known and segment measured from a different cut of the video).","commonSituations":"Duration guessed or rounded down (e.g. trimmed/premium versions); segments authored against a longer preview; stale duration from a previous video reused for the current one; duration 0 passed because it was unknown — note that duration <= 0 skips this check entirely.","solutions":["Fetch the accurate video duration and pass it as the duration parameter to build_payload.","Clamp segment end to min(end, duration) before submitting.","Re-author the segment against the correct video if the timestamps came from a different cut.","Ensure you are not passing duration = 0.0 (which silently disables this check) when the real duration is known."],"exampleFix":"// before\nbuild_payload(&id, &user, 300.0, &segments) // segment end = 320.0\n// after\nlet dur = fetch_duration(&id).await?; // 330.0\nbuild_payload(&id, &user, dur, &segments)","handlingStrategy":"validation","validationCode":"fn within_duration(s: &NewSegment, duration: f64) -> bool {\n    duration <= 0.0 || s.end <= duration + 1.0\n}","typeGuard":"fn fits_video(s: &NewSegment, duration: f64) -> bool {\n    duration > 0.0 && s.end <= duration + 1.0\n}","tryCatchPattern":"match build_payload(&id, &user, dur, &segs) {\n    Err(e) if e.to_string().contains(\"passa do fim do vídeo\") => clamp_segments(&mut segs, dur),\n    other => other?,\n}","preventionTips":["Always pass the real video duration to build_payload (never 0.0, which disables the check).","Clamp segment end times to the duration before submitting.","Re-fetch duration when switching videos instead of reusing a cached value."],"tags":["validation","sponsorblock","rust","range-check"],"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-15T23:17:13.987Z"}