{"id":"Gd4MsAZGnSGfBwaw","meta":{"instanceId":"workflow-cfc36d28","versionId":"1.0.0","createdAt":"2025-09-29T07:07:54.059612","updatedAt":"2025-09-29T07:07:54.059620","owner":"n8n-user","license":"MIT","category":"automation","status":"active","priority":"high","environment":"production"},"name":"Telegram channel to Readeck & Hoarder","nodes":[{"id":"6e50d52e-8b9e-4c92-82a1-af366c7a2ccf","name":"Schedule Trigger","type":"n8n-nodes-base.scheduleTrigger","position":[-440,-700],"parameters":{"rule":{"interval":[{"field":"hours"}]}},"typeVersion":1.2,"notes":"This scheduleTrigger node performs automated tasks as part of the workflow."},{"id":"bb7430a2-a7b7-47f2-9ba3-a3e43c8da004","name":"Split Out","type":"n8n-nodes-base.splitOut","position":[-100,-120],"parameters":{"options":{},"fieldToSplitOut":"bookmarks"},"typeVersion":1,"notes":"This splitOut node performs automated tasks as part of the workflow."},{"id":"922aeb0b-29b1-46c6-9b18-76c02eca5a9e","name":"Sticky Note","type":"n8n-nodes-base.stickyNote","position":[-460,-480],"parameters":{"width":1120,"height":220,"content":"## Readeck"},"typeVersion":1,"notes":"This stickyNote node performs automated tasks as part of the workflow."},{"id":"64d4ca0b-2c16-441e-9461-5707be877132","name":"Sticky Note1","type":"n8n-nodes-base.stickyNote","position":[-220,-740],"parameters":{"width":480,"height":200,"content":"## Telegram"},"typeVersion":1,"notes":"This stickyNote node performs automated tasks as part of the workflow."},{"id":"13ae24ec-ac11-470a-bad4-76403861f632","name":"Sticky Note2","type":"n8n-nodes-base.stickyNote","position":[-460,-180],"parameters":{"width":1120,"height":220,"content":"## Hoarder"},"typeVersion":1,"notes":"This stickyNote node performs automated tasks as part of the workflow."},{"id":"c606f434-d37b-4406-997a-1e7f17319281","name":"not_saved_links_hd","type":"n8n-nodes-base.code","position":[260,-120],"parameters":{"jsCode":"const linksCanalItems = $('channel_links_tg').all();\nconst saved_links_items = $('saved_links_hd').all();\n\n// Extract links\nconst saved_links = new Set(\n    saved_links_items.map(item => String(item.json.content.url))\n);\n\n// Filter\nconst filteredLinks = linksCanalItems.filter(item => {\n    return !saved_links.has(String(item.json.url));\n});\n\nreturn filteredLinks;\n\n\n\n\n\n\n\n\n"},"typeVersion":2,"notes":"This code node performs automated tasks as part of the workflow."},{"id":"d0f61836-798c-4835-ae8f-8f184b6720ed","name":"not_saved_links_rd","type":"n8n-nodes-base.code","position":[260,-420],"parameters":{"jsCode":"const linksCanalItems = $('channel_links_tg').all();\nconst saved_links_items = $('saved_links_rd').all();\n\n// Extract urls\nconst saved_urls = new Set(\n    saved_links_items.map(item => String(item.json.url))\n);\n\n// Filter\nconst filteredLinks = linksCanalItems.filter(item => {\n    return !saved_urls.has(String(item.json.url));\n});\n\nreturn filteredLinks;\n\n\n\n\n\n\n\n\n"},"typeVersion":2,"notes":"This code node performs automated tasks as part of the workflow."},{"id":"f33349a7-361a-4b0f-844b-1ca5ded2aeab","name":"saved_links_rd","type":"n8n-nodes-base.set","position":[80,-420],"parameters":{"options":{},"assignments":{"assignments":[{"id":"8c6f3806-0fb8-4c76-a0bc-19b588717430","name":"id","type":"string","value":"={{ $json.id }}"},{"id":"ef41cba3-2844-479c-9467-6b94ae24c98b","name":"url","type":"string","value":"={{ $json.url }}"}]}},"typeVersion":3.4,"notes":"This set node performs automated tasks as part of the workflow."},{"id":"63d45b19-e878-418e-8eb5-c16b50af9669","name":"save_link_rd","type":"n8n-nodes-base.httpRequest","position":[460,-420],"parameters":{"url":"{{ $env.BASE_URL }}","method":"POST","options":{},"sendBody":true,"sendHeaders":true,"bodyParameters":{"parameters":[{"name":"url","value":"={{ $json.url }}"}]},"headerParameters":{"parameters":[{"name":"accept","value":"application/json"},{"name":"authorization","value":"=Bearer {{$env.READECK_API_KEY}}"}]}},"typeVersion":4.2,"notes":"This httpRequest node performs automated tasks as part of the workflow."},{"id":"9416a858-1a25-4c3e-a49e-153118c268a7","name":"save_link_hd","type":"n8n-nodes-base.httpRequest","position":[460,-120],"parameters":{"url":"{{ $env.BASE_URL }}","method":"POST","options":{},"sendBody":true,"sendHeaders":true,"bodyParameters":{"parameters":[{"name":"type","value":"link"},{"name":"url","value":"={{ $json.url }}"}]},"headerParameters":{"parameters":[{"name":"Authorization","value":"=Bearer {{$env.HOARDER_API_KEY}}"}]}},"typeVersion":4.2,"notes":"This httpRequest node performs automated tasks as part of the workflow."},{"id":"13693467-cd75-4774-9072-832419606ab2","name":"get_links_rd","type":"n8n-nodes-base.httpRequest","position":[-280,-420],"parameters":{"url":"{{ $env.BASE_URL }}","options":{},"sendHeaders":true,"headerParameters":{"parameters":[{"name":"accept","value":"application/json"},{"name":"authorization","value":"=Bearer {{$env.READECK_API_KEY}}"}]}},"typeVersion":4.2,"alwaysOutputData":true,"notes":"This httpRequest node performs automated tasks as part of the workflow."},{"id":"e4ed315d-d065-425a-b30d-eca1509670cc","name":"get_links_hd","type":"n8n-nodes-base.httpRequest","position":[-280,-120],"parameters":{"url":"{{ $env.BASE_URL }}","options":{},"sendHeaders":true,"headerParameters":{"parameters":[{"name":"Authorization","value":"=Bearer {{$env.HOARDER_API_KEY}}"}]}},"typeVersion":4.2,"alwaysOutputData":true,"notes":"This httpRequest node performs automated tasks as part of the workflow."},{"id":"f54d9a4d-f00b-41bf-988a-8920d0046424","name":"saved_links_hd","type":"n8n-nodes-base.set","position":[80,-120],"parameters":{"options":{},"assignments":{"assignments":[{"id":"b07ce8e5-0b67-4c9c-831a-7a52f92f5744","name":"content.url","type":"string","value":"={{ $json.content.url }}"}]}},"typeVersion":3.4,"notes":"This set node performs automated tasks as part of the workflow."},{"id":"d4e83b9d-5988-46f4-b853-86daec274dba","name":"channel_links_tg","type":"n8n-nodes-base.code","position":[120,-700],"parameters":{"jsCode":"// Define the chatId from the environment variable\nconst chatId = parseInt($env.TG_SHERLINK_ID, 10);\n// Access the \"result\" field from the previous node's output\nconst updates = $node[\"channel_items_tg\"].json[\"result\"];\n// Check if \"result\" is an array\nif (!Array.isArray(updates)) {\n  return []; // Return empty if there are no messages\n}\n// Filter and process the messages\nconst filteredUpdates = updates\n  .map(update => {\n    // Ensure message from the specified channel\n    if (update.channel_post && update.channel_post.chat && update.channel_post.chat.id === chatId) {\n      return {\n        id: update.channel_post.message_id,\n        url: update.channel_post.text\n      };\n    }\n    return null;\n  })\n  \n  .filter(item => item !== null) // Filter nulls\n  .filter(item => {\n    // Filter only with hyperlink in text\n    const text = item.url || \"\"; // Defined text\n    return /https?:\\/\\/[^\\s]+/.test(text); // hyperlink\n  });\n// Convert each array element into an individual item\nreturn filteredUpdates.map(update => ({ json: update }));\n"},"typeVersion":2,"alwaysOutputData":false,"notes":"This code node performs automated tasks as part of the workflow."},{"id":"ca306aed-e682-4c35-a257-3b65bcfde895","name":"channel_items_tg","type":"n8n-nodes-base.httpRequest","position":[-80,-700],"parameters":{"url":"{{ $env.BASE_URL }}","options":{},"sendQuery":true,"queryParameters":{"parameters":[{}]}},"typeVersion":4.2,"notes":"This httpRequest node performs automated tasks as part of the workflow."}],"active":true,"settings":{"callerPolicy":"workflowsFromSameOwner","executionOrder":"v1","saveManualExecutions":true,"errorWorkflow":null,"timezone":"UTC","executionTimeout":3600,"maxExecutions":1000,"retryOnFail":true,"retryCount":3,"retryDelay":1000},"versionId":"85dd3731-0772-4b8b-b828-ae6a034d5419","connections":{"save_link_rd":{"main":[[],[],[],[],[]]},"save_link_hd":{"main":[[],[],[],[],[]]},"get_links_rd":{"main":[[],[],[],[],[]]},"get_links_hd":{"main":[[],[],[],[],[]]},"channel_items_tg":{"main":[[],[],[],[],[]]}},"description":"Automated workflow: Telegram channel to Readeck & Hoarder. This workflow integrates 7 different services: stickyNote, httpRequest, code, scheduleTrigger, splitOut. It contains 25 nodes and follows best practices for error handling and security.","notes":"Excellent quality workflow: Telegram channel to Readeck & Hoarder. This workflow has been optimized for production use with comprehensive error handling, security, and documentation."}