{
  "name": "News Aggregation with Deduplication and Ranking",
  "nodes": [
    {
      "parameters": {},
      "name": "Manual Trigger",
      "type": "n8n-nodes-base.manualTrigger",
      "typeVersion": 1,
      "position": [
        240,
        400
      ]
    },
    {
      "parameters": {
        "url": "https://newsapi.org/v2/everything?q=AI&language=en&pageSize=20",
        "authentication": "predefinedCredentialType",
        "nodeCredentialType": "httpHeaderAuth",
        "options": {}
      },
      "name": "Fetch NewsAPI",
      "type": "n8n-nodes-base.httpRequest",
      "typeVersion": 4.2,
      "position": [
        460,
        300
      ]
    },
    {
      "parameters": {
        "url": "https://blog.n8n.io/rss/",
        "options": {}
      },
      "name": "Fetch RSS Feed",
      "type": "n8n-nodes-base.rssFeedRead",
      "typeVersion": 1,
      "position": [
        460,
        500
      ]
    },
    {
      "parameters": {
        "assignments": {
          "assignments": [
            {
              "id": "title",
              "name": "title",
              "value": "={{ $json.title }}",
              "type": "string"
            },
            {
              "id": "url",
              "name": "url",
              "value": "={{ $json.url }}",
              "type": "string"
            },
            {
              "id": "source",
              "name": "source",
              "value": "={{ $json.source.name }}",
              "type": "string"
            },
            {
              "id": "timestamp",
              "name": "timestamp",
              "value": "={{ $json.publishedAt }}",
              "type": "string"
            },
            {
              "id": "summary",
              "name": "summary",
              "value": "={{ $json.description }}",
              "type": "string"
            },
            {
              "id": "score",
              "name": "score",
              "value": 0,
              "type": "number"
            }
          ]
        }
      },
      "name": "Normalize NewsAPI",
      "type": "n8n-nodes-base.set",
      "typeVersion": 3.3,
      "position": [
        680,
        300
      ]
    },
    {
      "parameters": {
        "assignments": {
          "assignments": [
            {
              "id": "title",
              "name": "title",
              "value": "={{ $json.title }}",
              "type": "string"
            },
            {
              "id": "url",
              "name": "url",
              "value": "={{ $json.link }}",
              "type": "string"
            },
            {
              "id": "source",
              "name": "source",
              "value": "n8n Blog",
              "type": "string"
            },
            {
              "id": "timestamp",
              "name": "timestamp",
              "value": "={{ $json.pubDate }}",
              "type": "string"
            },
            {
              "id": "summary",
              "name": "summary",
              "value": "={{ $json.contentSnippet }}",
              "type": "string"
            },
            {
              "id": "score",
              "name": "score",
              "value": 0,
              "type": "number"
            }
          ]
        }
      },
      "name": "Normalize RSS",
      "type": "n8n-nodes-base.set",
      "typeVersion": 3.3,
      "position": [
        680,
        500
      ]
    },
    {
      "parameters": {
        "mode": "append"
      },
      "name": "Merge Sources",
      "type": "n8n-nodes-base.merge",
      "typeVersion": 2.1,
      "position": [
        900,
        400
      ]
    },
    {
      "parameters": {
        "mode": "raw",
        "jsonOutput": "={{ (() => {\n  const items = $input.all().map(i => i.json);\n  const seen = new Set();\n  const unique = [];\n\n  for (const item of items) {\n    const url = (item.url || '').toLowerCase().replace(/^https?:\\/\\/(www\\.)?/, '').replace(/\\/$/, '');\n    if (url && !seen.has(url)) {\n      seen.add(url);\n      unique.push(item);\n    }\n  }\n\n  return unique;\n})() }}",
        "options": {}
      },
      "name": "Deduplicate",
      "type": "n8n-nodes-base.code",
      "typeVersion": 2,
      "position": [
        1120,
        400
      ]
    },
    {
      "parameters": {
        "mode": "raw",
        "jsonOutput": "={{ (() => {\n  const items = $input.all().map(i => i.json);\n  const keywords = ['ai', 'automation', 'workflow', 'n8n'];\n\n  const scored = items.map(item => {\n    const text = (item.title + ' ' + item.summary).toLowerCase();\n    let score = 0;\n\n    keywords.forEach(kw => {\n      if (text.includes(kw)) score += 1;\n    });\n\n    const ageHours = (Date.now() - new Date(item.timestamp).getTime()) / (1000 * 60 * 60);\n    const recencyScore = ageHours < 24 ? 2 : ageHours < 48 ? 1 : 0;\n\n    return {\n      ...item,\n      keywordScore: score,\n      recencyScore,\n      finalScore: score + recencyScore\n    };\n  });\n\n  return scored.sort((a, b) => b.finalScore - a.finalScore).slice(0, 10);\n})() }}",
        "options": {}
      },
      "name": "Rank and Filter Top 10",
      "type": "n8n-nodes-base.code",
      "typeVersion": 2,
      "position": [
        1340,
        400
      ]
    }
  ],
  "connections": {
    "Manual Trigger": {
      "main": [
        [
          {
            "node": "Fetch NewsAPI",
            "type": "main",
            "index": 0
          },
          {
            "node": "Fetch RSS Feed",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "Fetch NewsAPI": {
      "main": [
        [
          {
            "node": "Normalize NewsAPI",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "Fetch RSS Feed": {
      "main": [
        [
          {
            "node": "Normalize RSS",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "Normalize NewsAPI": {
      "main": [
        [
          {
            "node": "Merge Sources",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "Normalize RSS": {
      "main": [
        [
          {
            "node": "Merge Sources",
            "type": "main",
            "index": 1
          }
        ]
      ]
    },
    "Merge Sources": {
      "main": [
        [
          {
            "node": "Deduplicate",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "Deduplicate": {
      "main": [
        [
          {
            "node": "Rank and Filter Top 10",
            "type": "main",
            "index": 0
          }
        ]
      ]
    }
  },
  "settings": {
    "executionOrder": "v1"
  }
}