{"record":{"id":"f46816832be85a99","repo":"tonhowtf/omniget","slug":"no-url-available-f46816","errorCode":null,"errorMessage":"No URL available","messagePattern":"No URL available","errorType":"exception","errorClass":"anyhow::Error","httpStatus":null,"severity":"error","filePath":"src-tauri/src/platforms/bilibili/mod.rs","lineNumber":108,"sourceCode":"        }\n        line.split('\\t').nth(5) == Some(\"SESSDATA\")\n    })\n}\n\nasync fn api_engine_download(\n    info: &MediaInfo,\n    opts: &DownloadOptions,\n    progress: mpsc::Sender<ProgressUpdate>,\n) -> anyhow::Result<DownloadResult> {\n    let _ = cookie::ensure_fresh().await;\n\n    let url = info\n        .available_qualities\n        .first()\n        .map(|q| q.url.as_str())\n        .unwrap_or(\"\");\n    if url.is_empty() {\n        return Err(anyhow!(\"No URL available\"));\n    }\n\n    let slug = active_account_slug();\n    let client = build_api_client(slug.as_deref(), opts.user_agent.as_deref())?;\n\n    let mut effective_url = url.to_string();\n    if url_kind::is_b23_short(&effective_url) {\n        if let Ok(resolved) = url_kind::resolve_b23(&client, &effective_url).await {\n            effective_url = resolved;\n        }\n    }\n\n    let kind = url_kind::detect(&effective_url)\n        .map_err(|e| anyhow!(\"Failed to detect URL kind: {}\", e.i18n_key()))?;\n    let parsed = parser::parse(&client, &kind)\n        .await\n        .map_err(|e| anyhow!(\"Failed to parse content: {}\", e.i18n_key()))?;\n","sourceCodeStart":90,"sourceCodeEnd":126,"githubUrl":"https://github.com/tonhowtf/omniget/blob/8600b91f4246848bac346874daa9e61c1fc5677a/src-tauri/src/platforms/bilibili/mod.rs#L90-L126","documentation":"The modern API-engine download path (`api_engine_download`) mirrors the legacy check: it takes the first entry of `info.available_qualities` and throws `No URL available` when the resolved URL is empty. The API engine cannot build an effective download URL without one.","triggerScenarios":"Calling `download` routed to the API engine with a MediaInfo whose `available_qualities` is empty or whose first quality has an empty `url` — failed parse, expired stream URLs, or content (e.g. charge-only/region-locked videos) that yields no playable streams for the current account.","commonSituations":"Downloading premium (充电专属) or region-locked Bilibili videos without proper login/account; stale MediaInfo fetched long before download; API returning metadata but empty `durl`/`dash` lists; bug in a parser producing quality entries with empty URLs.","solutions":["Re-fetch MediaInfo via `get_media_info` immediately before downloading so URLs are fresh.","Log in / select the right account (`active_account_slug`) so protected streams resolve.","Inspect the parsed response: if the API returned no stream URLs, the content likely requires purchase/login or is unavailable.","Check `info.available_qualities` non-empty before calling download and surface a friendly message."],"exampleFix":"// before\ndownload(info, opts, progress).await?; // No URL available\n// after\nensure!(!info.available_qualities.is_empty() && !info.available_qualities[0].url.is_empty(), \"no stream\");\nlet info = get_media_info(&source_url).await?; // refresh\ndownload(info, opts, progress).await?;","handlingStrategy":"validation","validationCode":"fn stream_url_ready(info: &MediaInfo) -> bool {\n    info.available_qualities.first().map(|q| !q.url.is_empty()).unwrap_or(false)\n}\nif !stream_url_ready(&info) { info = get_media_info(&src).await?; }","typeGuard":null,"tryCatchPattern":"match download(info, opts, progress).await {\n    Err(e) if e.to_string().contains(\"No URL available\") => notify_no_stream(&info),\n    Err(e) => return Err(e),\n    Ok(_) => {},\n}","preventionTips":["Re-fetch MediaInfo right before download; URLs expire.","Ensure the correct account is active for protected content.","Validate parsed results so empty stream lists surface early.","Handle login/charge-only content explicitly instead of passing empty qualities through."],"tags":["download","api","bilibili"],"backgroundTag":"empty-required-field","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"}