{"record":{"id":"3a12c3170ebda4f2","repo":"jackwener/OpenCLI","slug":"subtitle-url","errorCode":null,"errorMessage":"字幕条目缺少 subtitle_url 字段","messagePattern":"字幕条目缺少 subtitle_url 字段","errorType":"exception","errorClass":"CommandExecutionError","httpStatus":null,"severity":"error","filePath":"clis/bilibili/subtitle.js","lineNumber":74,"sourceCode":"            throw new CommandExecutionError(`获取视频播放信息失败: ${payload.message} (${payload.code})`);\n        }\n        const needLoginSubtitle = payload.data?.need_login_subtitle === true;\n        const subtitles = payload.data?.subtitle?.subtitles;\n        if (!Array.isArray(subtitles)) {\n            throw new CommandExecutionError('获取到的字幕列表对象不符合数组格式');\n        }\n        if (subtitles.length === 0) {\n            if (needLoginSubtitle) {\n                throw new AuthRequiredError('bilibili.com', 'Bilibili subtitles are hidden behind login for this video. Please log in to bilibili.com in Chrome and retry.');\n            }\n            throw new EmptyResultError('bilibili subtitle', '此视频没有发现外挂或智能字幕。');\n        }\n        // 3. 选择目标字幕语言\n        const target = kwargs.lang\n            ? subtitles.find((s) => s.lan === kwargs.lang) || subtitles[0]\n            : subtitles[0];\n        if (!target || typeof target !== 'object' || !Object.hasOwn(target, 'subtitle_url')) {\n            throw new CommandExecutionError('字幕条目缺少 subtitle_url 字段');\n        }\n        const targetSubUrl = typeof target.subtitle_url === 'string' ? target.subtitle_url.trim() : '';\n        if (!targetSubUrl) {\n            throw new AuthRequiredError('bilibili.com', '[风控拦截/未登录] 获取到的 subtitle_url 为空！请确保 CLI 已成功登录且风控未封锁此账号。');\n        }\n        const finalUrl = targetSubUrl.startsWith('//') ? 'https:' + targetSubUrl : targetSubUrl;\n        if (!/^https?:\\/\\//i.test(finalUrl)) {\n            throw new CommandExecutionError(`字幕 URL 非法: ${finalUrl}`);\n        }\n        // 4. 解析并拉取 CDN 的 JSON 文件\n        const fetchJs = `\n      (async () => {\n         const url = ${JSON.stringify(finalUrl)};\n         const res = await fetch(url);\n         const text = await res.text();\n\n         if (text.startsWith('<!DOCTYPE') || text.startsWith('<html')) {\n            return { error: 'HTML', text: text.substring(0, 100), url };","sourceCodeStart":56,"sourceCodeEnd":92,"githubUrl":"https://github.com/jackwener/OpenCLI/blob/49907e53dc3ade5c223ff0c4c2c2785687cec4e6/clis/bilibili/subtitle.js#L56-L92","documentation":"A CommandExecutionError thrown when the selected subtitle track object does not contain a subtitle_url property. The library picks the track matching kwargs.lang (or the first track) and requires subtitle_url to know where the CDN JSON subtitle file lives. This indicates the API returned malformed or unexpectedly shaped subtitle data.","triggerScenarios":"The chosen subtitles[i] entry lacks subtitle_url — e.g. the player API response shape changed, or the entry matched by kwargs.lang is a stub/metadata-only track.","commonSituations":"Passing a lang code that matches a track with no downloadable URL; Bilibili changing/renaming the subtitle_url field in an API update; mocking or cached API responses missing the field.","solutions":["Drop the --lang option so the library falls back to subtitles[0] instead of a possibly malformed matching track.","Re-run the command — transient API payloads sometimes omit fields.","Check whether a Bilibili API update renamed subtitle_url (inspect the raw /player/wbi/v2 response).","Update the CLI/library to a version matching the current API shape."],"exampleFix":"// before\nawait run('bilibili subtitle', { url, lang: 'ai-zh' });\n// after\nawait run('bilibili subtitle', { url }); // let it pick the first valid track","handlingStrategy":"validation","validationCode":"// After receiving the API list yourself (or after a failure), verify entries:\nconst valid = Array.isArray(subtitles) && subtitles.some(s => s && typeof s === 'object' && 'subtitle_url' in s);","typeGuard":"const hasSubtitleUrl = (t) => !!t && typeof t === 'object' && 'subtitle_url' in t;","tryCatchPattern":"try {\n  await run('bilibili subtitle', { url, lang });\n} catch (e) {\n  if (/subtitle_url/.test(e.message)) {\n    return run('bilibili subtitle', { url }); // retry without lang filter\n  }\n  throw e;\n}","preventionTips":["Avoid pinning --lang to tracks that may be metadata-only.","Keep the library updated for Bilibili API shape changes.","Retry once without the lang filter on this error."],"tags":["bilibili","subtitle","schema","api-response"],"backgroundTag":"schema-validation-failed","analyzedSha":"49907e53dc3ade5c223ff0c4c2c2785687cec4e6","analyzedAt":"2026-08-29T08:14:47.543Z","schemaVersion":2},"datasetVersion":"2026-08-29T12:17:43.993Z"}