init after v1 corruption
This commit is contained in:
868
workflows/aEtoKG8mIocULX5W.json
Normal file
868
workflows/aEtoKG8mIocULX5W.json
Normal file
@@ -0,0 +1,868 @@
|
||||
{
|
||||
"id": "aEtoKG8mIocULX5W",
|
||||
"name": "Audiobook Torrents",
|
||||
"nodes": [
|
||||
{
|
||||
"parameters": {},
|
||||
"type": "n8n-nodes-base.manualTrigger",
|
||||
"typeVersion": 1,
|
||||
"position": [
|
||||
-736,
|
||||
-48
|
||||
],
|
||||
"id": "286acfc0-180f-407a-aa4a-f76683e5e061",
|
||||
"name": "When clicking 'Execute workflow'"
|
||||
},
|
||||
{
|
||||
"parameters": {
|
||||
"url": "https://nyaa.si/?page=rss&q=%5BAudiobook%5D&c=3_1&f=0",
|
||||
"options": {}
|
||||
},
|
||||
"type": "n8n-nodes-base.httpRequest",
|
||||
"typeVersion": 4.2,
|
||||
"position": [
|
||||
-512,
|
||||
48
|
||||
],
|
||||
"id": "c3a1b112-cd01-4a0e-b843-bd6c635202c6",
|
||||
"name": "HTTP Request"
|
||||
},
|
||||
{
|
||||
"parameters": {
|
||||
"options": {
|
||||
"trim": true
|
||||
}
|
||||
},
|
||||
"type": "n8n-nodes-base.xml",
|
||||
"typeVersion": 1,
|
||||
"position": [
|
||||
-288,
|
||||
48
|
||||
],
|
||||
"id": "0239b8cc-c0b0-4bce-9892-176bf69ab8aa",
|
||||
"name": "XML"
|
||||
},
|
||||
{
|
||||
"parameters": {
|
||||
"fieldToSplitOut": "rss.channel.item",
|
||||
"options": {}
|
||||
},
|
||||
"id": "split-items-node",
|
||||
"name": "Split Feed Items",
|
||||
"type": "n8n-nodes-base.splitOut",
|
||||
"typeVersion": 1,
|
||||
"position": [
|
||||
-64,
|
||||
48
|
||||
]
|
||||
},
|
||||
{
|
||||
"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": [
|
||||
160,
|
||||
48
|
||||
],
|
||||
"executeOnce": false
|
||||
},
|
||||
{
|
||||
"parameters": {
|
||||
"conditions": {
|
||||
"conditions": [
|
||||
{
|
||||
"leftValue": "={{ $json.seeders }}",
|
||||
"rightValue": 0,
|
||||
"operator": {
|
||||
"type": "number",
|
||||
"operation": "gt"
|
||||
}
|
||||
}
|
||||
]
|
||||
},
|
||||
"options": {}
|
||||
},
|
||||
"id": "filter-has-seeders",
|
||||
"name": "Has Seeders?",
|
||||
"type": "n8n-nodes-base.if",
|
||||
"typeVersion": 2,
|
||||
"position": [
|
||||
-592,
|
||||
624
|
||||
]
|
||||
},
|
||||
{
|
||||
"parameters": {
|
||||
"rule": {
|
||||
"interval": [
|
||||
{
|
||||
"field": "minutes"
|
||||
}
|
||||
]
|
||||
}
|
||||
},
|
||||
"id": "schedule-trigger-5min",
|
||||
"name": "Every 5 Minutes",
|
||||
"type": "n8n-nodes-base.scheduleTrigger",
|
||||
"typeVersion": 1.2,
|
||||
"position": [
|
||||
-736,
|
||||
144
|
||||
]
|
||||
},
|
||||
{
|
||||
"parameters": {
|
||||
"sendTo": "admin@ben.io",
|
||||
"subject": "={{ $json.torrentCount }} New Audiobook Torrent(s) Found",
|
||||
"message": "={{ $json.emailHtmlBody }}",
|
||||
"options": {}
|
||||
},
|
||||
"id": "send-gmail-notification",
|
||||
"name": "Send Gmail Notification",
|
||||
"type": "n8n-nodes-base.gmail",
|
||||
"typeVersion": 2.1,
|
||||
"position": [
|
||||
896,
|
||||
528
|
||||
],
|
||||
"webhookId": "8da5c0a8-d147-46e8-bcc5-85d5cd2c87d5",
|
||||
"credentials": {
|
||||
"gmailOAuth2": {
|
||||
"id": "Os1ux3h3zFlC2XkG",
|
||||
"name": "Gmail account"
|
||||
}
|
||||
}
|
||||
},
|
||||
{
|
||||
"parameters": {
|
||||
"operation": "getAll",
|
||||
"tableId": "nyaa_audiobooks",
|
||||
"returnAll": true,
|
||||
"filterType": "none"
|
||||
},
|
||||
"type": "n8n-nodes-base.supabase",
|
||||
"typeVersion": 1,
|
||||
"position": [
|
||||
-368,
|
||||
704
|
||||
],
|
||||
"id": "ea585083-0b0a-410b-b0ac-768badf335fa",
|
||||
"name": "Get many rows",
|
||||
"executeOnce": true,
|
||||
"credentials": {
|
||||
"supabaseApi": {
|
||||
"id": "lWyf2ikOGHTTwnSU",
|
||||
"name": "Supabase account"
|
||||
}
|
||||
}
|
||||
},
|
||||
{
|
||||
"parameters": {
|
||||
"mergeByFields": {
|
||||
"values": [
|
||||
{
|
||||
"field1": "info_hash",
|
||||
"field2": "info_hash"
|
||||
}
|
||||
]
|
||||
},
|
||||
"options": {
|
||||
"skipFields": "seeders,discovered_at,updated_at,mam_torrent_id,mam_checked_at,view_link,id,created_at,search_title,volume_range"
|
||||
}
|
||||
},
|
||||
"type": "n8n-nodes-base.compareDatasets",
|
||||
"typeVersion": 2.3,
|
||||
"position": [
|
||||
-144,
|
||||
592
|
||||
],
|
||||
"id": "13fffea6-eb23-4746-9c21-e9695bd8c377",
|
||||
"name": "Compare Datasets"
|
||||
},
|
||||
{
|
||||
"parameters": {
|
||||
"jsCode": "// Get all incoming items using $input.all()\nconst torrents = $input.all();\nconst count = torrents.length;\n\n// If no torrents, return empty to stop workflow\nif (count === 0) {\n return [];\n}\n\n// Helper function to get MAM status display\nfunction getMAMStatus(torrent) {\n if (torrent.mam_torrent_id) {\n return `✅ <a href=\"https://www.myanonamouse.net/t/${torrent.mam_torrent_id}\">Yes</a>`;\n } else {\n return '❌ No';\n }\n}\n\n// Build HTML table rows\nlet tableRows = \"\";\n\nfor (const item of torrents) {\n const torrent = item.json;\n \n tableRows += `\n <tr>\n <td><a href=\"${torrent.view_link}\">${torrent.title}</a></td>\n <td>${torrent.seeders}</td>\n <td>${torrent.size}</td>\n <td>${getMAMStatus(torrent)}</td>\n <td>\n <a href=\"${torrent.link}\">Download</a> | \n <a href=\"${torrent.view_link}\">View</a>\n </td>\n </tr>\n `;\n}\n\n// Build complete HTML email body\nconst emailBody = `\n<h2>${count} New Audiobook Torrent(s) Found</h2>\n<table border=\"1\" cellpadding=\"8\" cellspacing=\"0\" style=\"border-collapse: collapse;\">\n <thead>\n <tr>\n <th>Title</th>\n <th>Seeders</th>\n <th>Size</th>\n <th>On MAM?</th>\n <th>Links</th>\n </tr>\n </thead>\n <tbody>\n ${tableRows}\n </tbody>\n</table>\n`;\n\nreturn [{\n json: {\n torrentCount: count,\n emailHtmlBody: emailBody\n }\n}];"
|
||||
},
|
||||
"type": "n8n-nodes-base.code",
|
||||
"typeVersion": 2,
|
||||
"position": [
|
||||
672,
|
||||
528
|
||||
],
|
||||
"id": "99f5e0ba-0c7e-4c37-9692-ff0c01ab48ae",
|
||||
"name": "Code in JavaScript",
|
||||
"executeOnce": true
|
||||
},
|
||||
{
|
||||
"parameters": {
|
||||
"conditions": {
|
||||
"options": {
|
||||
"caseSensitive": true,
|
||||
"leftValue": "",
|
||||
"typeValidation": "strict"
|
||||
},
|
||||
"conditions": [
|
||||
{
|
||||
"id": "condition1",
|
||||
"leftValue": "={{ $input.all().length }}",
|
||||
"rightValue": 0,
|
||||
"operator": {
|
||||
"type": "number",
|
||||
"operation": "gt"
|
||||
}
|
||||
}
|
||||
]
|
||||
},
|
||||
"options": {}
|
||||
},
|
||||
"id": "check-has-new-torrents",
|
||||
"name": "Has New Torrents?",
|
||||
"type": "n8n-nodes-base.if",
|
||||
"typeVersion": 2,
|
||||
"position": [
|
||||
224,
|
||||
528
|
||||
]
|
||||
},
|
||||
{
|
||||
"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": [
|
||||
448,
|
||||
528
|
||||
],
|
||||
"credentials": {
|
||||
"supabaseApi": {
|
||||
"id": "lWyf2ikOGHTTwnSU",
|
||||
"name": "Supabase account"
|
||||
}
|
||||
}
|
||||
},
|
||||
{
|
||||
"parameters": {
|
||||
"url": "https://www.myanonamouse.net/tor/js/loadSearchJSONbasic.php",
|
||||
"authentication": "genericCredentialType",
|
||||
"genericAuthType": "httpHeaderAuth",
|
||||
"sendQuery": true,
|
||||
"queryParameters": {
|
||||
"parameters": [
|
||||
{
|
||||
"name": "tor[text]",
|
||||
"value": "={{ $json.search_title }}"
|
||||
},
|
||||
{
|
||||
"name": "tor[srchIn][title]",
|
||||
"value": "true"
|
||||
},
|
||||
{
|
||||
"name": "tor[searchType]",
|
||||
"value": "all"
|
||||
},
|
||||
{
|
||||
"name": "tor[main_cat][]",
|
||||
"value": "13"
|
||||
},
|
||||
{
|
||||
"name": "tor[sortType]",
|
||||
"value": "default"
|
||||
},
|
||||
{
|
||||
"name": "tor[startNumber]",
|
||||
"value": "0"
|
||||
},
|
||||
{
|
||||
"name": "perpage",
|
||||
"value": "10"
|
||||
}
|
||||
]
|
||||
},
|
||||
"sendHeaders": true,
|
||||
"headerParameters": {
|
||||
"parameters": [
|
||||
{
|
||||
"name": "Content-Type",
|
||||
"value": "application/json; charset=utf-8"
|
||||
}
|
||||
]
|
||||
},
|
||||
"options": {
|
||||
"response": {
|
||||
"response": {
|
||||
"neverError": true
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
"id": "search-mam-by-title",
|
||||
"name": "Search MAM by Title",
|
||||
"type": "n8n-nodes-base.httpRequest",
|
||||
"typeVersion": 4.2,
|
||||
"position": [
|
||||
1056,
|
||||
48
|
||||
],
|
||||
"credentials": {
|
||||
"httpHeaderAuth": {
|
||||
"id": "sxQYMPEq6GLbc9Av",
|
||||
"name": "n8n_auth_cookie"
|
||||
}
|
||||
}
|
||||
},
|
||||
{
|
||||
"parameters": {
|
||||
"jsCode": "// Parse MAM title search results with volume and format matching\n// Get the filtered torrents that actually went through MAM search\nconst searchedTorrents = $('Filter Unchecked Torrents').all();\nconst mamResults = $input.all();\n\n// Helper function to extract volume number from MAM title\nfunction extractVolume(title) {\n const patterns = [\n /[Vv]ol\\.?\\s*(\\d+)/,\n /[Vv]olume\\s*(\\d+)/,\n /\\bv(\\d+)\\b/,\n /[Bb]ook\\s*(\\d+)/,\n /,\\s*(\\d+)$/ // Match \", 1\" at end of title\n ];\n \n for (const pattern of patterns) {\n const match = title.match(pattern);\n if (match) {\n return parseInt(match[1]);\n }\n }\n return null;\n}\n\n// Helper function to check if volume is in range\nfunction isVolumeInRange(vol, range) {\n if (!range || vol === null) return false;\n return vol >= range.start && vol <= range.end;\n}\n\n// Helper function to check if it's m4b format\nfunction isM4bFormat(filetype) {\n if (!filetype) return false;\n return filetype.toLowerCase().includes('m4b');\n}\n\n// Process each item - match MAM results with the torrents that were searched\nreturn searchedTorrents.map((item, index) => {\n const mamResult = mamResults[index]?.json;\n const torrentData = item.json;\n \n let mamTorrentId = null;\n let mamFound = false;\n \n if (mamResult && mamResult.data && Array.isArray(mamResult.data) && mamResult.data.length > 0) {\n // Search through results for a matching volume and format\n for (const result of mamResult.data) {\n // Only match m4b format\n if (!isM4bFormat(result.filetype)) {\n continue;\n }\n \n // Extract volume from MAM title\n const mamVolume = extractVolume(result.title || '');\n \n // If Nyaa has volume info, match it\n if (torrentData.volume_range) {\n if (isVolumeInRange(mamVolume, torrentData.volume_range)) {\n mamTorrentId = result.id;\n mamFound = true;\n break;\n }\n } else {\n // No volume info in Nyaa title, take first m4b match\n mamTorrentId = result.id;\n mamFound = true;\n break;\n }\n }\n }\n \n return {\n json: {\n ...torrentData,\n mam_torrent_id: mamTorrentId,\n mam_found_by_title: mamFound,\n mam_checked_at: new Date().toISOString()\n }\n };\n});"
|
||||
},
|
||||
"id": "parse-mam-title-results",
|
||||
"name": "Parse MAM Title Results",
|
||||
"type": "n8n-nodes-base.code",
|
||||
"typeVersion": 2,
|
||||
"position": [
|
||||
1280,
|
||||
48
|
||||
],
|
||||
"executeOnce": false
|
||||
},
|
||||
{
|
||||
"parameters": {
|
||||
"conditions": {
|
||||
"conditions": [
|
||||
{
|
||||
"leftValue": "={{ $json.mam_found_by_title }}",
|
||||
"rightValue": true,
|
||||
"operator": {
|
||||
"type": "boolean",
|
||||
"operation": "equals"
|
||||
}
|
||||
}
|
||||
]
|
||||
},
|
||||
"options": {}
|
||||
},
|
||||
"id": "title-match-found",
|
||||
"name": "Title Match Found?",
|
||||
"type": "n8n-nodes-base.if",
|
||||
"typeVersion": 2,
|
||||
"position": [
|
||||
-496,
|
||||
336
|
||||
]
|
||||
},
|
||||
{
|
||||
"parameters": {
|
||||
"jsCode": "// Extract author/narrator from Nyaa title for fallback search\nreturn $input.all().map(item => {\n const title = item.json.title || '';\n let searchTerm = '';\n \n // Try to extract author/narrator from common patterns\n // Pattern 1: \"Author Name - Book Title\"\n const dashPattern = /^([^-]+)\\s*-\\s*.+$/;\n const dashMatch = title.match(dashPattern);\n if (dashMatch) {\n searchTerm = dashMatch[1].trim();\n }\n \n // Pattern 2: [Author Name]\n if (!searchTerm) {\n const bracketPattern = /\\[([^\\]]+)\\]/;\n const bracketMatch = title.match(bracketPattern);\n if (bracketMatch) {\n searchTerm = bracketMatch[1].trim();\n }\n }\n \n // Pattern 3: \"by Author Name\"\n if (!searchTerm) {\n const byPattern = /\\bby\\s+([^-,(]+)/i;\n const byMatch = title.match(byPattern);\n if (byMatch) {\n searchTerm = byMatch[1].trim();\n }\n }\n \n // Fallback: use first few words of title\n if (!searchTerm) {\n const words = title.split(/\\s+/).slice(0, 3);\n searchTerm = words.join(' ');\n }\n \n return {\n json: {\n ...item.json,\n search_term: searchTerm\n }\n };\n});"
|
||||
},
|
||||
"id": "extract-author-narrator",
|
||||
"name": "Extract Author/Narrator",
|
||||
"type": "n8n-nodes-base.code",
|
||||
"typeVersion": 2,
|
||||
"position": [
|
||||
-256,
|
||||
320
|
||||
],
|
||||
"executeOnce": false
|
||||
},
|
||||
{
|
||||
"parameters": {
|
||||
"url": "https://www.myanonamouse.net/tor/js/loadSearchJSONbasic.php",
|
||||
"authentication": "genericCredentialType",
|
||||
"genericAuthType": "httpHeaderAuth",
|
||||
"sendQuery": true,
|
||||
"queryParameters": {
|
||||
"parameters": [
|
||||
{
|
||||
"name": "tor[text]",
|
||||
"value": "={{ $json.search_term }}"
|
||||
},
|
||||
{
|
||||
"name": "tor[srchIn][author]",
|
||||
"value": "true"
|
||||
},
|
||||
{
|
||||
"name": "tor[srchIn][narrator]",
|
||||
"value": "true"
|
||||
},
|
||||
{
|
||||
"name": "tor[searchType]",
|
||||
"value": "all"
|
||||
},
|
||||
{
|
||||
"name": "tor[main_cat][]",
|
||||
"value": "13"
|
||||
},
|
||||
{
|
||||
"name": "tor[sortType]",
|
||||
"value": "default"
|
||||
},
|
||||
{
|
||||
"name": "tor[startNumber]",
|
||||
"value": "0"
|
||||
},
|
||||
{
|
||||
"name": "perpage",
|
||||
"value": "10"
|
||||
}
|
||||
]
|
||||
},
|
||||
"sendHeaders": true,
|
||||
"headerParameters": {
|
||||
"parameters": [
|
||||
{
|
||||
"name": "Content-Type",
|
||||
"value": "application/json; charset=utf-8"
|
||||
}
|
||||
]
|
||||
},
|
||||
"options": {
|
||||
"response": {
|
||||
"response": {
|
||||
"neverError": true
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
"id": "search-mam-by-author",
|
||||
"name": "Search MAM by Author/Narrator",
|
||||
"type": "n8n-nodes-base.httpRequest",
|
||||
"typeVersion": 4.2,
|
||||
"position": [
|
||||
-48,
|
||||
320
|
||||
],
|
||||
"credentials": {
|
||||
"httpHeaderAuth": {
|
||||
"id": "sxQYMPEq6GLbc9Av",
|
||||
"name": "n8n_auth_cookie"
|
||||
}
|
||||
}
|
||||
},
|
||||
{
|
||||
"parameters": {
|
||||
"jsCode": "// Parse MAM author/narrator search results\n// Get the torrents that went through author/narrator search (filtered by title-not-found)\nconst searchedTorrents = $('Extract Author/Narrator').all();\nconst mamResults = $input.all();\n\n// Process each item\nreturn searchedTorrents.map((item, index) => {\n const mamResult = mamResults[index]?.json;\n const torrentData = item.json;\n \n // Check if MAM search returned results\n let mamTorrentId = torrentData.mam_torrent_id;\n \n // Only update if we didn't find by title\n if (!torrentData.mam_found_by_title && mamResult && mamResult.data && Array.isArray(mamResult.data) && mamResult.data.length > 0) {\n // Found at least one match - take the first result\n mamTorrentId = mamResult.data[0].id;\n }\n \n return {\n json: {\n ...torrentData,\n mam_torrent_id: mamTorrentId\n }\n };\n});"
|
||||
},
|
||||
"id": "parse-mam-author-results",
|
||||
"name": "Parse MAM Author Results",
|
||||
"type": "n8n-nodes-base.code",
|
||||
"typeVersion": 2,
|
||||
"position": [
|
||||
160,
|
||||
320
|
||||
],
|
||||
"executeOnce": false
|
||||
},
|
||||
{
|
||||
"parameters": {
|
||||
"jsCode": "// Merge data from both paths (title match and author/narrator search)\n// Note: Only one of these paths will execute depending on title match result\n\n// Get all input items from the current execution\nconst allResults = $input.all();\n\n// Clean up temporary fields used during MAM search\nreturn allResults.map(item => {\n const { mam_found_by_title, search_term, ...cleanData } = item.json;\n return {\n json: cleanData\n };\n});"
|
||||
},
|
||||
"id": "merge-mam-data",
|
||||
"name": "Merge MAM Data",
|
||||
"type": "n8n-nodes-base.code",
|
||||
"typeVersion": 2,
|
||||
"position": [
|
||||
400,
|
||||
320
|
||||
],
|
||||
"executeOnce": false
|
||||
},
|
||||
{
|
||||
"parameters": {
|
||||
"conditions": {
|
||||
"options": {
|
||||
"caseSensitive": true,
|
||||
"leftValue": "",
|
||||
"typeValidation": "strict",
|
||||
"version": 1
|
||||
},
|
||||
"conditions": [
|
||||
{
|
||||
"leftValue": "={{ $json.mam_torrent_id }}",
|
||||
"rightValue": "",
|
||||
"operator": {
|
||||
"type": "number",
|
||||
"operation": "notEmpty",
|
||||
"singleValue": true
|
||||
},
|
||||
"id": "41cd060f-08bc-4b5c-8396-ac604893a67a"
|
||||
}
|
||||
],
|
||||
"combinator": "and"
|
||||
},
|
||||
"options": {}
|
||||
},
|
||||
"id": "filter-needs-mam-update",
|
||||
"name": "Needs MAM Update?",
|
||||
"type": "n8n-nodes-base.filter",
|
||||
"typeVersion": 2,
|
||||
"position": [
|
||||
224,
|
||||
720
|
||||
]
|
||||
},
|
||||
{
|
||||
"parameters": {
|
||||
"jsCode": "// Extract base title AND volume numbers for matching\nreturn $input.all().map(item => {\n let fullTitle = item.json.title || '';\n let baseTitle = fullTitle;\n let volumeInfo = null;\n \n // Extract volume information first (we'll need it for matching later)\n // Match patterns: Vol. 01-10, Vol 1-5, Volume 1, v01, Book 1, etc.\n const volPatterns = [\n /[Vv]ol\\.?\\s*(\\d+)(?:\\s*-\\s*(\\d+))?/,\n /[Vv]olume\\s*(\\d+)(?:\\s*-\\s*(\\d+))?/,\n /\\bv(\\d+)(?:-v?(\\d+))?\\b/,\n /[Bb]ook\\s*(\\d+)(?:\\s*-\\s*(\\d+))?/\n ];\n \n for (const pattern of volPatterns) {\n const match = fullTitle.match(pattern);\n if (match) {\n const startVol = parseInt(match[1]);\n const endVol = match[2] ? parseInt(match[2]) : startVol;\n volumeInfo = { start: startVol, end: endVol };\n break;\n }\n }\n \n // Remove all metadata to get base title\n baseTitle = baseTitle.replace(/\\s*[Vv]ol\\.?\\s*\\d+(-\\d+)?/gi, '');\n baseTitle = baseTitle.replace(/\\s*[Vv]olume\\s*\\d+(-\\d+)?/gi, '');\n baseTitle = baseTitle.replace(/\\s*\\bv\\d+(-v?\\d+)?\\b/gi, '');\n baseTitle = baseTitle.replace(/\\s*\\[[^\\]]+\\]/g, '');\n baseTitle = baseTitle.replace(/\\s*\\([^)]+\\)/g, '');\n baseTitle = baseTitle.replace(/\\s*[Bb]ook\\s*\\d+(-\\d+)?/gi, '');\n baseTitle = baseTitle.replace(/\\s*[Pp]art\\s*\\d+(-\\d+)?/gi, '');\n baseTitle = baseTitle.replace(/[,\\s-]+$/, '').trim();\n \n return {\n json: {\n ...item.json,\n search_title: baseTitle,\n volume_range: volumeInfo\n }\n };\n});"
|
||||
},
|
||||
"id": "extract-base-title",
|
||||
"name": "Extract Base Title",
|
||||
"type": "n8n-nodes-base.code",
|
||||
"typeVersion": 2,
|
||||
"position": [
|
||||
384,
|
||||
48
|
||||
]
|
||||
},
|
||||
{
|
||||
"parameters": {
|
||||
"jsCode": "// Filter out torrents that already have MAM data\nconst nyaaTorrents = $('Extract Base Title').all();\nconst dbTorrents = $('Get DB Torrents for Filtering').all();\n\n// Create a map of info_hash -> mam_torrent_id from database\nconst checkedHashes = new Map();\nfor (const item of dbTorrents) {\n if (item.json.mam_torrent_id) {\n checkedHashes.set(item.json.info_hash, item.json.mam_torrent_id);\n }\n}\n\n// Filter Nyaa torrents to only include unchecked ones\nconst uncheckedTorrents = nyaaTorrents.filter(item => {\n return !checkedHashes.has(item.json.info_hash);\n});\n\nconsole.log(`Total torrents: ${nyaaTorrents.length}, Already checked: ${checkedHashes.size}, Need MAM search: ${uncheckedTorrents.length}`);\n\nreturn uncheckedTorrents;"
|
||||
},
|
||||
"id": "filter-unchecked-torrents",
|
||||
"name": "Filter Unchecked Torrents",
|
||||
"type": "n8n-nodes-base.code",
|
||||
"typeVersion": 2,
|
||||
"position": [
|
||||
832,
|
||||
48
|
||||
]
|
||||
},
|
||||
{
|
||||
"id": "Get DB Torrents for Filtering",
|
||||
"name": "Get DB Torrents for Filtering (Postgres)",
|
||||
"type": "n8n-nodes-base.postgres",
|
||||
"typeVersion": 1,
|
||||
"position": [
|
||||
500,
|
||||
100
|
||||
],
|
||||
"parameters": {
|
||||
"operation": "executeQuery",
|
||||
"query": "SELECT * FROM nyaa_audiobooks;"
|
||||
},
|
||||
"credentials": {
|
||||
"postgres": {
|
||||
"id": "9grzZwW7Br6SzdV8",
|
||||
"name": "n8n-media"
|
||||
}
|
||||
}
|
||||
},
|
||||
{
|
||||
"id": "Update Existing Torrents MAM Data",
|
||||
"name": "Update Existing Torrents MAM Data (Postgres)",
|
||||
"type": "n8n-nodes-base.postgres",
|
||||
"typeVersion": 1,
|
||||
"position": [
|
||||
1500,
|
||||
500
|
||||
],
|
||||
"parameters": {
|
||||
"operation": "executeQuery",
|
||||
"options": {
|
||||
"queryParameterValues": "{{$json.mam_torrent_id}},{{$json.id}}"
|
||||
},
|
||||
"query": "UPDATE nyaa_audiobooks SET mam_torrent_id = $1, mam_checked_at = NOW(), updated_at = NOW() WHERE id = $2;"
|
||||
},
|
||||
"credentials": {
|
||||
"postgres": {
|
||||
"id": "9grzZwW7Br6SzdV8",
|
||||
"name": "n8n-media"
|
||||
}
|
||||
}
|
||||
}
|
||||
],
|
||||
"connections": {
|
||||
"When clicking 'Execute workflow'": {
|
||||
"main": [
|
||||
[
|
||||
{
|
||||
"node": "HTTP Request",
|
||||
"type": "main",
|
||||
"index": 0
|
||||
}
|
||||
]
|
||||
]
|
||||
},
|
||||
"HTTP Request": {
|
||||
"main": [
|
||||
[
|
||||
{
|
||||
"node": "XML",
|
||||
"type": "main",
|
||||
"index": 0
|
||||
}
|
||||
]
|
||||
]
|
||||
},
|
||||
"XML": {
|
||||
"main": [
|
||||
[
|
||||
{
|
||||
"node": "Split Feed Items",
|
||||
"type": "main",
|
||||
"index": 0
|
||||
}
|
||||
]
|
||||
]
|
||||
},
|
||||
"Split Feed Items": {
|
||||
"main": [
|
||||
[
|
||||
{
|
||||
"node": "Extract Torrent Data",
|
||||
"type": "main",
|
||||
"index": 0
|
||||
}
|
||||
]
|
||||
]
|
||||
},
|
||||
"Every 5 Minutes": {
|
||||
"main": [
|
||||
[
|
||||
{
|
||||
"node": "HTTP Request",
|
||||
"type": "main",
|
||||
"index": 0
|
||||
}
|
||||
]
|
||||
]
|
||||
},
|
||||
"Has Seeders?": {
|
||||
"main": [
|
||||
[
|
||||
{
|
||||
"node": "Get many rows",
|
||||
"type": "main",
|
||||
"index": 0
|
||||
},
|
||||
{
|
||||
"node": "Compare Datasets",
|
||||
"type": "main",
|
||||
"index": 0
|
||||
}
|
||||
]
|
||||
]
|
||||
},
|
||||
"Get many rows": {
|
||||
"main": [
|
||||
[
|
||||
{
|
||||
"node": "Compare Datasets",
|
||||
"type": "main",
|
||||
"index": 1
|
||||
}
|
||||
]
|
||||
]
|
||||
},
|
||||
"Code in JavaScript": {
|
||||
"main": [
|
||||
[
|
||||
{
|
||||
"node": "Send Gmail Notification",
|
||||
"type": "main",
|
||||
"index": 0
|
||||
}
|
||||
]
|
||||
]
|
||||
},
|
||||
"Compare Datasets": {
|
||||
"main": [
|
||||
[
|
||||
{
|
||||
"node": "Has New Torrents?",
|
||||
"type": "main",
|
||||
"index": 0
|
||||
}
|
||||
],
|
||||
[
|
||||
{
|
||||
"node": "Needs MAM Update?",
|
||||
"type": "main",
|
||||
"index": 0
|
||||
}
|
||||
]
|
||||
]
|
||||
},
|
||||
"Has New Torrents?": {
|
||||
"main": [
|
||||
[
|
||||
{
|
||||
"node": "Insert New Torrents",
|
||||
"type": "main",
|
||||
"index": 0
|
||||
}
|
||||
]
|
||||
]
|
||||
},
|
||||
"Insert New Torrents": {
|
||||
"main": [
|
||||
[
|
||||
{
|
||||
"node": "Code in JavaScript",
|
||||
"type": "main",
|
||||
"index": 0
|
||||
}
|
||||
]
|
||||
]
|
||||
},
|
||||
"Search MAM by Title": {
|
||||
"main": [
|
||||
[
|
||||
{
|
||||
"node": "Parse MAM Title Results",
|
||||
"type": "main",
|
||||
"index": 0
|
||||
}
|
||||
]
|
||||
]
|
||||
},
|
||||
"Parse MAM Title Results": {
|
||||
"main": [
|
||||
[
|
||||
{
|
||||
"node": "Title Match Found?",
|
||||
"type": "main",
|
||||
"index": 0
|
||||
}
|
||||
]
|
||||
]
|
||||
},
|
||||
"Title Match Found?": {
|
||||
"main": [
|
||||
[
|
||||
{
|
||||
"node": "Extract Author/Narrator",
|
||||
"type": "main",
|
||||
"index": 0
|
||||
},
|
||||
{
|
||||
"node": "Merge MAM Data",
|
||||
"type": "main",
|
||||
"index": 0
|
||||
}
|
||||
]
|
||||
]
|
||||
},
|
||||
"Extract Author/Narrator": {
|
||||
"main": [
|
||||
[
|
||||
{
|
||||
"node": "Search MAM by Author/Narrator",
|
||||
"type": "main",
|
||||
"index": 0
|
||||
}
|
||||
]
|
||||
]
|
||||
},
|
||||
"Search MAM by Author/Narrator": {
|
||||
"main": [
|
||||
[
|
||||
{
|
||||
"node": "Parse MAM Author Results",
|
||||
"type": "main",
|
||||
"index": 0
|
||||
}
|
||||
]
|
||||
]
|
||||
},
|
||||
"Parse MAM Author Results": {
|
||||
"main": [
|
||||
[
|
||||
{
|
||||
"node": "Merge MAM Data",
|
||||
"type": "main",
|
||||
"index": 0
|
||||
}
|
||||
]
|
||||
]
|
||||
},
|
||||
"Merge MAM Data": {
|
||||
"main": [
|
||||
[
|
||||
{
|
||||
"node": "Has Seeders?",
|
||||
"type": "main",
|
||||
"index": 0
|
||||
}
|
||||
]
|
||||
]
|
||||
},
|
||||
"Extract Torrent Data": {
|
||||
"main": [
|
||||
[
|
||||
{
|
||||
"node": "Extract Base Title",
|
||||
"type": "main",
|
||||
"index": 0
|
||||
}
|
||||
]
|
||||
]
|
||||
},
|
||||
"Filter Unchecked Torrents": {
|
||||
"main": [
|
||||
[
|
||||
{
|
||||
"node": "Search MAM by Title",
|
||||
"type": "main",
|
||||
"index": 0
|
||||
}
|
||||
]
|
||||
]
|
||||
},
|
||||
"Extract Base Title": {
|
||||
"main": [
|
||||
[
|
||||
{
|
||||
"node": "Get DB Torrents for Filtering (Postgres)",
|
||||
"type": "main",
|
||||
"index": 0
|
||||
}
|
||||
]
|
||||
]
|
||||
},
|
||||
"Get DB Torrents for Filtering (Postgres)": {
|
||||
"main": [
|
||||
[
|
||||
{
|
||||
"node": "Filter Unchecked Torrents",
|
||||
"type": "main",
|
||||
"index": 0
|
||||
}
|
||||
]
|
||||
]
|
||||
},
|
||||
"Needs MAM Update?": {
|
||||
"main": [
|
||||
[
|
||||
{
|
||||
"node": "Update Existing Torrents MAM Data (Postgres)",
|
||||
"type": "main",
|
||||
"index": 0
|
||||
}
|
||||
]
|
||||
]
|
||||
}
|
||||
},
|
||||
"settings": {
|
||||
"executionOrder": "v1",
|
||||
"callerPolicy": "workflowsFromSameOwner",
|
||||
"availableInMCP": false
|
||||
},
|
||||
"triggerCount": 1,
|
||||
"versionId": "5a1020ae-9654-4801-8ddc-48d87af2b558",
|
||||
"owner": {
|
||||
"type": "personal",
|
||||
"projectId": "FeLO36wNUAcn61Wj",
|
||||
"projectName": "Ben W <admin@ben.io>",
|
||||
"personalEmail": "admin@ben.io"
|
||||
},
|
||||
"parentFolderId": "kUg4HIPXraph3M0E",
|
||||
"isArchived": false
|
||||
}
|
||||
Reference in New Issue
Block a user