{
  "id": "ljrF8yAzgwnJ3NYx",
  "name": "Get Douyin user published videos and first video details with JustOneAPI",
  "tags": [],
  "nodes": [
    {
      "id": "8f5241af-9b2e-411e-ad22-2f4e77041cd8",
      "name": "Sticky Note",
      "type": "n8n-nodes-base.stickyNote",
      "position": [
        2768,
        480
      ],
      "parameters": {
        "width": 496,
        "height": 464,
        "content": "## Get Douyin user published videos and first video details with JustOneAPI\n\n### How it works\n\n1. Triggers workflow manually\n2. Prepares API and user inputs for Douyin API calls\n3. Gets user's published videos list\n4. Extracts video IDs from the list\n5. Fetches details for the first video\n6. Builds and outputs final video details\n\n### Setup steps\n\n- - [ ] Configure JustOneAPI credentials in workflow settings\n- - [ ] Set Douyin API base URL in 'Prepare API and User Inputs' node\n- - [ ] Verify HTTP request nodes have correct endpoints\n\n### Customization\n\nYou can modify the code in 'Extract Video IDs from List' to process more/fewer videos, or change the output format in 'Build Video Detail Output'."
      },
      "typeVersion": 1
    },
    {
      "id": "3577c88d-b585-4a0c-92bc-59adf3522e7c",
      "name": "Sticky Note1",
      "type": "n8n-nodes-base.stickyNote",
      "position": [
        3328,
        480
      ],
      "parameters": {
        "color": 7,
        "height": 112,
        "content": "## Workflow Trigger\n\nManually starts the workflow execution"
      },
      "typeVersion": 1
    },
    {
      "id": "4ee96882-4112-41b4-83eb-7baaea4a59c6",
      "name": "Sticky Note2",
      "type": "n8n-nodes-base.stickyNote",
      "position": [
        3600,
        480
      ],
      "parameters": {
        "color": 7,
        "height": 112,
        "content": "## Input Preparation\n\nPrepares API endpoints and user inputs for subsequent requests"
      },
      "typeVersion": 1
    },
    {
      "id": "2a6c7215-e2ea-4c01-a58b-b3611d358f91",
      "name": "Sticky Note3",
      "type": "n8n-nodes-base.stickyNote",
      "position": [
        3888,
        480
      ],
      "parameters": {
        "color": 7,
        "width": 528,
        "height": 112,
        "content": "## Get User Videos\n\nFetches list of user's published videos from Douyin API"
      },
      "typeVersion": 1
    },
    {
      "id": "adcafc4c-2bcd-465b-a310-2c427eba0f11",
      "name": "Sticky Note4",
      "type": "n8n-nodes-base.stickyNote",
      "position": [
        4464,
        480
      ],
      "parameters": {
        "color": 7,
        "width": 528,
        "height": 112,
        "content": "## Process Video List\n\nExtracts video IDs from the raw response for further processing"
      },
      "typeVersion": 1
    },
    {
      "id": "41aeb9e1-b52a-4771-bf10-24f0da477a49",
      "name": "Sticky Note5",
      "type": "n8n-nodes-base.stickyNote",
      "position": [
        5008,
        480
      ],
      "parameters": {
        "color": 7,
        "width": 256,
        "height": 112,
        "content": "## Fetch Video Details\n\nGets detailed information about the first video from Douyin API"
      },
      "typeVersion": 1
    },
    {
      "id": "0f717ead-8056-489d-91c7-e22656a775ee",
      "name": "Sticky Note6",
      "type": "n8n-nodes-base.stickyNote",
      "position": [
        5280,
        480
      ],
      "parameters": {
        "color": 7,
        "width": 512,
        "height": 112,
        "content": "## Build Final Output\n\nFormats and prepares the final video details for output"
      },
      "typeVersion": 1
    },
    {
      "id": "0d293ef7-01ac-4b83-b10e-e94f408b6ac1",
      "name": "Start Workflow Execution",
      "type": "n8n-nodes-base.manualTrigger",
      "position": [
        3376,
        640
      ],
      "parameters": {},
      "typeVersion": 1
    },
    {
      "id": "6596942e-0381-47ea-8005-2d1fa3417146",
      "name": "Prepare API and User Data",
      "type": "n8n-nodes-base.set",
      "position": [
        3648,
        640
      ],
      "parameters": {
        "mode": "raw",
        "options": {},
        "jsonOutput": "{\n  \"baseUrl\": \"https://api.justoneapi.com\",\n  \"token\": \"YOUR_JUSTONEAPI_TOKEN\",\n  \"secUid\": \"YOUR_DOUYIN_SEC_UID\",\n  \"maxCursor\": 0,\n  \"maxVideos\": 1\n}"
      },
      "typeVersion": 3.4
    },
    {
      "id": "b7f4c476-83ec-470d-8fca-6e332566ed05",
      "name": "Fetch User Published Videos",
      "type": "n8n-nodes-base.httpRequest",
      "position": [
        3936,
        640
      ],
      "parameters": {
        "url": "={{$json.baseUrl + '/api/douyin/get-user-video-list/v3'}}",
        "options": {
          "redirect": {
            "redirect": {}
          }
        },
        "sendQuery": true,
        "queryParameters": {
          "parameters": [
            {
              "name": "token",
              "value": "={{$json.token}}"
            },
            {
              "name": "secUid",
              "value": "={{$json.secUid}}"
            },
            {
              "name": "maxCursor",
              "value": "={{$json.maxCursor}}"
            }
          ]
        }
      },
      "typeVersion": 4.2
    },
    {
      "id": "8aed753f-fad6-4d43-946b-35be64714051",
      "name": "Output Raw Video Data",
      "type": "n8n-nodes-base.set",
      "position": [
        4272,
        864
      ],
      "parameters": {
        "mode": "raw",
        "options": {},
        "jsonOutput": "={{$json}}"
      },
      "typeVersion": 3.4
    },
    {
      "id": "b21f2851-1e71-4c37-90f1-7ac5d08c5d19",
      "name": "Extract Video IDs from Data",
      "type": "n8n-nodes-base.code",
      "position": [
        4512,
        640
      ],
      "parameters": {
        "jsCode": "const cfg = $('Prepare API and User Data').first().json;\nconst maxVideos = Math.max(1, Number(cfg.maxVideos || 1));\n\nconst rows = $input.all();\n\nfunction asArray(value) {\n  if (Array.isArray(value)) return value;\n  if (value === undefined || value === null) return [];\n  return [value];\n}\n\nfunction firstUrl(mediaObject) {\n  const list = mediaObject?.url_list;\n  return Array.isArray(list) && list.length > 0 ? list[0] : '';\n}\n\nfunction summarizeVideoFromList(video, index) {\n  return {\n    videoRank: index + 1,\n    videoId: video?.aweme_id ? String(video.aweme_id) : '',\n    desc: video?.desc || '',\n    createTime: video?.create_time ?? null,\n    authorUid: video?.author?.uid || '',\n    authorSecUid: video?.author?.sec_uid || '',\n    authorNickname: video?.author?.nickname || '',\n    musicId: video?.music?.id_str || video?.music?.mid || '',\n    musicTitle: video?.music?.title || '',\n    musicAuthor: video?.music?.author || '',\n    shareUrl: video?.share_url || video?.share_info?.share_url || '',\n    coverImage: firstUrl(video?.video?.cover),\n    originCoverImage: firstUrl(video?.video?.origin_cover),\n    imageCount: Array.isArray(video?.images) ? video.images.length : 0,\n    mediaType: video?.media_type ?? null,\n    awemeType: video?.aweme_type ?? null,\n    diggCount: video?.statistics?.digg_count ?? null,\n    commentCount: video?.statistics?.comment_count ?? null,\n    shareCount: video?.statistics?.share_count ?? null,\n    collectCount: video?.statistics?.collect_count ?? null,\n    playCount: video?.statistics?.play_count ?? null\n  };\n}\n\nconst listResponses = rows.flatMap(row => asArray(row.json));\nconst firstListResponse = listResponses[0] || {};\nconst listData = firstListResponse.data || {};\nconst videos = Array.isArray(listData.aweme_list) ? listData.aweme_list : [];\n\nconst videoSummaries = videos.map((video, index) => summarizeVideoFromList(video, index));\nconst selectedVideos = [];\nconst seen = new Set();\n\nfor (let index = 0; index < videos.length; index++) {\n  const video = videos[index];\n  const videoId = video?.aweme_id ? String(video.aweme_id) : '';\n  if (!videoId || seen.has(videoId)) continue;\n  seen.add(videoId);\n  selectedVideos.push({\n    ...summarizeVideoFromList(video, index),\n    rawVideoListItem: video\n  });\n  if (selectedVideos.length >= maxVideos) break;\n}\n\nreturn selectedVideos.map(video => ({\n  json: {\n    baseUrl: cfg.baseUrl,\n    token: cfg.token,\n    secUid: cfg.secUid,\n    maxCursor: cfg.maxCursor,\n    videoId: video.videoId,\n    videoRank: video.videoRank,\n    selectedBy: 'first-unique-aweme_id-from-data-aweme_list',\n    selectedVideoFromList: video,\n    videoListSummary: videoSummaries,\n    pagination: {\n      statusCode: listData.status_code ?? null,\n      minCursor: listData.min_cursor ?? null,\n      maxCursor: listData.max_cursor ?? null,\n      hasMore: listData.has_more ?? null,\n      requestItemCursor: listData.request_item_cursor ?? null,\n      postSerial: listData.post_serial ?? null,\n      imprId: listData.log_pb?.impr_id || ''\n    },\n    rawVideoListOutput: listResponses\n  }\n}));"
      },
      "typeVersion": 2
    },
    {
      "id": "566da34d-6827-43de-8bd0-fbbcf8b37e68",
      "name": "Output Extracted Video IDs",
      "type": "n8n-nodes-base.set",
      "position": [
        4832,
        864
      ],
      "parameters": {
        "mode": "raw",
        "options": {},
        "jsonOutput": "={{$json}}"
      },
      "typeVersion": 3.4
    },
    {
      "id": "06168c05-f554-4183-920b-31a0e010b8de",
      "name": "Fetch First Video Details",
      "type": "n8n-nodes-base.httpRequest",
      "position": [
        5056,
        640
      ],
      "parameters": {
        "url": "={{$json.baseUrl + '/api/douyin/get-video-detail/v2'}}",
        "options": {
          "redirect": {
            "redirect": {}
          }
        },
        "sendQuery": true,
        "queryParameters": {
          "parameters": [
            {
              "name": "token",
              "value": "={{$json.token}}"
            },
            {
              "name": "videoId",
              "value": "={{$json.videoId}}"
            }
          ]
        }
      },
      "typeVersion": 4.2
    },
    {
      "id": "c5b6775e-b6ce-4fa4-9acd-31db57082c45",
      "name": "Build Video Details Output",
      "type": "n8n-nodes-base.code",
      "position": [
        5328,
        640
      ],
      "parameters": {
        "jsCode": "const rows = $input.all();\nconst cfg = $('Prepare API and User Data').first().json;\n\nlet extractedVideos = [];\ntry {\n  extractedVideos = $('Extract Video IDs from Data').all().map(item => item.json);\n} catch (error) {\n  extractedVideos = [];\n}\n\nfunction asArray(value) {\n  if (Array.isArray(value)) return value;\n  if (value === undefined || value === null) return [];\n  return [value];\n}\n\nfunction firstUrl(mediaObject) {\n  const list = mediaObject?.url_list;\n  return Array.isArray(list) && list.length > 0 ? list[0] : '';\n}\n\nfunction summarizeDetail(detail) {\n  return {\n    videoId: detail?.aweme_id ? String(detail.aweme_id) : '',\n    desc: detail?.desc || '',\n    previewTitle: detail?.preview_title || '',\n    createTime: detail?.create_time ?? null,\n    groupId: detail?.group_id || '',\n    secItemId: detail?.sec_item_id || '',\n    shareUrl: detail?.share_url || detail?.share_info?.share_url || '',\n    shareTitle: detail?.share_info?.share_title || '',\n    shareDescription: detail?.share_info?.share_desc || '',\n    mediaType: detail?.media_type ?? null,\n    awemeType: detail?.aweme_type ?? null,\n    isMultiContent: detail?.is_multi_content ?? null,\n    imageCount: Array.isArray(detail?.images) ? detail.images.length : 0,\n    coverImage: firstUrl(detail?.video?.cover),\n    originCoverImage: firstUrl(detail?.video?.origin_cover),\n    videoWidth: detail?.video?.width ?? null,\n    videoHeight: detail?.video?.height ?? null,\n    videoDuration: detail?.video?.duration ?? null,\n    playUrl: firstUrl(detail?.video?.play_addr),\n    downloadUrl: firstUrl(detail?.video?.download_addr),\n    authorUid: detail?.author?.uid || '',\n    authorSecUid: detail?.author?.sec_uid || '',\n    authorNickname: detail?.author?.nickname || '',\n    authorSignature: detail?.author?.signature || '',\n    authorUniqueId: detail?.author?.unique_id || '',\n    musicId: detail?.music?.id_str || detail?.music?.mid || '',\n    musicTitle: detail?.music?.title || '',\n    musicAuthor: detail?.music?.author || '',\n    musicPlayUrl: firstUrl(detail?.music?.play_url),\n    diggCount: detail?.statistics?.digg_count ?? null,\n    commentCount: detail?.statistics?.comment_count ?? null,\n    shareCount: detail?.statistics?.share_count ?? null,\n    collectCount: detail?.statistics?.collect_count ?? null,\n    playCount: detail?.statistics?.play_count ?? null,\n    allowComment: detail?.aweme_control?.can_comment ?? null,\n    allowShare: detail?.aweme_control?.can_share ?? null,\n    allowDownload: detail?.video_control?.allow_download ?? null\n  };\n}\n\nreturn rows.map((item, index) => {\n  const detailResponses = asArray(item.json);\n  const detailRoot = detailResponses[0] || {};\n  const detailData = detailRoot.data || {};\n  const detail = detailData.aweme_detail || {};\n  const extracted = extractedVideos[index] || {};\n\n  return {\n    json: {\n      requestedSecUid: cfg.secUid || '',\n      requestedMaxCursor: cfg.maxCursor ?? 0,\n      videoRank: extracted.videoRank || index + 1,\n      selectedBy: extracted.selectedBy || 'first-unique-aweme_id-from-data-aweme_list',\n      videoId: detail?.aweme_id ? String(detail.aweme_id) : (extracted.videoId || ''),\n\n      videoDetail: summarizeDetail(detail),\n      selectedVideoFromList: extracted.selectedVideoFromList || {},\n      videoListSummary: extracted.videoListSummary || [],\n      pagination: extracted.pagination || {},\n\n      rawVideoListOutput: extracted.rawVideoListOutput || [],\n      rawVideoDetailOutput: detailResponses\n    }\n  };\n});"
      },
      "typeVersion": 2
    },
    {
      "id": "d3ef3dba-6066-49de-9115-955c90966d51",
      "name": "Output Final Video Data",
      "type": "n8n-nodes-base.set",
      "position": [
        5648,
        640
      ],
      "parameters": {
        "mode": "raw",
        "options": {},
        "jsonOutput": "={{$json}}"
      },
      "typeVersion": 3.4
    }
  ],
  "active": false,
  "settings": {
    "binaryMode": "separate",
    "executionOrder": "v1"
  },
  "versionId": "2312b411-6407-4f18-a4bf-1dadf374d869",
  "connections": {
    "Start Workflow Execution": {
      "main": [
        [
          {
            "node": "Prepare API and User Data",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "Fetch First Video Details": {
      "main": [
        [
          {
            "node": "Build Video Details Output",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "Prepare API and User Data": {
      "main": [
        [
          {
            "node": "Fetch User Published Videos",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "Build Video Details Output": {
      "main": [
        [
          {
            "node": "Output Final Video Data",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "Extract Video IDs from Data": {
      "main": [
        [
          {
            "node": "Output Extracted Video IDs",
            "type": "main",
            "index": 0
          },
          {
            "node": "Fetch First Video Details",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "Fetch User Published Videos": {
      "main": [
        [
          {
            "node": "Output Raw Video Data",
            "type": "main",
            "index": 0
          },
          {
            "node": "Extract Video IDs from Data",
            "type": "main",
            "index": 0
          }
        ]
      ]
    }
  }
}