{"record":{"id":"0645945ca13b51c0","repo":"tonhowtf/omniget","slug":"no-video-url-available","errorCode":null,"errorMessage":"No video URL available","messagePattern":"No video URL available","errorType":"exception","errorClass":null,"httpStatus":null,"severity":"error","filePath":"src-tauri/omniget-core/src/platforms/tiktok.rs","lineNumber":540,"sourceCode":"                    opts.concurrent_fragments,\n                    false,\n                    &[],\n                    opts.audio_format.as_deref(),\n                )\n                .await;\n            }\n        }\n\n        let cookies = self.captured_cookies.lock().await.clone();\n        let mut headers = self.download_headers(&cookies);\n        crate::core::http_client::inject_ua_header(&mut headers, opts.user_agent.as_deref());\n\n        match info.media_type {\n            MediaType::Video => {\n                let quality = info\n                    .available_qualities\n                    .first()\n                    .ok_or_else(|| anyhow!(\"No video URL available\"))?;\n\n                if quality.format == \"tiktok_direct\" {\n                    let filename = format!(\"{}.mp4\", sanitize_filename::sanitize(&info.title));\n                    let output = opts.output_dir.join(&filename);\n\n                    let result = direct_downloader::download_direct_with_headers(\n                        &self.client,\n                        &quality.url,\n                        &output,\n                        progress.clone(),\n                        Some(headers),\n                        Some(&opts.cancel_token),\n                    )\n                    .await;\n\n                    match result {\n                        Ok(bytes) => {\n                            return Ok(DownloadResult {","sourceCodeStart":522,"sourceCodeEnd":558,"githubUrl":"https://github.com/tonhowtf/omniget/blob/8600b91f4246848bac346874daa9e61c1fc5677a/src-tauri/omniget-core/src/platforms/tiktok.rs#L522-L558","documentation":"For MediaType::Video the library picks the first entry of info.available_qualities as the download source. If that list is empty — the scrape returned video metadata but no playable stream URLs — there is nothing to download and this error is thrown.","triggerScenarios":"download() is called with a MediaInfo whose media_type is Video but available_qualities is empty (quality extraction yielded no tiktok_direct or yt-dlp-playable URLs).","commonSituations":"TikTok serving the metadata but withholding playAddr for logged-out requests; region-blocked streams filtered out during quality extraction; photo/slideshow posts misdetected as Video; expired play URLs after a stale MediaInfo was cached.","solutions":["Re-fetch a fresh MediaInfo via get_media_info — play URLs expire quickly.","Check whether the post is actually a video (photo posts have no video qualities).","Retry with authenticated cookies so TikTok includes playAddr in the response.","Ensure yt-dlp is installed so fallback quality extraction (yt-dlp-playable format) can populate the list."],"exampleFix":"// before: blind download\nlet info = tiktok.get_media_info(url).await?;\ntiktok.download(&info, &opts).await?;\n// after: pre-validate qualities\nlet info = tiktok.get_media_info(url).await?;\nif info.media_type == MediaType::Video && info.available_qualities.is_empty() {\n    let info = tiktok.get_media_info(url).await?; // re-fetch fresh URLs\n    anyhow::ensure!(!info.available_qualities.is_empty(), \"No video URL available\");\n}\ntiktok.download(&info, &opts).await?;","handlingStrategy":"validation","validationCode":"let info = tiktok.get_media_info(url).await?;\nanyhow::ensure!(\n    info.media_type != MediaType::Video || !info.available_qualities.is_empty(),\n    \"No video URL available\"\n);","typeGuard":"fn has_video_url(info: &MediaInfo) -> bool {\n    info.media_type != MediaType::Video || !info.available_qualities.is_empty()\n}","tryCatchPattern":"match tiktok.download(&info, &opts).await {\n    Err(e) if e.to_string() == \"No video URL available\" => {\n        let fresh = tiktok.get_media_info(url).await?; // re-fetch: URLs may have expired\n        tiktok.download(&fresh, &opts).await\n    }\n    other => other,\n}","preventionTips":["Always download immediately after get_media_info — play URLs expire fast.","Check media_type: photo/slideshow posts have no video qualities.","Ensure yt-dlp is installed so fallback quality formats can be extracted.","Use authenticated cookies so TikTok includes playAddr for logged-out-blocked content."],"tags":["tiktok","empty-list","download","expired-url"],"backgroundTag":"empty-result-set","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"}