{"record":{"id":"9c90e7d8c63f12d0","repo":"jackwener/OpenCLI","slug":"ext-mp4-mov-avi-webm-9c90e7","errorCode":null,"errorMessage":"不支持的视频格式: ${ext}（支持 mp4/mov/avi/webm）","messagePattern":"不支持的视频格式: (.+?)（支持 mp4/mov/avi/webm）","errorType":"validation","errorClass":"ArgumentError","httpStatus":null,"severity":"error","filePath":"clis/douyin/publish.js","lineNumber":119,"sourceCode":"        { name: 'allow_download', type: 'bool', default: false, help: '允许下载' },\n        { name: 'collection', default: '', help: '合集 ID' },\n        { name: 'activity', default: '', help: '活动 ID' },\n        { name: 'poi_id', default: '', help: '地理位置 ID' },\n        { name: 'poi_name', default: '', help: '地理位置名称' },\n        { name: 'hotspot', default: '', help: '关联热点词' },\n        { name: 'no_safety_check', type: 'bool', default: false, help: '跳过内容安全检测' },\n        { name: 'sync_toutiao', type: 'bool', default: false, help: '同步发布到头条' },\n    ],\n    columns: ['status', 'aweme_id', 'url', 'publish_time'],\n    func: async (page, kwargs) => {\n        // ── Fail-fast validation ────────────────────────────────────────────\n        const videoPath = path.resolve(kwargs.video);\n        if (!fs.existsSync(videoPath)) {\n            throw new ArgumentError(`视频文件不存在: ${videoPath}`);\n        }\n        const ext = path.extname(videoPath).toLowerCase();\n        if (!['.mp4', '.mov', '.avi', '.webm'].includes(ext)) {\n            throw new ArgumentError(`不支持的视频格式: ${ext}（支持 mp4/mov/avi/webm）`);\n        }\n        const fileSize = fs.statSync(videoPath).size;\n        const title = kwargs.title;\n        if (title.length > 30) {\n            throw new ArgumentError('标题不能超过 30 字');\n        }\n        const caption = kwargs.caption || '';\n        if (caption.length > 1000) {\n            throw new ArgumentError('正文不能超过 1000 字');\n        }\n        const timingTs = toUnixSeconds(kwargs.schedule);\n        validateTiming(timingTs);\n        const visibilityType = VISIBILITY_MAP[kwargs.visibility] ?? 0;\n        const coverPath = kwargs.cover;\n        if (coverPath) {\n            if (!fs.existsSync(path.resolve(coverPath))) {\n                throw new ArgumentError(`封面文件不存在: ${path.resolve(coverPath)}`);\n            }","sourceCodeStart":101,"sourceCodeEnd":137,"githubUrl":"https://github.com/jackwener/OpenCLI/blob/49907e53dc3ade5c223ff0c4c2c2785687cec4e6/clis/douyin/publish.js#L101-L137","documentation":"ArgumentError thrown when the video file's extension (lowercased) is not one of .mp4, .mov, .avi, .webm. The library rejects unsupported containers before attempting upload.","triggerScenarios":"Publishing a file with an extension outside the allowlist — e.g. .mkv, .flv, .ts, .wmv, or a misnamed file like video.mp4.txt (clis/douyin/publish.js:119).","commonSituations":"Screen recorders producing .mkv/.flv; OBS default mkv output; files downloaded as .webm.part or renamed with wrong extension; concatenating extensionless temp files.","solutions":["Re-encode/transcode the video to MP4 (e.g. ffmpeg -i in.mkv -c:v libx264 -c:a aac out.mp4).","Rename the file with a correct supported extension if the container actually matches.","Check that the extension is lowercase-valid; the check is case-insensitive but the extension must still be one of the four.","Update the library if you need a newly supported format."],"exampleFix":"// before\nffmpeg -i screen-recording.mkv -c copy out.mkv\n// after\nffmpeg -i screen-recording.mkv -c:v libx264 -c:a aac out.mp4","handlingStrategy":"validation","validationCode":"const SUPPORTED = ['.mp4', '.mov', '.avi', '.webm'];\nconst ext = path.extname(videoPath).toLowerCase();\nif (!SUPPORTED.includes(ext)) throw new Error(`re-encode ${videoPath} (${ext}) to mp4 before publishing`);","typeGuard":null,"tryCatchPattern":"try {\n  await publish({ video, title });\n} catch (e) {\n  if (String(e.message).startsWith('不支持的视频格式')) {\n    console.error('transcode with ffmpeg to .mp4 and retry');\n  }\n  throw e;\n}","preventionTips":["Standardize recording/encoding pipelines on MP4 output.","Never trust file names — verify container/extension before publishing.","Avoid double extensions like clip.mp4.txt.","Configure OBS/screen recorders to record directly in mp4."],"tags":["argument-validation","video-format","file-extension"],"backgroundTag":"unsupported-file-format","analyzedSha":"49907e53dc3ade5c223ff0c4c2c2785687cec4e6","analyzedAt":"2026-08-29T08:14:47.543Z","schemaVersion":2},"datasetVersion":"2026-08-29T12:17:43.993Z"}