{"record":{"id":"ae608aac33eb3666","repo":"tonhowtf/omniget","slug":"unsupported-media-type","errorCode":null,"errorMessage":"Unsupported media type","messagePattern":"Unsupported media type","errorType":"exception","errorClass":null,"httpStatus":null,"severity":"warning","filePath":"src-tauri/omniget-core/src/platforms/bluesky.rs","lineNumber":41,"sourceCode":"\nimpl BlueskyDownloader {\n    async fn fallback_ytdlp(&self, url: &str) -> anyhow::Result<MediaInfo> {\n        let ytdlp_path = crate::core::ytdlp::ensure_ytdlp().await?;\n        let json = crate::core::ytdlp::get_video_info(&ytdlp_path, url, &[]).await?;\n        crate::platforms::generic_ytdlp::GenericYtdlpDownloader::parse_video_info(&json)\n    }\n\n    async fn native_get_media_info(&self, url: &str) -> anyhow::Result<MediaInfo> {\n        let (user, post_id) = Self::extract_user_and_post(url)\n            .ok_or_else(|| anyhow!(\"Could not extract user and post_id from URL\"))?;\n\n        let json = self.fetch_post(&user, &post_id).await?;\n\n        let embed = json\n            .pointer(\"/thread/post/embed\")\n            .ok_or_else(|| anyhow!(\"Post does not contain media\"))?;\n\n        let media = extract_media(embed).ok_or_else(|| anyhow!(\"Unsupported media type\"))?;\n\n        let filename_base = format!(\"bluesky_{}_{}\", sanitize_filename::sanitize(&user), post_id);\n\n        match media {\n            BlueskyMedia::Video { hls_url } => Ok(MediaInfo {\n                title: filename_base,\n                author: user,\n                platform: \"bluesky\".to_string(),\n                duration_seconds: None,\n                thumbnail_url: None,\n                available_qualities: vec![VideoQuality {\n                    label: \"best\".to_string(),\n                    width: 0,\n                    height: 0,\n                    url: hls_url,\n                    format: \"hls\".to_string(),\n                }],\n                media_type: MediaType::Video,","sourceCodeStart":23,"sourceCodeEnd":59,"githubUrl":"https://github.com/tonhowtf/omniget/blob/8600b91f4246848bac346874daa9e61c1fc5677a/src-tauri/omniget-core/src/platforms/bluesky.rs#L23-L59","documentation":"Thrown in BlueskyDownloader::native_get_media_info when extract_media(embed) returns None. The post's embed exists but its `$type` is not one of the supported embed views (video, images, external Tenor GIF, recordWithMedia), or required fields (playlist, images.fullsize, external.uri) are missing/empty. It means the native parser cannot handle this post's media shape.","triggerScenarios":"Calling get_media_info on a bsky.app post whose embed is e.g. app.bsky.embed.record#view (quote post without media), an unknown/new embed $type, an images embed whose fullsize URLs are absent, or an external embed pointing to a non-Tenor URI.","commonSituations":"Users paste links to quote-only posts, posts whose external link card is not Tenor, or new embed types Bluesky introduces that the extractor doesn't know; also posts where the CDN returns embed objects with unexpected fields.","solutions":["Rely on the yt-dlp fallback: get_media_info already falls back to yt-dlp when native parsing fails, so ensure yt-dlp is installed/up to date (crate::core::ytdlp::ensure_ytdlp).","Verify the post actually contains downloadable media (video, images, or Tenor GIF) in a browser before treating it as a bug.","Update the library/embed match arms in extract_media to handle the new $type.","Surface a user-facing 'this post has no supported media' message instead of retrying."],"exampleFix":"// before\nlet media = extract_media(embed).ok_or_else(|| anyhow!(\"Unsupported media type\"))?;\n// after\nlet Some(media) = extract_media(embed) else {\n    tracing::debug!(embed = ?embed, \"unhandled bluesky embed; falling back\");\n    return Err(anyhow!(\"Unsupported media type\")); // get_media_info will try yt-dlp\n};","handlingStrategy":"fallback","validationCode":"let embed = json.pointer(\"/thread/post/embed\");\nlet supported = embed\n    .and_then(|e| e.get(\"$type\"))\n    .and_then(|t| t.as_str())\n    .map(|t| matches!(t, \"app.bsky.embed.video#view\" | \"app.bsky.embed.images#view\" | \"app.bsky.embed.external#view\" | \"app.bsky.embed.recordWithMedia#view\"))\n    .unwrap_or(false);","typeGuard":"fn has_supported_embed(json: &serde_json::Value) -> bool {\n    json.pointer(\"/thread/post/embed/$type\")\n        .and_then(|t| t.as_str())\n        .map(|t| t.ends_with(\"video#view\") || t.ends_with(\"images#view\") || t.ends_with(\"external#view\") || t.ends_with(\"recordWithMedia#view\"))\n        .unwrap_or(false)\n}","tryCatchPattern":"match downloader.get_media_info(url).await {\n    Ok(info) => download(info),\n    Err(e) if e.to_string().contains(\"Unsupported media type\") => {\n        // post has no supported embed; inform user, don't retry\n    }\n    Err(e) => report(e),\n}","preventionTips":["Only pass bsky.app post URLs that visibly contain video/images/GIF media","Keep yt-dlp installed so the built-in fallback can handle exotic embeds","Log the embed $type when this error occurs to spot new Bluesky embed kinds early"],"tags":["bluesky","media-parsing","unsupported-embed"],"backgroundTag":"unsupported-operation","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"}