{ "id": "sJhcphTjZcqASzwF", "name": "Audiobook Torrents - Main Orchestrator", "nodes": [ { "parameters": {}, "id": "manual-trigger", "name": "When clicking 'Execute workflow'", "type": "n8n-nodes-base.manualTrigger", "typeVersion": 1, "position": [ 256, 256 ] }, { "parameters": { "rule": { "interval": [ { "field": "minutes" } ] } }, "id": "schedule-trigger", "name": "Every 5 Minutes", "type": "n8n-nodes-base.scheduleTrigger", "typeVersion": 1.2, "position": [ 256, 448 ] }, { "parameters": { "url": "https://nyaa.si/?page=rss&q=%5BAudiobook%5D&c=3_1&f=0", "options": {} }, "id": "fetch-rss", "name": "Fetch RSS from Nyaa", "type": "n8n-nodes-base.httpRequest", "typeVersion": 4.2, "position": [ 480, 352 ] }, { "parameters": { "options": { "trim": true } }, "id": "parse-xml", "name": "Parse XML", "type": "n8n-nodes-base.xml", "typeVersion": 1, "position": [ 704, 352 ] }, { "parameters": { "fieldToSplitOut": "rss.channel.item", "options": {} }, "id": "split-items", "name": "Split Feed Items", "type": "n8n-nodes-base.splitOut", "typeVersion": 1, "position": [ 928, 352 ] }, { "parameters": { "jsCode": "// Process all input items and return them\nreturn $input.all().map(item => ({\n json: {\n info_hash: item.json['nyaa:infoHash'],\n title: item.json.title,\n link: item.json.link,\n view_link: item.json.guid._ || item.json.guid,\n pub_date: item.json.pubDate,\n seeders: parseInt(item.json['nyaa:seeders']) || 0,\n size: item.json['nyaa:size']\n }\n}));" }, "id": "extract-torrent-data", "name": "Extract Torrent Data", "type": "n8n-nodes-base.code", "typeVersion": 2, "position": [ 1152, 352 ] }, { "parameters": { "workflowId": { "__rl": true, "mode": "id", "value": "t2BEdqrbF474ul3B" }, "workflowInputs": { "mappingMode": "defineBelow", "value": {}, "matchingColumns": [], "schema": [], "attemptToConvertTypes": false, "convertFieldsToString": true }, "options": {} }, "id": "call-tracker-crossref", "name": "Execute Tracker Cross-Reference", "type": "n8n-nodes-base.executeWorkflow", "typeVersion": 1.3, "position": [ 1376, 352 ], "disabled": false }, { "parameters": { "mergeByFields": { "values": [ { "field1": "info_hash", "field2": "info_hash" } ] }, "resolve": "mix", "exceptWhenMix": "last_processed,processing_workflow", "options": { "skipFields": "id,title,link,pub_date,seeders,size,discovered_at,created_at,updated_at,view_link,mam_torrent_id,mam_checked_at,download_status,download_path,download_size_bytes,downloaded_at,download_error,torrent_created,torrent_file_path,torrent_created_at,torrent_info_hash_verified,upload_status,uploaded_mam_id,uploaded_at,upload_notes,last_processed,processing_workflow,debug_stage,debug_count,debug_timestamp" } }, "id": "compare-datasets", "name": "Compare Datasets", "type": "n8n-nodes-base.compareDatasets", "typeVersion": 2.3, "position": [ 2048, 320 ] }, { "parameters": { "conditions": { "options": { "version": 2, "leftValue": "", "caseSensitive": true, "typeValidation": "strict" }, "conditions": [ { "leftValue": "={{ $json.seeders }}", "rightValue": 0, "operator": { "type": "number", "operation": "gt" }, "id": "condition-1762096826037-masiy0yzf" } ] }, "options": {} }, "id": "has-seeders", "name": "Has Seeders?", "type": "n8n-nodes-base.if", "typeVersion": 2.2, "position": [ 1600, 352 ] }, { "parameters": { "tableId": "nyaa_audiobooks", "dataToSend": "autoMapInputData", "inputsToIgnore": "view_link" }, "id": "insert-new-torrents", "name": "Insert New Torrents", "type": "n8n-nodes-base.supabase", "typeVersion": 1, "position": [ 2496, 208 ], "credentials": { "supabaseApi": { "id": "lWyf2ikOGHTTwnSU", "name": "Supabase account" } } }, { "parameters": { "operation": "update", "tableId": "nyaa_audiobooks", "filters": { "conditions": [ { "keyName": "info_hash", "condition": "eq", "keyValue": "={{ $json.info_hash }}" } ] }, "fieldsUi": { "fieldValues": [ { "fieldId": "mam_torrent_id", "fieldValue": "={{ $json.mam_torrent_id }}" }, { "fieldId": "mam_checked_at", "fieldValue": "={{ $json.mam_checked_at }}" }, { "fieldId": "last_processed", "fieldValue": "={{ $now.toISO() }}" }, { "fieldId": "processing_workflow", "fieldValue": "main-orchestrator" } ] } }, "id": "update-existing-mam", "name": "Update Existing with MAM Data", "type": "n8n-nodes-base.supabase", "typeVersion": 1, "position": [ 3168, 496 ], "credentials": { "supabaseApi": { "id": "lWyf2ikOGHTTwnSU", "name": "Supabase account" } } }, { "parameters": { "jsCode": "// Prepare data for notification router\nconst torrents = $input.all().map(item => item.json);\n\nreturn [{\n json: {\n torrent_count: torrents.length,\n torrents: torrents\n }\n}];" }, "id": "prepare-notification-data", "name": "Prepare Notification Data", "type": "n8n-nodes-base.code", "typeVersion": 2, "position": [ 2944, 256 ], "executeOnce": true }, { "parameters": { "workflowId": { "__rl": true, "mode": "id", "value": "kubWVFN16Jar4v4Q" }, "options": {} }, "id": "call-notification-router", "name": "Execute Notification Router", "type": "n8n-nodes-base.executeWorkflow", "typeVersion": 1.3, "position": [ 3168, 256 ] }, { "parameters": { "conditions": { "options": { "version": 2, "leftValue": "", "caseSensitive": true, "typeValidation": "strict", "combineOperation": "all" }, "conditions": [ { "leftValue": "={{ $json.needs_mam_update }}", "operator": { "type": "boolean", "operation": "isTrue" }, "id": "condition-1762110814452-nceww466w" } ] }, "options": {} }, "id": "7ea9bc8b-a092-472d-81f3-9aede474a784", "name": "Needs MAM Update (IF)", "type": "n8n-nodes-base.if", "typeVersion": 2.2, "position": [ 2944, 496 ] }, { "parameters": { "functionCode": "const data = { ...$json };\nconst hasMam = !!data.mam_torrent_id && String(data.mam_torrent_id).trim() !== '';\nconst lastProcessed = data.last_processed;\nconst notProcessed = !lastProcessed || String(lastProcessed).trim() === '';\nreturn {\n ...data,\n needs_mam_update: hasMam && notProcessed,\n};" }, "id": "2accc734-d3ab-421d-8769-79a74753d677", "name": "Flag Needs MAM Update", "type": "n8n-nodes-base.functionItem", "typeVersion": 1, "position": [ 2720, 496 ] }, { "parameters": { "functionCode": "const raw = { ...$json };\nconst hasStructuredDiff = raw.keys !== undefined || raw.same !== undefined || raw.different !== undefined;\nif (!hasStructuredDiff) {\n return {\n ...raw,\n compare_status: raw.compare_status ?? 'different',\n previous_mam_torrent_id: raw.previous_mam_torrent_id ?? null,\n previous_mam_checked_at: raw.previous_mam_checked_at ?? null,\n };\n}\nconst keys = raw.keys ?? {};\nconst same = raw.same ?? {};\nconst different = raw.different ?? {};\nconst toValue = (value) => {\n if (value && typeof value === 'object' && value.inputA !== undefined) {\n return value.inputA;\n }\n return value;\n};\nconst result = { ...same };\nfor (const [field, value] of Object.entries(different)) {\n result[field] = toValue(value);\n}\nif (keys.info_hash) {\n result.info_hash = keys.info_hash;\n}\nif (!result.info_hash && same.info_hash) {\n result.info_hash = same.info_hash;\n}\nconst mamTorrentId = toValue(different.mam_torrent_id);\nif (mamTorrentId !== undefined) {\n result.mam_torrent_id = mamTorrentId;\n}\nconst mamCheckedAt = toValue(different.mam_checked_at);\nif (mamCheckedAt !== undefined) {\n result.mam_checked_at = mamCheckedAt;\n}\nif (same.mam_checked_at && !result.mam_checked_at) {\n result.mam_checked_at = same.mam_checked_at;\n}\nresult.last_processed = same.last_processed ?? result.last_processed ?? null;\nresult.processing_workflow = same.processing_workflow ?? result.processing_workflow ?? null;\nresult.compare_status = 'different';\nresult.previous_mam_torrent_id = same.mam_torrent_id ?? null;\nresult.previous_mam_checked_at = same.mam_checked_at ?? null;\nreturn result;" }, "id": "d659029a-5a44-4d43-a11b-4dc033d927d3", "name": "Normalize Updated Torrents", "type": "n8n-nodes-base.functionItem", "typeVersion": 1, "position": [ 2496, 448 ] }, { "parameters": {}, "id": "5f2aeff8-f616-44c3-aaa1-d6266e1945a5", "name": "Collect Notification Items", "type": "n8n-nodes-base.merge", "typeVersion": 1, "position": [ 2720, 256 ] }, { "parameters": { "operation": "getAll", "tableId": "nyaa_audiobooks", "returnAll": true, "filterType": "none" }, "id": "get-db-rows", "name": "Get DB Rows for Deduplication", "type": "n8n-nodes-base.supabase", "typeVersion": 1, "position": [ 1824, 432 ], "executeOnce": true, "credentials": { "supabaseApi": { "id": "lWyf2ikOGHTTwnSU", "name": "Supabase account" } } }, { "parameters": { "conditions": { "options": { "version": 2, "leftValue": "", "caseSensitive": true, "typeValidation": "strict" }, "conditions": [ { "leftValue": "={{ $json.info_hash != \"\" }}", "rightValue": true, "operator": { "type": "boolean", "operation": "equals" }, "id": "condition-infohash-not-empty" } ], "combinator": "and" }, "options": {} }, "id": "52f493b9-66bc-48ac-8b1d-f301d12131ee", "name": "Has Info Hash Guard", "type": "n8n-nodes-base.if", "typeVersion": 2.2, "position": [ 2272, 208 ] } ], "connections": { "When clicking 'Execute workflow'": { "main": [ [ { "node": "Fetch RSS from Nyaa", "type": "main", "index": 0 } ] ] }, "Every 5 Minutes": { "main": [ [ { "node": "Fetch RSS from Nyaa", "type": "main", "index": 0 } ] ] }, "Fetch RSS from Nyaa": { "main": [ [ { "node": "Parse XML", "type": "main", "index": 0 } ] ] }, "Parse XML": { "main": [ [ { "node": "Split Feed Items", "type": "main", "index": 0 } ] ] }, "Split Feed Items": { "main": [ [ { "node": "Extract Torrent Data", "type": "main", "index": 0 } ] ] }, "Extract Torrent Data": { "main": [ [ { "node": "Execute Tracker Cross-Reference", "type": "main", "index": 0 }, { "node": "Has Seeders?", "type": "main", "index": 0 } ] ] }, "Has Seeders?": { "main": [ [ { "node": "Compare Datasets", "type": "main", "index": 0 }, { "node": "Get DB Rows for Deduplication", "type": "main", "index": 0 } ] ] }, "Compare Datasets": { "main": [ [ { "node": "Has Info Hash Guard", "type": "main", "index": 0 } ], [], [ { "node": "Normalize Updated Torrents", "type": "main", "index": 0 } ] ] }, "Prepare Notification Data": { "main": [ [ { "node": "Execute Notification Router", "type": "main", "index": 0 } ] ] }, "Needs MAM Update (IF)": { "main": [ [ { "node": "Update Existing with MAM Data", "type": "main", "index": 0 } ] ] }, "Flag Needs MAM Update": { "main": [ [ { "node": "Needs MAM Update (IF)", "type": "main", "index": 0 } ] ] }, "Insert New Torrents": { "main": [ [ { "node": "Collect Notification Items", "type": "main", "index": 0 } ] ] }, "Collect Notification Items": { "main": [ [ { "node": "Prepare Notification Data", "type": "main", "index": 0 } ] ] }, "Normalize Updated Torrents": { "main": [ [ { "node": "Collect Notification Items", "type": "main", "index": 1 }, { "node": "Flag Needs MAM Update", "type": "main", "index": 0 } ] ] }, "Get DB Rows for Deduplication": { "main": [ [ { "node": "Compare Datasets", "type": "main", "index": 1 } ] ] }, "Has Info Hash Guard": { "main": [ [ { "node": "Insert New Torrents", "type": "main", "index": 0 } ] ] } }, "settings": {}, "triggerCount": 1, "versionId": "91ae4190-31f6-4a86-b38d-6a69a171d9bf", "owner": { "type": "personal", "projectId": "FeLO36wNUAcn61Wj", "projectName": "Ben W ", "personalEmail": "admin@ben.io" }, "parentFolderId": "kUg4HIPXraph3M0E", "isArchived": false }