{"record":{"id":"7639d8e3d53e37c5","repo":"tonhowtf/omniget","slug":"mod","errorCode":null,"errorMessage":"{}","messagePattern":"\\{\\}","errorType":"exception","errorClass":"anyhow::Error","httpStatus":null,"severity":"error","filePath":"src-tauri/omniget-core/src/core/tools/tiktok/mod.rs","lineNumber":757,"sourceCode":"    let bin = ytdlp_binary().await?;\n    let mut cmd = crate::core::ytdlp::ytdlp_command(&bin);\n    cmd.args(args)\n        .stdin(std::process::Stdio::null())\n        .stdout(std::process::Stdio::piped())\n        .stderr(std::process::Stdio::piped());\n    let out = cmd\n        .output()\n        .await\n        .map_err(|e| anyhow!(\"não foi possível iniciar o yt-dlp: {}\", e))?;\n    let text = String::from_utf8_lossy(&out.stdout);\n    let line = text\n        .lines()\n        .map(|l| l.trim())\n        .find(|l| l.starts_with('{'))\n        .unwrap_or(\"\");\n    if line.is_empty() {\n        let tail = String::from_utf8_lossy(&out.stderr).to_string();\n        return Err(anyhow!(\"{}\", short_reason(&tail)));\n    }\n    serde_json::from_str(line).map_err(|e| anyhow!(\"o JSON do yt-dlp não foi lido: {}\", e))\n}\n\n// ───────────────────────── formatação ─────────────────────────\n\npub fn fmt_utc(ts: i64) -> String {\n    chrono::DateTime::from_timestamp(ts, 0)\n        .map(|d| d.format(\"%Y-%m-%d %H:%M UTC\").to_string())\n        .unwrap_or_default()\n}\n\n/// Escapa um campo de CSV do jeito que a planilha espera.\npub fn csv_escape(s: &str) -> String {\n    if s.contains([',', '\"', '\\n', '\\r']) {\n        format!(\"\\\"{}\\\"\", s.replace('\"', \"\\\"\\\"\"))\n    } else {\n        s.to_string()","sourceCodeStart":739,"sourceCodeEnd":775,"githubUrl":"https://github.com/tonhowtf/omniget/blob/8600b91f4246848bac346874daa9e61c1fc5677a/src-tauri/omniget-core/src/core/tools/tiktok/mod.rs#L739-L775","documentation":"After running yt-dlp in JSON mode, `ytdlp_json` scans stdout for a line starting with '{'. If none is found, it treats the run as failed and raises an error whose message is the shortened stderr reason (via `short_reason`). This surfaces yt-dlp's own failure output (e.g. video unavailable, login required) as the error.","triggerScenarios":"yt-dlp exits with no JSON on stdout — unsupported/removed video, network failure, age/login restriction, bad URL, or a yt-dlp version whose output format changed; stdout is empty while stderr carries the reason.","commonSituations":"Private or region-blocked TikTok video; yt-dlp outdated for a changed TikTok page structure; bot-check/captcha page returned instead of media; invalid or malformed URL passed in.","solutions":["Read the `{}` message: it is the shortened stderr from yt-dlp; fix the cause it names (URL, login, network).","Update yt-dlp to the latest version (`yt-dlp -U` or pip install -U yt-dlp) — TikTok extractors change often.","Verify the video URL opens in a browser and is public.","If cookies/session are required, pass the session cookie file to yt-dlp."],"exampleFix":"// before\n$ yt-dlp -j https://www.tiktok.com/@u/video/123\nERROR: video unavailable\n// after\n$ yt-dlp -U   # update extractors, then retry with a valid public URL","handlingStrategy":"try-catch","validationCode":"// Validate the URL shape before invoking yt-dlp\nif !url.contains(\"tiktok.com\") { return Err(anyhow!(\"URL não parece ser do TikTok\")); }","typeGuard":null,"tryCatchPattern":"match ytdlp_json(&args).await {\n    Ok(v) => Ok(v),\n    Err(e) if e.to_string().contains(\"unavailable\") => warn_user_and_skip(),\n    Err(e) => { update_ytdlp().await; Err(e) },\n}","preventionTips":["Keep yt-dlp updated — TikTok extractors break frequently.","Check that the target video is public and reachable before downloading.","Surface the shortened yt-dlp stderr reason to the end user for actionable feedback."],"tags":["external-tool","ytdlp","stderr"],"backgroundTag":"upstream-api-error","analyzedSha":"8600b91f4246848bac346874daa9e61c1fc5677a","analyzedAt":"2026-09-12T14:29:19.317Z","contentChangedAt":"2026-09-12T14:29:19.317Z","schemaVersion":2},"datasetVersion":"2026-09-16T04:17:20.429Z"}