{"record":{"id":"d735b4047749edd2","repo":"jackwener/OpenCLI","slug":"bilibili-summary-url-must-be-a-bilibili-com-or-b23","errorCode":null,"errorMessage":"Bilibili summary URL must be a bilibili.com or b23.tv URL","messagePattern":"Bilibili summary URL must be a bilibili\\.com or b23\\.tv URL","errorType":"validation","errorClass":"ArgumentError","httpStatus":null,"severity":"error","filePath":"clis/bilibili/summary.js","lineNumber":48,"sourceCode":"    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}\n\nfunction requireOkPayload(payload, label) {\n    if (!payload || typeof payload !== 'object' || Array.isArray(payload)) {\n        throw new CommandExecutionError(`Bilibili ${label} API returned a malformed payload`);\n    }\n    if (payload.code !== 0) {\n        const message = payload.message ?? 'unknown error';\n        if (payload.code === -101 || payload.code === -403 || /登录|权限|forbidden|permission|login/i.test(String(message))) {\n            throw new AuthRequiredError('bilibili.com', `Bilibili ${label} API requires login or permission: ${message} (${payload.code})`);\n        }","sourceCodeStart":30,"sourceCodeEnd":66,"githubUrl":"https://github.com/jackwener/OpenCLI/blob/49907e53dc3ade5c223ff0c4c2c2785687cec4e6/clis/bilibili/summary.js#L30-L66","documentation":"If the input parses as a URL but its hostname is neither bilibili.com nor b23.tv (checked by BILIBILI_HOST_RE and B23_HOST_RE), readBvid rejects it with this ArgumentError. The library will only resolve ids from official Bilibili domains; arbitrary third-party URLs are not fetched, partly for safety and partly because the extraction logic would not apply.","triggerScenarios":"Passing URLs from other sites that embed Bilibili players, e.g. `https://www.youtube.com/watch?v=...`, a mirror site, or a localhost dev URL like `http://localhost:3000/video/BV1xx411c7mD`.","commonSituations":"Grabbing a link from an aggregator or embedded player page; typos in the domain (bilibili.co, bilibili.tv are not matched); testing against a local mock server whose host isn't bilibili.com.","solutions":["Use the canonical URL on www.bilibili.com or the b23.tv short link.","Or extract the BV ID yourself and pass the bare id.","Fix domain typos — the check accepts any *.bilibili.com and *.b23.tv subdomain."],"exampleFix":"// before\nawait summaryCommand('https://mirror.example.com/watch/BV1xx411c7mD');\n// after\nawait summaryCommand('https://www.bilibili.com/video/BV1xx411c7mD');","handlingStrategy":"validation","validationCode":"const u = new URL(input);\nconst ok = /(^|\\.)bilibili\\.com$/i.test(u.hostname) || /(^|\\.)b23\\.tv$/i.test(u.hostname);\nif (!ok) throw new Error(`Host ${u.hostname} is not allowed; use bilibili.com or b23.tv`);","typeGuard":"function isBilibiliHostUrl(u) {\n  try {\n    const h = new URL(u).hostname;\n    return /(^|\\.)bilibili\\.com$/i.test(h) || /(^|\\.)b23\\.tv$/i.test(h);\n  } catch { return false; }\n}","tryCatchPattern":"try {\n  await summaryCommand(input);\n} catch (e) {\n  if (/bilibili\\.com or b23\\.tv URL/.test(e.message)) {\n    const bvid = input.match(/BV[A-Za-z0-9]+/)?.[0];\n    if (bvid) await summaryCommand(bvid);\n    else throw e;\n  } else throw e;\n}","preventionTips":["Extract the BV id from embedded/third-party pages yourself and pass the bare id.","Watch for lookalike domains (bilibili.tv, bilibili.co) that fail the whitelist.","In tests, pass bare BV ids instead of local mock host URLs."],"tags":["url-validation","domain-whitelist","argument-error"],"backgroundTag":"untrusted-url-host","analyzedSha":"49907e53dc3ade5c223ff0c4c2c2785687cec4e6","analyzedAt":"2026-08-29T08:14:47.543Z","schemaVersion":2},"datasetVersion":"2026-08-29T17:17:51.833Z"}