{
  "name": "\u89c6\u9891\u526a\u85cf\u5de5\u4f5c\u6d41 Demo",
  "nodes": [
    {
      "parameters": {},
      "type": "n8n-nodes-base.manualTrigger",
      "typeVersion": 1,
      "position": [
        -800,
        -160
      ],
      "id": "01d13c16-a9d1-4124-9ef0-b3e95cdeda99",
      "name": "When clicking \u2018Execute workflow\u2019"
    },
    {
      "parameters": {
        "resource": "playlistItem",
        "operation": "getAll",
        "playlistId": "PLORDp40s58gMHecjJRjHQ4J3K23iMrGfd",
        "returnAll": true,
        "options": {}
      },
      "type": "n8n-nodes-base.youTube",
      "typeVersion": 1,
      "position": [
        -592,
        -160
      ],
      "id": "fab9b67d-707a-44a5-bcd9-d5f3b5325945",
      "name": "Get many playlist items",
      "credentials": {
        "youTubeOAuth2Api": {
          "name": "<your credential>"
        }
      }
    },
    {
      "parameters": {
        "assignments": {
          "assignments": [
            {
              "id": "4c81e286-8f54-4fe3-980d-de801b8d04d0",
              "name": "videoname",
              "value": "={{ $json.snippet.title }}",
              "type": "string"
            },
            {
              "id": "ba8319e3-e4ba-4cbb-a115-5e9f3de5dc8b",
              "name": "url",
              "value": "=https://www.youtube.com/watch?v={{ $json.snippet.resourceId.videoId }}",
              "type": "string"
            },
            {
              "id": "c7f9de6d-63b7-41ef-bd0e-438190921c34",
              "name": "pubilsh_time",
              "value": "={{ $json.contentDetails.videoPublishedAt }}",
              "type": "string"
            },
            {
              "id": "fe8ad35d-35f1-4248-af6e-adb7e28ac419",
              "name": "videoId",
              "value": "={{ $json.snippet.resourceId.videoId }}",
              "type": "string"
            }
          ]
        },
        "options": {}
      },
      "type": "n8n-nodes-base.set",
      "typeVersion": 3.4,
      "position": [
        -368,
        -160
      ],
      "id": "db70c9c3-2a5f-4130-bcf2-63b945354aae",
      "name": "Edit Fields"
    },
    {
      "parameters": {
        "options": {}
      },
      "type": "n8n-nodes-base.splitInBatches",
      "typeVersion": 3,
      "position": [
        -80,
        -160
      ],
      "id": "26b80b65-59c5-4547-b990-80e469385cad",
      "name": "Loop Over Items"
    },
    {
      "parameters": {
        "method": "POST",
        "url": "http://host.docker.internal:8081/add",
        "sendHeaders": true,
        "headerParameters": {
          "parameters": [
            {
              "name": "Content-Type",
              "value": "application/json"
            }
          ]
        },
        "sendBody": true,
        "specifyBody": "json",
        "jsonBody": "={\n  \"url\": \"{{ $json.url }}\",\n  \"quality\": \"720p\",\n  \"format\": \"mp4\", \n  \"folder\": \"demo/assets\"\n}  ",
        "options": {}
      },
      "type": "n8n-nodes-base.httpRequest",
      "typeVersion": 4.3,
      "position": [
        176,
        -144
      ],
      "id": "c67b8af3-0b94-4041-8e6b-78211d19f5d0",
      "name": "HTTP Request"
    },
    {
      "parameters": {
        "fileSelector": "=./n8ndata/downloads/demo/assets/{{ $('Loop Over Items').item.json.videoname }}.*.vtt",
        "options": {}
      },
      "type": "n8n-nodes-base.readWriteFile",
      "typeVersion": 1,
      "position": [
        1264,
        -128
      ],
      "id": "b8955f92-7d2e-480f-9013-41fb46dadbd7",
      "name": "Read/Write Files from Disk"
    },
    {
      "parameters": {
        "operation": "text",
        "options": {}
      },
      "type": "n8n-nodes-base.extractFromFile",
      "typeVersion": 1.1,
      "position": [
        1504,
        -128
      ],
      "id": "75e3ed32-8afb-4ef1-b487-387457cbc8b9",
      "name": "Extract from File"
    },
    {
      "parameters": {
        "promptType": "define",
        "text": "=\u5b57\u5e55\u5185\u5bb9\u5982\u4e0b\uff1a{{ $json.data }}",
        "hasOutputParser": true,
        "options": {
          "systemMessage": "# Role\n\u4f60\u662f\u4e00\u4f4d\u4e13\u4e1a\u7684\u89c6\u9891\u5185\u5bb9\u5206\u6790\u4e13\u5bb6\uff0c\u64c5\u957f\u4ece\u5197\u957f\u7684\u89c6\u9891\u5b57\u5e55\u4e2d\u63d0\u53d6\u6838\u5fc3\u89c2\u70b9\uff0c\u5e76\u5c06\u5176\u6574\u7406\u6210\u7ed3\u6784\u6e05\u6670\u3001\u5e26\u6807\u7b7e\u5206\u7c7b\u3001\u6613\u4e8e\u68c0\u7d22\u7684\u6458\u8981\u548c\u4e8c\u7ea7\u5927\u7eb2\u3002\n\n# Task\n\u8bf7\u9605\u8bfb\u63d0\u4f9b\u7684\u89c6\u9891\u5b57\u5e55\u6587\u4ef6\uff08\u5305\u542b\u65f6\u95f4\u6233\uff09\uff0c\u5e76\u6309\u7167\u4ee5\u4e0b\u56fa\u5b9a\u6a21\u677f\u751f\u6210\u5185\u5bb9\uff1a\n\n1. \u5185\u5bb9\u6807\u7b7e\uff1a\u63d0\u53d6 3-5 \u4e2a\u6838\u5fc3\u5173\u952e\u8bcd\u4f5c\u4e3a\u6807\u7b7e\uff08\u4f8b\u5982\uff1a#AI #n8n #\u81ea\u52a8\u5316 #\u6559\u7a0b\uff09\u3002\u8981\u6c42\u6db5\u76d6\u89c6\u9891\u6d89\u53ca\u7684\u6838\u5fc3\u5de5\u5177\u3001\u6280\u672f\u9886\u57df\u548c\u89c6\u9891\u6027\u8d28\u3002\n2. \u89c6\u9891\u6458\u8981\uff1a\u7528\u4e00\u6bb5\u8bdd\uff08\u7ea6 150-200 \u5b57\uff09\u9ad8\u5ea6\u6982\u62ec\u89c6\u9891\u7684\u6838\u5fc3\u5185\u5bb9\u3001\u903b\u8f91\u6d41\u7a0b\u4ee5\u53ca\u6700\u7ec8\u7ed3\u8bba\u3002\n3. \u4eae\u70b9\u5927\u7eb2\uff08\u4e8c\u7ea7\u7ed3\u6784\uff09\uff1a\n   - \u4e00\u7ea7\u6807\u9898\uff1a\u6807\u6ce8\u8be5\u7ae0\u8282\u7684\u8d77\u59cb\u65f6\u95f4\u6233\u53ca\u6838\u5fc3\u4e3b\u9898\u3002\n   - \u4e8c\u7ea7\u8981\u70b9\uff1a\u7f57\u5217\u8be5\u7ae0\u8282\u4e0b\u7684\u5177\u4f53\u7ec6\u8282\u3001\u64cd\u4f5c\u6b65\u9aa4\u6216\u5173\u952e\u8bba\u70b9\uff0c\u5e76\u7cbe\u786e\u6807\u6ce8\u5bf9\u5e94\u7684\u51fa\u73b0\u65f6\u95f4\u3002\n\n# Constraints\n- \u603b\u7ed3\u8981\u6c42\uff1a\u8bed\u6c14\u5ba2\u89c2\u4e13\u4e1a\uff0c\u80fd\u591f\u8ba9\u7528\u6237\u4e0d\u770b\u89c6\u9891\u4e5f\u80fd\u638c\u63e1 80% \u7684\u6838\u5fc3\u4fe1\u606f\u3002\n- \u65f6\u95f4\u6233\u7cbe\u5ea6\uff1a\u5fc5\u987b\u4e25\u683c\u57fa\u4e8e\u5b57\u5e55\u4e2d\u63d0\u4f9b\u7684\u65f6\u95f4\u4fe1\u606f\uff0c\u786e\u4fdd\u51c6\u786e\u6027\u3002\n- \u6807\u7b7e\u8981\u6c42\uff1a\u6807\u7b7e\u9700\u5177\u6709\u68c0\u7d22\u4ef7\u503c\uff0c\u4f18\u5148\u63d0\u53d6\u5de5\u5177\u540d\u3001\u6280\u672f\u540d\u8bcd\u6216\u573a\u666f\u5206\u7c7b\u3002\n- \u8bed\u8a00\uff1a\u7edf\u4e00\u4f7f\u7528\u4e2d\u6587\u3002\n- \u7b80\u6d01\u6027\uff1a\u4fdd\u6301\u7b80\u660e\u627c\u8981\uff0c\u4e25\u7981\u5197\u957f\u5e9f\u8bdd\u3002"
        }
      },
      "type": "@n8n/n8n-nodes-langchain.agent",
      "typeVersion": 3,
      "position": [
        1728,
        -128
      ],
      "id": "5aff7633-6bbb-4935-b406-21fc664da379",
      "name": "AI Agent"
    },
    {
      "parameters": {
        "options": {}
      },
      "type": "@n8n/n8n-nodes-langchain.lmChatDeepSeek",
      "typeVersion": 1,
      "position": [
        1696,
        80
      ],
      "id": "afc66731-a9e2-4300-beb2-acf809264831",
      "name": "DeepSeek Chat Model",
      "credentials": {
        "deepSeekApi": {
          "name": "<your credential>"
        }
      }
    },
    {
      "parameters": {
        "jsonSchemaExample": "{\n  \"tags\":[\"\u6807\u7b7e\",\"\u6807\u7b7e\",\"\u6807\u7b7e\"],\n  \"summary\": \"\u6b64\u5904\u586b\u5199\u751f\u6210\u7684\u89c6\u9891\u603b\u7ed3\u5168\u6587\uff0c\u8981\u6c42\u903b\u8f91\u8fde\u8d2f\uff0c\u6db5\u76d6\u89c6\u9891\u7684\u8d77\u56e0\u3001\u7ecf\u8fc7\u3001\u7ed3\u679c\u548c\u535a\u4e3b\u5efa\u8bae\u3002\",\n  \"highlights\": [\n    {\n      \"timestamp\": \"00:00\",\n      \"title\": \"\u4e00\u7ea7\u6807\u9898\u540d\u79f0\",\n      \"sub_points\": [\n        {\n          \"timestamp\": \"00:18\",\n          \"content\": \"\u4e8c\u7ea7\u8be6\u7ec6\u8981\u70b9 1\"\n        },\n        {\n          \"timestamp\": \"01:54\",\n          \"content\": \"\u4e8c\u7ea7\u8be6\u7ec6\u8981\u70b9 2\"\n        }\n      ]\n    },\n    {\n      \"timestamp\": \"06:48\",\n      \"title\": \"\u4e00\u7ea7\u6807\u9898\u540d\u79f0\",\n      \"sub_points\": [\n        {\n          \"timestamp\": \"07:35\",\n          \"content\": \"\u4e8c\u7ea7\u8be6\u7ec6\u8981\u70b9 1\"\n        },\n        {\n          \"timestamp\": \"08:42\",\n          \"content\": \"\u4e8c\u7ea7\u8be6\u7ec6\u8981\u70b9 2\"\n        }\n      ]\n    }\n  ]\n}"
      },
      "type": "@n8n/n8n-nodes-langchain.outputParserStructured",
      "typeVersion": 1.3,
      "position": [
        1904,
        80
      ],
      "id": "2bf84f2a-2d70-481b-805d-dd6fd16e1f64",
      "name": "Structured Output Parser"
    },
    {
      "parameters": {
        "resource": "databasePage",
        "databaseId": {
          "__rl": true,
          "value": "2ee629a6-152d-809d-963e-db8a25c99189",
          "mode": "list",
          "cachedResultName": "\u89c6\u9891\u6536\u85cf",
          "cachedResultUrl": "https://www.notion.so/2ee629a6152d809d963edb8a25c99189"
        },
        "title": "={{ $('Loop Over Items').item.json.videoname }}",
        "propertiesUi": {
          "propertyValues": [
            {
              "key": "\u6807\u9898|title",
              "title": "={{ $('Loop Over Items').item.json.videoname }}"
            },
            {
              "key": "\u6458\u8981|rich_text",
              "textContent": "={{ $json.output.summary }}"
            },
            {
              "key": "\u6765\u6e90|select",
              "selectValue": "YouTube"
            },
            {
              "key": "\u7f51\u5740|url",
              "urlValue": "={{ $('Loop Over Items').item.json.url }}"
            },
            {
              "key": "Tag\u6807\u7b7e|multi_select",
              "multiSelectValue": "={{ $json.output.tags }}"
            }
          ]
        },
        "options": {}
      },
      "type": "n8n-nodes-base.notion",
      "typeVersion": 2.2,
      "position": [
        2128,
        -352
      ],
      "id": "25713bcb-9d44-4274-87c4-3925291d4dfe",
      "name": "Create a database page",
      "credentials": {
        "notionApi": {
          "name": "<your credential>"
        }
      }
    },
    {
      "parameters": {
        "method": "PATCH",
        "url": "=https://api.notion.com/v1/blocks/{{ $json.id }}/children",
        "authentication": "predefinedCredentialType",
        "nodeCredentialType": "notionApi",
        "sendHeaders": true,
        "headerParameters": {
          "parameters": [
            {
              "name": "Content-Type",
              "value": "application/json"
            }
          ]
        },
        "sendBody": true,
        "specifyBody": "json",
        "jsonBody": "={\n  \"children\": [\n    {\n      \"object\": \"block\",\n      \"type\": \"video\",\n      \"video\": {\n        \"type\": \"external\",\n        \"external\": {\n          \"url\": \"{{ $('Loop Over Items').item.json.url }}\"\n        }\n      }\n    }\n  ]\n} ",
        "options": {}
      },
      "type": "n8n-nodes-base.httpRequest",
      "typeVersion": 4.3,
      "position": [
        2352,
        -352
      ],
      "id": "8cb98ecb-3fca-448a-8224-1426bda6a609",
      "name": "HTTP Request1",
      "credentials": {
        "notionApi": {
          "name": "<your credential>"
        }
      }
    },
    {
      "parameters": {
        "assignments": {
          "assignments": [
            {
              "id": "357c5018-717c-4518-aac9-bd74d992bdb4",
              "name": "time_line",
              "value": "={{ $('AI Agent').item.json.output.highlights }}",
              "type": "array"
            }
          ]
        },
        "options": {}
      },
      "type": "n8n-nodes-base.set",
      "typeVersion": 3.4,
      "position": [
        2880,
        -352
      ],
      "id": "a41ec582-d312-4123-b2b6-7d07e342df16",
      "name": "Edit Fields1"
    },
    {
      "parameters": {
        "fieldToSplitOut": "time_line",
        "include": "allOtherFields",
        "options": {}
      },
      "type": "n8n-nodes-base.splitOut",
      "typeVersion": 1,
      "position": [
        3120,
        -352
      ],
      "id": "98825180-ba72-41ca-a73f-e8aa62e2abe0",
      "name": "Split Out"
    },
    {
      "parameters": {
        "resource": "block",
        "blockId": {
          "__rl": true,
          "value": "={{ $('Create a database page').item.json.url }}",
          "mode": "url"
        },
        "blockUi": {
          "blockValues": [
            {
              "type": "heading_3",
              "textContent": "={{ $json.time_line.timestamp }} {{ $json.time_line.title }}"
            },
            {
              "textContent": "={{ $json.time_line.sub_points.map(item => `- ${item.timestamp} ${item.content}`).join('\\n') }}"
            }
          ]
        }
      },
      "type": "n8n-nodes-base.notion",
      "typeVersion": 2.2,
      "position": [
        3376,
        -352
      ],
      "id": "61969a11-2fc2-40e2-853a-81794877127a",
      "name": "Append a block",
      "credentials": {
        "notionApi": {
          "name": "<your credential>"
        }
      }
    },
    {
      "parameters": {
        "resource": "block",
        "blockId": {
          "__rl": true,
          "value": "={{ $('Create a database page').item.json.url }}",
          "mode": "url"
        },
        "blockUi": {
          "blockValues": [
            {
              "textContent": "={{ $('AI Agent').item.json.output.summary }}"
            },
            {
              "type": "heading_2",
              "textContent": "\u5185\u5bb9\u65f6\u95f4\u8f74\uff1a"
            }
          ]
        }
      },
      "type": "n8n-nodes-base.notion",
      "typeVersion": 2.2,
      "position": [
        2608,
        -352
      ],
      "id": "25ec4ed3-9f40-41f4-a291-9182fde7a21a",
      "name": "Append a block1",
      "credentials": {
        "notionApi": {
          "name": "<your credential>"
        }
      }
    },
    {
      "parameters": {
        "jsCode": "// \u83b7\u53d6\u8f93\u5165\u6570\u636e\nconst videoName = $('Loop Over Items').first().json.videoname;\nconst url = $('Loop Over Items').first().json.url;\nconst data = $input.first().json.output;\nconst now = new Date();\n\n// \u683c\u5f0f\u5316\u65f6\u95f4\u4e3a\u4e0a\u6d77\u65f6\u533a YYYY-MM-DD HH:mm\nconst formatDateTime = (date) => {\n  // \u8f6c\u6362\u4e3a\u4e0a\u6d77\u65f6\u533a (UTC+8)\n  const shanghaiTime = new Date(date.toLocaleString('en-US', { timeZone: 'Asia/Shanghai' }));\n  \n  const year = shanghaiTime.getFullYear();\n  const month = String(shanghaiTime.getMonth() + 1).padStart(2, '0');\n  const day = String(shanghaiTime.getDate()).padStart(2, '0');\n  const hours = String(shanghaiTime.getHours()).padStart(2, '0');\n  const minutes = String(shanghaiTime.getMinutes()).padStart(2, '0');\n  return `${year}-${month}-${day} ${hours}:${minutes}`;\n};\n\n// \u63d0\u53d6\u89c6\u9891ID\uff08\u4eceYouTube URL\u4e2d\uff09\nconst getVideoId = (url) => {\n  const match = url.match(/(?:v=|\\/)([\\w-]{11})/);\n  return match ? match[1] : '';\n};\n\n// \u751f\u6210\u6587\u4ef6\u540d\uff08\u4f7f\u7528\u89c6\u9891\u6807\u9898\uff0c\u5904\u7406\u7279\u6b8a\u5b57\u7b26\u548c\u6807\u7b7e\uff09\nconst generateFileName = (title) => {\n  // \u79fb\u9664 #tag \u6807\u7b7e\n  let cleanTitle = title.replace(/#\\S+/g, '').trim();\n  \n  // \u79fb\u9664\u6216\u66ff\u6362\u6587\u4ef6\u540d\u4e2d\u4e0d\u5141\u8bb8\u7684\u7279\u6b8a\u5b57\u7b26\n  const sanitizedTitle = cleanTitle\n    .replace(/[<>:\"/\\\\|?*]/g, '') // \u79fb\u9664Windows\u4e0d\u5141\u8bb8\u7684\u5b57\u7b26\n    .replace(/\\s+/g, '_')          // \u7a7a\u683c\u66ff\u6362\u4e3a\u4e0b\u5212\u7ebf\n    .substring(0, 100);            // \u9650\u5236\u957f\u5ea6\u907f\u514d\u6587\u4ef6\u540d\u8fc7\u957f\n  \n  return `${sanitizedTitle}.md`;\n};\n\n// \u751f\u6210YAML\u524d\u7f6e\u6570\u636e\uff08\u5305\u542btags\u6570\u7ec4\uff09\nconst yamlFrontMatter = `---\nurl: ${url}\ntags: ${data.tags.join(', ')}\n\u6765\u6e90: YouTube\n\u6dfb\u52a0\u65f6\u95f4: ${formatDateTime(now)}\n---`;\n\n// \u751f\u6210\u89c6\u9891\u5d4c\u5165\uff08\u4f7f\u7528videoName\u4f5c\u4e3a\u6807\u9898\uff09\nconst videoEmbed = `![${videoName}](${url})`;\n\n// \u76f4\u63a5\u8f93\u51fa\u6458\u8981\u5185\u5bb9\uff0c\u4e0d\u5e26\"\u6458\u8981\"\u6807\u9898\nconst summarySection = `${data.summary}`;\n\n// \u751f\u6210\u9ad8\u4eae/\u8981\u70b9\u90e8\u5206\nlet highlightsSection = '## \u8981\u70b9\\n\\n';\n\ndata.highlights.forEach((highlight) => {\n  // \u683c\u5f0f\u5316\u4e00\u7ea7\u6807\u9898\u7684\u65f6\u95f4\u6233\n  const titleTimeParts = highlight.timestamp.split(':');\n  const titleHours = parseInt(titleTimeParts[0]);\n  const titleMinutes = parseInt(titleTimeParts[1]);\n  const titleSeconds = parseFloat(titleTimeParts[2]);\n  const titleTotalSeconds = titleHours * 3600 + titleMinutes * 60 + titleSeconds;\n  const titleDisplayMinutes = String(Math.floor(titleTotalSeconds / 60)).padStart(2, '0');\n  const titleDisplaySeconds = String(Math.floor(titleTotalSeconds % 60)).padStart(2, '0');\n  const titleDisplayTime = `${titleDisplayMinutes}:${titleDisplaySeconds}`;\n  \n  // \u83b7\u53d6\u89c6\u9891ID\n  const videoId = getVideoId(url);\n  \n  // \u751f\u6210\u4e00\u7ea7\u6807\u9898\u7684\u65f6\u95f4\u94fe\u63a5\n  const titleTimeLink = `https://www.youtube.com/watch?v=${videoId}&t=${Math.floor(titleTotalSeconds)}#t=${highlight.timestamp}`;\n  \n  // \u4e00\u7ea7\u6807\u9898\uff08\u65f6\u95f4\u94fe\u63a5\u5728\u5916\u9762\uff0c\u6807\u9898\u52a0\u7c97\uff09\n  highlightsSection += `[${titleDisplayTime}](${titleTimeLink}) **${highlight.title}**\\n\\n`;\n  \n  // \u4e8c\u7ea7\u5185\u5bb9\uff08\u65e0\u5e8f\u5217\u8868\uff09\n  if (highlight.sub_points && highlight.sub_points.length > 0) {\n    highlight.sub_points.forEach((point) => {\n      // \u5c06\u65f6\u95f4\u6233\u8f6c\u6362\u4e3a\u79d2\u6570\n      const timeParts = point.timestamp.split(':');\n      const hours = parseInt(timeParts[0]);\n      const minutes = parseInt(timeParts[1]);\n      const seconds = parseFloat(timeParts[2]);\n      const totalSeconds = hours * 3600 + minutes * 60 + seconds;\n      \n      // \u683c\u5f0f\u5316\u65f6\u95f4\u4e3a MM:SS\n      const displayMinutes = String(Math.floor(totalSeconds / 60)).padStart(2, '0');\n      const displaySeconds = String(Math.floor(totalSeconds % 60)).padStart(2, '0');\n      const displayTime = `${displayMinutes}:${displaySeconds}`;\n      \n      // \u751f\u6210\u5e26\u65f6\u95f4\u6233\u94fe\u63a5\u7684\u5217\u8868\u9879\n      const timeLink = `https://www.youtube.com/watch?v=${videoId}&t=${Math.floor(totalSeconds)}#t=${point.timestamp}`;\n      highlightsSection += `- [${displayTime}](${timeLink}) ${point.content}\\n`;\n    });\n    highlightsSection += '\\n';\n  }\n});\n\n// \u7ec4\u5408\u5b8c\u6574\u7684markdown\u5185\u5bb9\nconst markdownContent = `${yamlFrontMatter}\n\n${videoEmbed}\n\n${summarySection}\n\n${highlightsSection}`;\n\n// \u8fd4\u56de\u7b26\u5408n8n\u89c4\u8303\u7684\u5bf9\u8c61\u6570\u7ec4\uff0c\u5305\u542b\u6587\u4ef6\u76f8\u5173\u4fe1\u606f\nreturn [\n  {\n    json: {\n      fileContent: markdownContent,\n      fileName: generateFileName(videoName),\n      mimeType: 'text/markdown',\n      title: videoName\n    }\n  }\n];"
      },
      "type": "n8n-nodes-base.code",
      "typeVersion": 2,
      "position": [
        2112,
        0
      ],
      "id": "830dcd8f-f978-4c70-9b1b-fd82aafe6324",
      "name": "Code in JavaScript"
    },
    {
      "parameters": {
        "operation": "toText",
        "sourceProperty": "fileContent",
        "options": {
          "fileName": "={{ $json.fileName }}"
        }
      },
      "type": "n8n-nodes-base.convertToFile",
      "typeVersion": 1.1,
      "position": [
        2320,
        0
      ],
      "id": "9f16ec9c-fd12-4727-bbd3-749548d7c120",
      "name": "Convert to File"
    },
    {
      "parameters": {
        "operation": "write",
        "fileName": "=./n8ndata/downloads/demo/{{ $('Code in JavaScript').item.json.fileName }}",
        "options": {}
      },
      "type": "n8n-nodes-base.readWriteFile",
      "typeVersion": 1,
      "position": [
        2528,
        0
      ],
      "id": "1cf8f67d-1956-491a-9219-61dac493c134",
      "name": "Read/Write Files from Disk1"
    },
    {
      "parameters": {
        "conditions": {
          "options": {
            "caseSensitive": true,
            "leftValue": "",
            "typeValidation": "strict",
            "version": 3
          },
          "conditions": [
            {
              "id": "aebcfddb-1fa4-49a0-8855-9f49375ee54a",
              "leftValue": "={{ $json.hasRunningTasks }}",
              "rightValue": false,
              "operator": {
                "type": "boolean",
                "operation": "equals"
              }
            }
          ],
          "combinator": "and"
        },
        "options": {}
      },
      "type": "n8n-nodes-base.if",
      "typeVersion": 2.3,
      "position": [
        1024,
        -128
      ],
      "id": "b28a4d34-d09d-4937-84b2-af66b58bddf4",
      "name": "If"
    },
    {
      "parameters": {
        "url": "http://host.docker.internal:8081/history",
        "options": {}
      },
      "type": "n8n-nodes-base.httpRequest",
      "typeVersion": 4.3,
      "position": [
        592,
        -192
      ],
      "id": "f935eed6-0e0d-4536-8bd8-93fbef90e6e5",
      "name": "HTTP Request4"
    },
    {
      "parameters": {
        "jsCode": "// \u4ece HTTP Request \u8282\u70b9\u83b7\u53d6\u6570\u636e\nconst input = $input.first().json;\n\ntry {\n  // \u89e3\u6790 JSON \u5b57\u7b26\u4e32\n  const history = JSON.parse(input.data);\n  \n  // ========== 1. \u68c0\u67e5\u4efb\u52a1\u8fdb\u5ea6 ==========\n  const queueCount = history.queue?.length || 0;\n  const pendingCount = history.pending?.length || 0;\n  const hasRunningTasks = queueCount > 0 || pendingCount > 0;\n  \n  if (hasRunningTasks) {\n    return [{\n      json: {\n        hasRunningTasks: true,\n        status: '\u4efb\u52a1\u8fd8\u5728\u8fdb\u884c\u4e2d',\n        queueCount: queueCount,\n        pendingCount: pendingCount,\n        message: `\u8fd8\u6709 ${queueCount + pendingCount} \u4e2a\u4efb\u52a1\u672a\u5b8c\u6210\uff08\u961f\u5217\u4e2d: ${queueCount}, \u5f85\u5904\u7406: ${pendingCount}\uff09`\n      }\n    }];\n  }\n  \n  // ========== 2. \u627e\u5230\u6700\u65b0\u5b8c\u6210\u7684\u4efb\u52a1 ==========\n  const doneTasks = history.done || [];\n  \n  if (doneTasks.length === 0) {\n    return [{\n      json: {\n        hasRunningTasks: false,\n        status: '\u6ca1\u6709\u5df2\u5b8c\u6210\u7684\u4efb\u52a1',\n        error: true,\n        message: '\u6ca1\u6709\u627e\u5230\u4efb\u4f55\u5df2\u5b8c\u6210\u7684\u4efb\u52a1'\n      }\n    }];\n  }\n  \n  // \u6309\u65f6\u95f4\u6233\u964d\u5e8f\u6392\u5e8f\uff0c\u53d6\u7b2c\u4e00\u4e2a\uff08\u6700\u65b0\u7684\uff09\n  const latestTask = doneTasks.reduce((latest, current) => {\n    return (current.timestamp > latest.timestamp) ? current : latest;\n  }, doneTasks[0]);\n  \n  // ========== 3. \u68c0\u67e5\u5b57\u5e55\u6587\u4ef6\uff08\u4e25\u683c\u6392\u9664\u5f39\u5e55\uff09==========\n  const requestedSubtitles = latestTask.entry?.requested_subtitles || {};\n  \n  // \u83b7\u53d6\u6240\u6709\u5b57\u5e55\u8bed\u8a00\uff0c\u4e25\u683c\u6392\u9664 danmaku\n  const subtitleLanguages = Object.keys(requestedSubtitles).filter(\n    lang => lang !== 'danmaku'\n  );\n  \n  const hasSubtitles = subtitleLanguages.length > 0;\n  const hasDanmaku = requestedSubtitles.hasOwnProperty('danmaku');\n  \n  // ========== 4. \u8fd4\u56de\u5b8c\u6574\u7ed3\u679c ==========\n  return [{\n    json: {\n      // \u4efb\u52a1\u8fdb\u5ea6\n      hasRunningTasks: false,\n      status: '\u6240\u6709\u4efb\u52a1\u5df2\u5b8c\u6210',\n      totalCompleted: doneTasks.length,\n      \n      // \u6700\u65b0\u4efb\u52a1\u4fe1\u606f\n      latestTask: {\n        id: latestTask.id,\n        title: latestTask.title,\n        url: latestTask.url,\n        timestamp: latestTask.timestamp,\n        timestampReadable: new Date(latestTask.timestamp / 1000000).toLocaleString('zh-CN'),\n        size: latestTask.size,\n        sizeMB: (latestTask.size / (1024 * 1024)).toFixed(2),\n        status: latestTask.status\n      },\n      \n      // \u5b57\u5e55\u68c0\u6d4b\u7ed3\u679c\n      subtitleCheck: {\n        hasSubtitles: hasSubtitles,\n        hasDanmaku: hasDanmaku,\n        subtitleLanguages: subtitleLanguages,\n        subtitleCount: subtitleLanguages.length,\n        result: hasSubtitles \n          ? `\u2705 \u5305\u542b\u5b57\u5e55\u6587\u4ef6\uff1a${subtitleLanguages.join(', ')}`\n          : (hasDanmaku ? '\u274c \u4ec5\u6709\u5f39\u5e55\uff0c\u65e0\u5b57\u5e55\u6587\u4ef6' : '\u274c \u65e0\u5b57\u5e55\u3001\u65e0\u5f39\u5e55')\n      },\n      \n      // \u8be6\u7ec6\u5b57\u5e55\u6587\u4ef6\u4fe1\u606f\n      subtitleFiles: hasSubtitles ? subtitleLanguages.map(lang => ({\n        language: lang,\n        url: requestedSubtitles[lang].url,\n        extension: requestedSubtitles[lang].ext\n      })) : [],\n      \n      // \u5f39\u5e55\u4fe1\u606f\uff08\u5982\u679c\u6709\uff09\n      danmaku: hasDanmaku ? {\n        url: requestedSubtitles.danmaku.url,\n        extension: requestedSubtitles.danmaku.ext\n      } : null,\n      \n      // \u603b\u7ed3\u6d88\u606f\n      message: hasSubtitles \n        ? `\u2705 \u6700\u65b0\u4efb\u52a1\u5df2\u5b8c\u6210\uff0c\u5305\u542b ${subtitleLanguages.length} \u4e2a\u5b57\u5e55\u6587\u4ef6`\n        : '\u26a0\ufe0f \u6700\u65b0\u4efb\u52a1\u5df2\u5b8c\u6210\uff0c\u4f46\u672a\u5305\u542b\u5b57\u5e55\u6587\u4ef6'\n    }\n  }];\n  \n} catch (error) {\n  return [{\n    json: {\n      error: true,\n      errorMessage: error.message,\n      errorStack: error.stack\n    }\n  }];\n}\n"
      },
      "type": "n8n-nodes-base.code",
      "typeVersion": 2,
      "position": [
        816,
        -176
      ],
      "id": "0033c96f-984b-4d7e-909f-2f7a91e2717a",
      "name": "Code in JavaScript1"
    },
    {
      "parameters": {
        "amount": 1
      },
      "type": "n8n-nodes-base.wait",
      "typeVersion": 1.1,
      "position": [
        384,
        -160
      ],
      "id": "ecadcfe9-0b97-4b33-ac23-eb0903895d6a",
      "name": "Wait"
    }
  ],
  "connections": {
    "When clicking \u2018Execute workflow\u2019": {
      "main": [
        [
          {
            "node": "Get many playlist items",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "Get many playlist items": {
      "main": [
        [
          {
            "node": "Edit Fields",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "Edit Fields": {
      "main": [
        [
          {
            "node": "Loop Over Items",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "Loop Over Items": {
      "main": [
        [],
        [
          {
            "node": "HTTP Request",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "HTTP Request": {
      "main": [
        [
          {
            "node": "Wait",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "Read/Write Files from Disk": {
      "main": [
        [
          {
            "node": "Extract from File",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "Extract from File": {
      "main": [
        [
          {
            "node": "AI Agent",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "DeepSeek Chat Model": {
      "ai_languageModel": [
        [
          {
            "node": "AI Agent",
            "type": "ai_languageModel",
            "index": 0
          }
        ]
      ]
    },
    "Structured Output Parser": {
      "ai_outputParser": [
        [
          {
            "node": "AI Agent",
            "type": "ai_outputParser",
            "index": 0
          }
        ]
      ]
    },
    "AI Agent": {
      "main": [
        [
          {
            "node": "Code in JavaScript",
            "type": "main",
            "index": 0
          },
          {
            "node": "Create a database page",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "Create a database page": {
      "main": [
        [
          {
            "node": "HTTP Request1",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "HTTP Request1": {
      "main": [
        [
          {
            "node": "Append a block1",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "Edit Fields1": {
      "main": [
        [
          {
            "node": "Split Out",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "Split Out": {
      "main": [
        [
          {
            "node": "Append a block",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "Append a block1": {
      "main": [
        [
          {
            "node": "Edit Fields1",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "Code in JavaScript": {
      "main": [
        [
          {
            "node": "Convert to File",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "Convert to File": {
      "main": [
        [
          {
            "node": "Read/Write Files from Disk1",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "If": {
      "main": [
        [
          {
            "node": "Read/Write Files from Disk",
            "type": "main",
            "index": 0
          }
        ],
        [
          {
            "node": "Wait",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "HTTP Request4": {
      "main": [
        [
          {
            "node": "Code in JavaScript1",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "Code in JavaScript1": {
      "main": [
        [
          {
            "node": "If",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "Wait": {
      "main": [
        [
          {
            "node": "HTTP Request4",
            "type": "main",
            "index": 0
          }
        ]
      ]
    }
  },
  "active": false,
  "settings": {
    "executionOrder": "v1"
  },
  "versionId": "08b246e7-a2b1-4d2d-aab3-7c1fc3651438",
  "meta": {
    "templateCredsSetupCompleted": true
  },
  "id": "rBgHbHMlrO0J0v9k",
  "tags": []
}