{"record":{"id":"0149a56e3c4d3093","repo":"jackwener/OpenCLI","slug":"bilibili-summary-url-must-use-http-or-https","errorCode":null,"errorMessage":"Bilibili summary URL must use http or https","messagePattern":"Bilibili summary URL must use http or https","errorType":"validation","errorClass":"ArgumentError","httpStatus":null,"severity":"error","filePath":"clis/bilibili/summary.js","lineNumber":38,"sourceCode":"}\n\nasync function readBvid(raw) {\n    const input = String(raw ?? '').trim();\n    if (!input) {\n        throw new ArgumentError('bilibili summary bvid cannot be empty', 'Pass a BV ID, Bilibili video URL, or b23.tv short link.');\n    }\n    if (BVID_RE.test(input)) {\n        return input;\n    }\n    let parsed = null;\n    try {\n        parsed = new URL(input);\n    } catch {\n        // Bare b23.tv short codes are accepted by the shared resolver.\n    }\n    if (parsed) {\n        if (parsed.protocol !== 'https:' && parsed.protocol !== 'http:') {\n            throw new ArgumentError('Bilibili summary URL must use http or https');\n        }\n        if (BILIBILI_HOST_RE.test(parsed.hostname)) {\n            const match = parsed.pathname.match(/\\/(?:video|bangumi\\/play)\\/(BV[A-Za-z0-9]+)/i);\n            if (!match) {\n                throw new ArgumentError('Bilibili summary URL must contain a BV video id');\n            }\n            return match[1];\n        }\n        if (!B23_HOST_RE.test(parsed.hostname)) {\n            throw new ArgumentError('Bilibili summary URL must be a bilibili.com or b23.tv URL');\n        }\n    }\n    try {\n        return await resolveBvid(input);\n    } catch (error) {\n        throw new ArgumentError(`Cannot resolve Bilibili BV ID from input: ${input}`, error instanceof Error ? error.message : String(error));\n    }\n}","sourceCodeStart":20,"sourceCodeEnd":56,"githubUrl":"https://github.com/jackwener/OpenCLI/blob/49907e53dc3ade5c223ff0c4c2c2785687cec4e6/clis/bilibili/summary.js#L20-L56","documentation":"If the bvid input parses as a URL, readBvid only accepts http: or https: schemes. Any other scheme (ftp:, file:, javascript:, ws:, etc.) is rejected with this ArgumentError because the resolver only knows how to fetch over HTTP(S). This is a scheme whitelist check on already-parsed URLs.","triggerScenarios":"Passing a URL-like string whose protocol is not http/https, e.g. `bvid('ftp://bilibili.com/video/BV1xx411c7mD')` or `bvid('file:///tmp/BV1xx411c7mD')`; `new URL()` succeeds, the protocol check at summary.js:37-39 fails.","commonSituations":"Copy-pasting a link from a non-browser tool that emits other schemes; constructing URLs programmatically with a wrong base scheme; accidentally passing a magnet/file URI.","solutions":["Use an https:// URL, e.g. https://www.bilibili.com/video/BV1xx411c7mD.","Or skip the URL entirely and pass the bare BV ID (BV...).","If the input is generated by your code, fix the scheme construction (http/https only)."],"exampleFix":"// before\nconst input = `ftp://www.bilibili.com/video/${bvid}`;\n// after\nconst input = `https://www.bilibili.com/video/${bvid}`;","handlingStrategy":"validation","validationCode":"let parsed;\ntry { parsed = new URL(input); } catch { parsed = null; }\nif (parsed && parsed.protocol !== 'https:' && parsed.protocol !== 'http:') {\n  throw new Error(`Unsupported protocol ${parsed.protocol}; use http(s)`);\n}","typeGuard":"function isHttpUrl(s) {\n  try { const u = new URL(s); return u.protocol === 'https:' || u.protocol === 'http:'; }\n  catch { return false; }\n}","tryCatchPattern":"try {\n  await summaryCommand(input);\n} catch (e) {\n  if (/must use http or https/.test(e.message)) {\n    const fixed = input.replace(/^\\w+:/, 'https:');\n    await summaryCommand(fixed);\n  } else throw e;\n}","preventionTips":["Normalize any programmatically built Bilibili links to https://.","Never paste file/ftp/magnet URIs as video identifiers.","Prefer passing the bare BV id when you already have it."],"tags":["url-validation","protocol","argument-error"],"backgroundTag":"invalid-url-scheme","analyzedSha":"49907e53dc3ade5c223ff0c4c2c2785687cec4e6","analyzedAt":"2026-08-29T08:14:47.543Z","schemaVersion":2},"datasetVersion":"2026-08-29T12:17:43.993Z"}