Files
n8n-backup-v2/workflows/cSg8UMX1OvzDoLrk.json
2026-01-02 22:48:32 +00:00

376 lines
11 KiB
JSON

{
"id": "cSg8UMX1OvzDoLrk",
"name": "EVE Bazaar Ingest",
"nodes": [
{
"parameters": {
"rule": {
"interval": [
{
"field": "minutes",
"minutesInterval": 15
}
]
}
},
"id": "Schedule Trigger",
"name": "Schedule Trigger",
"position": [
0,
-24
],
"type": "n8n-nodes-base.scheduleTrigger",
"typeVersion": 1.1
},
{
"parameters": {
"url": "https://forums.eveonline.com/c/marketplace/character-bazaar/60.rss",
"options": {}
},
"id": "RSS Feed Read",
"name": "RSS Feed Read",
"position": [
224,
-24
],
"type": "n8n-nodes-base.rssFeedRead",
"typeVersion": 1.2
},
{
"parameters": {
"jsCode": "return $input.all().filter(item => {\n const title = (item.json.title || \"\").toUpperCase();\n return title.includes(\"WTS\") && !title.includes(\"WTB\");\n});"
},
"id": "Filter WTS",
"name": "Filter WTS",
"position": [
448,
-24
],
"type": "n8n-nodes-base.code",
"typeVersion": 2
},
{
"parameters": {
"jsCode": "const items = $input.all();\nreturn items.map(item => {\n const content = item.json.content || item.json.contentSnippet || \"\";\n const link = item.json.link || \"\";\n const text = content + \" \" + link;\n \n let charId = null;\n let skillqUrl = null;\n \n const patterns = [\n /evewho\\.com\\/character\\/(\\d+)/,\n /zkillboard\\.com\\/character\\/(\\d+)/,\n /qsna\\.eu\\/eve\\/characters?\\/(\\d+)/,\n /eveboard\\.com\\/pilot\\/([^\\/]+)/,\n /images\\.evetech\\.net\\/characters\\/(\\d+)\\//\n ];\n \n for (const pattern of patterns) {\n const match = text.match(pattern);\n if (match) {\n charId = match[1];\n break;\n }\n }\n \n // Look for SkillQ URL if no ID found\n if (!charId) {\n // Updated regex to require /share/ component and capture full path\n const skillqMatch = text.match(/skillq\\.net\\/char\\/([^\\/]+)\\/share\\/([a-f0-9\\-]+)/);\n if (skillqMatch) {\n // Construct full URL with share token\n // match[1] is name, match[2] is token\n skillqUrl = `https://skillq.net/char/${skillqMatch[1]}/share/${skillqMatch[2]}`;\n }\n }\n \n return {\n json: {\n ...item.json,\n character_id: charId,\n skillq_url: skillqUrl\n }\n };\n});"
},
"id": "Extract Character ID",
"name": "Extract Character ID",
"position": [
672,
-24
],
"type": "n8n-nodes-base.code",
"typeVersion": 2
},
{
"parameters": {
"jsCode": "const items = $input.all();\nconst ids = items.map(item => item.json.post_id).filter(id => id);\nreturn [{\n json: {\n ids: ids\n }\n}];"
},
"id": "Prepare ID List",
"name": "Prepare ID List",
"position": [
2016,
-24
],
"type": "n8n-nodes-base.code",
"typeVersion": 2
},
{
"parameters": {
"operation": "executeQuery",
"query": "SELECT * FROM character_bazaar_posts WHERE post_id IN ('{{ $json.ids.join(\"','\") }}')",
"options": {}
},
"id": "Lookup Posts",
"name": "Lookup Posts",
"position": [
2240,
-24
],
"type": "n8n-nodes-base.postgres",
"typeVersion": 2.4,
"alwaysOutputData": true,
"credentials": {
"postgres": {
"id": "dsnKfvOBMkgU21Lt",
"name": "supabase postgres account"
}
}
},
{
"parameters": {
"jsCode": "return $input.all().map(item => {\n const json = item.json;\n const escape = (str) => str ? str.replace(/'/g, \"''\") : '';\n \n const post_id = escape(json.post_id);\n const title = escape(json.title);\n const url = escape(json.url);\n const author = escape(json.author);\n const content = escape(json.content);\n const character_id = json.character_id ? `'${json.character_id}'` : 'NULL';\n\n const query = `INSERT INTO character_bazaar_posts (post_id, title, url, author, content, post_status, character_id)\nVALUES ('${post_id}', '${title}', '${url}', '${author}', '${content}', 'new', ${character_id})\nON CONFLICT (post_id) DO UPDATE SET\ntitle = EXCLUDED.title,\nurl = EXCLUDED.url,\nauthor = EXCLUDED.author,\ncontent = EXCLUDED.content,\npost_status = 'updated',\ncharacter_id = EXCLUDED.character_id;`;\n\n return {\n json: {\n ...json,\n query\n }\n };\n});"
},
"id": "Routing",
"name": "Routing",
"position": [
2464,
-24
],
"type": "n8n-nodes-base.code",
"typeVersion": 2
},
{
"parameters": {
"operation": "executeQuery",
"query": "={{ $json.query }}",
"options": {}
},
"id": "Store Results",
"name": "Store Results",
"position": [
2688,
-24
],
"type": "n8n-nodes-base.postgres",
"typeVersion": 2.4,
"credentials": {
"postgres": {
"id": "dsnKfvOBMkgU21Lt",
"name": "supabase postgres account"
}
}
},
{
"parameters": {
"conditions": {
"boolean": [
{
"value1": "={{ $json.skillq_url && !$json.character_id }}",
"value2": true
}
]
}
},
"id": "If SkillQ Repair",
"name": "If SkillQ Repair",
"type": "n8n-nodes-base.if",
"typeVersion": 1,
"position": [
896,
-24
]
},
{
"parameters": {
"url": "={{ $json.skillq_url }}",
"options": {}
},
"id": "Scrape SkillQ",
"name": "Scrape SkillQ",
"type": "n8n-nodes-base.httpRequest",
"typeVersion": 4.1,
"position": [
1120,
-24
],
"onError": "continueRegularOutput"
},
{
"parameters": {
"jsCode": "const items = $input.all();\n\nreturn items.map(item => {\n // HTML should be in skillq_html (from Scrape SkillQ) or data/body\n const html = item.json.skillq_html || item.json.data || item.json.body;\n \n let charId = null;\n let error = null;\n \n try {\n if (html && typeof html === 'string') {\n const match = html.match(/images\\.evetech\\.net\\/characters\\/(\\d+)\\//);\n if (match) {\n charId = match[1];\n } else {\n error = \"Could not find character ID in SkillQ page\";\n }\n } else {\n error = \"Invalid or empty response from SkillQ\";\n }\n } catch (e) {\n error = \"Error parsing SkillQ response: \" + e.message;\n }\n \n return {\n json: {\n ...item.json, // Keep all original data (merged from context)\n character_id: charId || item.json.character_id,\n scraping_error: error\n }\n };\n});"
},
"id": "Parse Scraped ID",
"name": "Parse Scraped ID",
"type": "n8n-nodes-base.code",
"typeVersion": 2,
"position": [
1568,
-96
]
},
{
"parameters": {
"jsCode": "let scraped = [];\ntry {\n // Try to get items from Parse Scraped ID\n // This will throw if the node hasn't executed (e.g. no items went to True branch)\n scraped = $('Parse Scraped ID').all();\n} catch (e) {\n // Node didn't execute, which is fine\n scraped = [];\n}\n\nconst skipped = $('If SkillQ Repair').all(1); // Get False branch items\n\nreturn [...scraped, ...skipped];"
},
"id": "Merge Manual",
"name": "Merge Manual",
"type": "n8n-nodes-base.code",
"typeVersion": 2,
"position": [
1792,
-24
]
},
{
"parameters": {
"mode": "combine",
"combineBy": "combineByPosition",
"options": {}
},
"id": "Merge Context",
"name": "Merge Context",
"type": "n8n-nodes-base.merge",
"typeVersion": 3,
"position": [
1344,
-96
]
}
],
"connections": {
"Extract Character ID": {
"main": [
[
{
"node": "If SkillQ Repair",
"type": "main",
"index": 0
}
]
]
},
"Filter WTS": {
"main": [
[
{
"index": 0,
"node": "Extract Character ID",
"type": "main"
}
]
]
},
"Lookup Posts": {
"main": [
[
{
"index": 0,
"node": "Routing",
"type": "main"
}
]
]
},
"Prepare ID List": {
"main": [
[
{
"index": 0,
"node": "Lookup Posts",
"type": "main"
}
]
]
},
"RSS Feed Read": {
"main": [
[
{
"index": 0,
"node": "Filter WTS",
"type": "main"
}
]
]
},
"Routing": {
"main": [
[
{
"index": 0,
"node": "Store Results",
"type": "main"
}
]
]
},
"Schedule Trigger": {
"main": [
[
{
"index": 0,
"node": "RSS Feed Read",
"type": "main"
}
]
]
},
"If SkillQ Repair": {
"main": [
[
{
"node": "Scrape SkillQ",
"type": "main",
"index": 0
},
{
"node": "Merge Context",
"type": "main",
"index": 0
}
],
[
{
"node": "Merge Manual",
"type": "main",
"index": 0
}
]
]
},
"Parse Scraped ID": {
"main": [
[
{
"node": "Merge Manual",
"type": "main",
"index": 0
}
]
]
},
"Merge Manual": {
"main": [
[
{
"node": "Prepare ID List",
"type": "main",
"index": 0
}
]
]
},
"Scrape SkillQ": {
"main": [
[
{
"node": "Merge Context",
"type": "main",
"index": 1
}
]
]
},
"Merge Context": {
"main": [
[
{
"node": "Parse Scraped ID",
"type": "main",
"index": 0
}
]
]
}
},
"settings": {
"executionOrder": "v1",
"saveDataErrorExecution": "all",
"saveDataSuccessExecution": "all",
"saveManualExecutions": true,
"saveExecutionProgress": true,
"callerPolicy": "workflowsFromSameOwner",
"availableInMCP": false
},
"triggerCount": 0,
"versionId": "51b5294b-1a43-4f17-a9e2-440a026e24fd",
"owner": {
"type": "personal",
"projectId": "FeLO36wNUAcn61Wj",
"projectName": "Ben W <admin@ben.io>",
"personalEmail": "admin@ben.io"
},
"parentFolderId": "HWgaFb7kLF649L7l",
"isArchived": false
}