{"record":{"id":"1b3b23bac063d2a3","repo":"tonhowtf/omniget","slug":"vimeo-is-a-collection","errorCode":"vimeo:is_a_collection","errorMessage":"vimeo:is_a_collection","messagePattern":"vimeo:is_a_collection","errorType":"error_code","errorClass":null,"httpStatus":null,"severity":"error","filePath":"src-tauri/omniget-core/src/core/tools/vimeo.rs","lineNumber":1095,"sourceCode":"        kind: target.kind().to_string(),\n        title,\n        dest: dest.to_string_lossy().to_string(),\n        total,\n        ok,\n        skipped,\n        failed,\n        items,\n        used_session,\n        command: last_command,\n    })\n}\n\n/// Um vídeo privado ou unlisted. O hash já vai na URL; a senha, quando existe,\n/// vai em `--video-password` e nunca sai daqui.\npub async fn private(opts: &PrivateOptions, progress: &ProgressFn) -> Result<PrivateResult> {\n    let target = parse_target(&opts.url).ok_or_else(|| anyhow!(\"vimeo:bad_url\"))?;\n    if target.is_collection() {\n        return Err(anyhow!(\"vimeo:is_a_collection\"));\n    }\n    let (id, unlisted_hash) = match &target {\n        Target::Video { id, hash } => (id.clone(), hash.is_some()),\n        _ => (String::new(), false),\n    };\n    let url = target.canonical_url();\n    let dest = PathBuf::from(&opts.dest);\n    std::fs::create_dir_all(&dest)?;\n    let bin = ytdlp_bin().await?;\n    let ffmpeg = crate::core::dependencies::find_tool(\"ffmpeg\").await;\n    let cookies = cookie_file(opts.session_netscape.as_deref());\n    let used_session = cookies.is_some();\n    let secrets = secret_refs(opts.video_password.as_ref(), None);\n    let used_password = opts\n        .video_password\n        .as_deref()\n        .map(|p| !p.is_empty())\n        .unwrap_or(false);","sourceCodeStart":1077,"sourceCodeEnd":1113,"githubUrl":"https://github.com/tonhowtf/omniget/blob/8600b91f4246848bac346874daa9e61c1fc5677a/src-tauri/omniget-core/src/core/tools/vimeo.rs#L1077-L1113","documentation":"vimeo:is_a_collection is raised by `private` when the URL parses successfully but points to a collection (showcase, album, channel, or user profile) rather than a single video. The private-video path downloads exactly one video, so collection targets are rejected with this dedicated code.","triggerScenarios":"Calling `private(opts)` with opts.url such as https://vimeo.com/showcase/123456, /album/<id>, /channels/<name>, or /<username> — anything where `target.is_collection()` is true.","commonSituations":"User pastes their portfolio/profile URL into the single-video field; mixing up the 'download collection' and 'download private video' features in the UI; automated routing not distinguishing video ids from usernames.","solutions":["Route the request to `list` (enumerate) or `backup` (batch download) instead of `private`.","Ensure the URL is a single video: https://vimeo.com/<numeric-id> or /<id>/<hash>.","In the caller, use the parsed target kind (video vs showcase/album/channel/user) to pick the correct API before invoking.","Fix UI validation so collection URLs cannot be submitted in the private-video form."],"exampleFix":"// before\nawait vimeoPrivate({ url: \"https://vimeo.com/showcase/9911\" });\n// after\nif (/vimeo\\.com\\/(showcase|album|channels)\\//.test(url) || !/\\d+/.test(url.split(\"/\").pop() ?? \"\")) {\n  await vimeoList({ url });\n} else {\n  await vimeoPrivate({ url });\n}","handlingStrategy":"validation","validationCode":"const COLLECTION_RE = /vimeo\\.com\\/(showcase|album|channels)\\//;\nfunction isProfileUrl(u) {\n  const s = (u ?? \"\").trim();\n  return /^https:\\/\\/vimeo\\.com\\/[a-zA-Z][\\w-]*\\/?$/.test(s);\n}\nif (COLLECTION_RE.test(opts.url) || isProfileUrl(opts.url)) {\n  return vimeoList({ url: opts.url }); // route to collection flow instead\n}","typeGuard":"function isSingleVideoTarget(u) {\n  return /^(https:\\/\\/vimeo\\.com\\/\\d+|\\d+)(\\/[a-z0-9]+)?$/.test((u ?? \"\").trim());\n}","tryCatchPattern":"try {\n  await vimeoPrivate({ url });\n} catch (e) {\n  if (String(e).includes(\"vimeo:is_a_collection\")) {\n    showError(\"That URL is a collection — use batch download instead\");\n  } else throw e;\n}","preventionTips":["Classify the URL (video vs collection) once, centrally, and pick the API from the kind","Disable the private-video form for collection URLs in the UI","Numeric-id URLs are videos; username-shaped URLs are profiles — encode that rule in routing"],"tags":["vimeo","wrong-api","target-type","input-error"],"backgroundTag":"incompatible-source-type","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"}