{"record":{"id":"5318cc69a68858b9","repo":"jackwener/OpenCLI","slug":"expected-an-exact-bvid-or-bilibili-com-video-url","errorCode":null,"errorMessage":"Expected an exact BVID or bilibili.com video URL, for example BV1xx411c7mD","messagePattern":"Expected an exact BVID or bilibili\\.com video URL, for example BV1xx411c7mD","errorType":"validation","errorClass":"ArgumentError","httpStatus":null,"severity":"error","filePath":"clis/bilibili/utils.js","lineNumber":24,"sourceCode":"\nconst EXACT_BVID_RE = /^BV[0-9A-Za-z]{10}$/;\nconst VIDEO_HOSTS = new Set(['bilibili.com', 'www.bilibili.com', 'm.bilibili.com']);\n\n/**\n * Parse one exact, case-sensitive BVID or a trusted bilibili.com video URL.\n * Unlike the legacy short-link resolver, this is synchronous and never treats\n * malformed input as a b23.tv network lookup.\n */\nexport function parseBvidOrVideoUrl(value) {\n    const raw = String(value ?? '').trim();\n    if (EXACT_BVID_RE.test(raw)) return raw;\n\n    let parsed;\n    try {\n        parsed = new URL(raw);\n    }\n    catch {\n        throw new ArgumentError('Expected an exact BVID or bilibili.com video URL, for example BV1xx411c7mD');\n    }\n    if (!VIDEO_HOSTS.has(parsed.hostname) || parsed.protocol !== 'https:' || parsed.username || parsed.password || parsed.port) {\n        throw new ArgumentError('Expected a trusted HTTPS bilibili.com video URL without credentials or a custom port');\n    }\n    const match = parsed.pathname.match(/^\\/video\\/(BV[0-9A-Za-z]{10})\\/?$/);\n    if (!match) {\n        throw new ArgumentError('Bilibili video URL did not contain an exact case-sensitive BVID');\n    }\n    return match[1];\n}\n/**\n * Resolve Bilibili short URL / short code to BV ID.\n * Supports: BV1MV9NBtENN, XYzsqGa, b23.tv/XYzsqGa, https://b23.tv/XYzsqGa\n */\nexport function resolveBvid(input) {\n    const trimmed = String(input).trim();\n    if (/^BV[A-Za-z0-9]+$/i.test(trimmed)) {\n        return Promise.resolve(trimmed);","sourceCodeStart":6,"sourceCodeEnd":42,"githubUrl":"https://github.com/jackwener/OpenCLI/blob/49907e53dc3ade5c223ff0c4c2c2785687cec4e6/clis/bilibili/utils.js#L6-L42","documentation":"parseBvidOrVideoUrl in clis/bilibili/utils.js first checks for an exact BV[0-9A-Za-z]{10} BVID; if the input isn't one, it tries new URL(raw). When the string cannot be parsed as a URL at all, it throws ArgumentError 'Expected an exact BVID or bilibili.com video URL...'. The function is deliberately synchronous and strict — it never falls back to b23.tv short-code network resolution.","triggerScenarios":"Calling bvid/parseBvidOrVideoUrl with input that is neither a valid BVID nor a parsable absolute URL: a bare short code like 'XYzsqGa', a b23.tv short link, 'BV1' (too short), an empty string, or a URL without a scheme.","commonSituations":"Passing a b23.tv short link to this strict parser instead of resolveBvid; lowercasing the BVID (BV prefix is case-sensitive, though 'BV' itself must be exact and the rest alphanumeric — actually this error fires before the path check when input isn't URL-like); forgetting 'https://' on a bilibili.com URL.","solutions":["Pass an exact 12-character BVID like BV1xx411c7mD","Or pass a full URL: https://www.bilibili.com/video/BV1xx411c7mD/","For b23.tv short links or short codes, use resolveBvid instead of parseBvidOrVideoUrl","Add the https:// scheme if you omitted it"],"exampleFix":"// before\nparseBvidOrVideoUrl('b23.tv/XYzsqGa');\n// after\nparseBvidOrVideoUrl('https://www.bilibili.com/video/BV1xx411c7mD/');","handlingStrategy":"validation","validationCode":"function isExactBvid(v) {\n  return /^BV[0-9A-Za-z]{10}$/.test(String(v ?? '').trim());\n}\nfunction isBilibiliVideoUrl(v) {\n  try {\n    const u = new URL(String(v));\n    return /^(www|m)?\\.?bilibili\\.com$/.test(u.hostname) && /^\\/video\\/BV[0-9A-Za-z]{10}\\/?$/.test(u.pathname);\n  } catch { return false; }\n}\nif (!isExactBvid(input) && !isBilibiliVideoUrl(input)) throw new Error(`Bad bvid input: ${input}`);","typeGuard":"function isBvid(v) {\n  return typeof v === 'string' && /^BV[0-9A-Za-z]{10}$/.test(v);\n}","tryCatchPattern":"try {\n  const bvid = parseBvidOrVideoUrl(input);\n} catch (err) {\n  if (err instanceof ArgumentError) {\n    // input may be a b23.tv short link — fall back to the async resolver\n    const bvid = await resolveBvid(input);\n  } else throw err;\n}","preventionTips":["Use resolveBvid (async) for b23.tv short links and short codes; reserve parseBvidOrVideoUrl for exact BVIDs/URLs","Keep a canonical normalize step: trim input and add https:// if it starts with a known host","Never lowercase a BVID before validation","Store video references as exact BVIDs, not page URLs"],"tags":["argument-validation","bilibili","url-parsing"],"backgroundTag":"invalid-video-id-format","analyzedSha":"49907e53dc3ade5c223ff0c4c2c2785687cec4e6","analyzedAt":"2026-08-29T08:14:47.543Z","schemaVersion":2},"datasetVersion":"2026-08-29T12:17:43.993Z"}