{"record":{"id":"27885181711a3d23","repo":"jackwener/OpenCLI","slug":"douyin-user-videos","errorCode":null,"errorMessage":"douyin user-videos","messagePattern":"douyin user-videos","errorType":"exception","errorClass":"EmptyResultError","httpStatus":null,"severity":"error","filePath":"clis/douyin/user-videos.js","lineNumber":79,"sourceCode":"    domain: 'www.douyin.com',\n    strategy: Strategy.COOKIE,\n    args: [\n        { name: 'sec_uid', type: 'string', required: true, positional: true, help: '用户 sec_uid（个人主页 URL 末尾部分，也可直接传整条主页 URL）' },\n        { name: 'limit', type: 'int', default: 20, help: '获取数量（最大 20）' },\n        { name: 'with_comments', type: 'bool', default: true, help: '包含热门评论（默认: true）' },\n        { name: 'comment_limit', type: 'int', default: 10, help: '每个视频获取多少条评论（最大 10）' },\n    ],\n    columns: ['index', 'aweme_id', 'title', 'duration', 'digg_count', 'play_url', 'top_comments'],\n    func: async (page, kwargs) => {\n        const secUid = normalizeSecUid(kwargs.sec_uid);\n        const limit = normalizeUserVideosLimit(kwargs.limit);\n        const withComments = kwargs.with_comments !== false;\n        const commentLimit = normalizeCommentLimit(kwargs.comment_limit);\n        await page.goto(`https://www.douyin.com/user/${secUid}`);\n        await page.wait(3);\n        const awemeList = (await fetchDouyinUserVideos(page, secUid, limit)).slice(0, limit);\n        if (awemeList.length === 0) {\n            throw new EmptyResultError('douyin user-videos', `No videos were returned for sec_uid ${secUid}. Confirm the user exists and the Douyin session is valid.`);\n        }\n        const videos = withComments\n            ? await mapInBatches(awemeList, USER_VIDEO_COMMENT_CONCURRENCY, async (video) => ({\n                ...video,\n                top_comments: await fetchTopComments(page, video.aweme_id, commentLimit),\n            }))\n            : awemeList.map((video) => ({ ...video, top_comments: [] }));\n        return videos.map((video, index) => {\n            const playUrl = video.video?.play_addr?.url_list?.[0] ?? '';\n            return {\n                index: index + 1,\n                aweme_id: video.aweme_id,\n                title: video.desc ?? '',\n                duration: Math.round((video.video?.duration ?? 0) / 1000),\n                digg_count: video.statistics?.digg_count ?? 0,\n                play_url: playUrl,\n                top_comments: video.top_comments ?? [],\n            };","sourceCodeStart":61,"sourceCodeEnd":97,"githubUrl":"https://github.com/jackwener/OpenCLI/blob/49907e53dc3ade5c223ff0c4c2c2785687cec4e6/clis/douyin/user-videos.js#L61-L97","documentation":"An EmptyResultError thrown by the douyin user-videos command when fetchDouyinUserVideos returns no videos for the given sec_uid. The library treats an empty video list as an error rather than returning [] so callers can distinguish 'user has no listable videos' from a successful (possibly filtered) run. The message includes the sec_uid and points at account-existence or session validity.","triggerScenarios":"Calling `douyin user-videos --sec-uid <valid-format-sec-uid>` where the user profile page loads but fetchDouyinUserVideos yields an empty awemeList — no published videos, region/login restrictions hiding the list, or the page rendering as an error/verify page the scraper reads as empty.","commonSituations":"Target account deleted, renamed, or has zero public videos; account is private or shadow-restricted; the browsing session is logged out or flagged so Douyin serves an empty list; sec_uid belongs to a deactivated account.","solutions":["Open https://www.douyin.com/user/<sec_uid> in a normal browser and confirm the profile exists and shows videos.","Refresh the Douyin login session (re-run the auth flow) and retry.","Confirm the sec_uid corresponds to a non-deactivated account; if so, treat EmptyResultError as 'user has no videos' in your code.","Retry later if Douyin is serving a verification/captcha page that suppresses the video list."],"exampleFix":"// before\nconst { videos } = await run('douyin user-videos', { sec_uid });\n// after\nlet result;\ntry {\n  result = await run('douyin user-videos', { sec_uid });\n} catch (e) {\n  if (e.name === 'EmptyResultError') return { videos: [] };\n  throw e;\n}","handlingStrategy":"try-catch","validationCode":null,"typeGuard":null,"tryCatchPattern":"try {\n  const { videos } = await run('douyin user-videos', { sec_uid });\n} catch (e) {\n  if (e.name === 'EmptyResultError') return { videos: [] }; // user has no listable videos\n  throw e;\n}","preventionTips":["Verify the profile exists and has public videos in a normal browser first.","Refresh the Douyin session before large scrapes.","Treat EmptyResultError for user-videos as a legitimate empty account, not a crash."],"tags":["empty-result","douyin","scraping","session"],"backgroundTag":"empty-result-set","analyzedSha":"49907e53dc3ade5c223ff0c4c2c2785687cec4e6","analyzedAt":"2026-08-29T08:14:47.543Z","schemaVersion":2},"datasetVersion":"2026-08-29T17:17:51.833Z"}