{
  "id": "K07e4PPANXDkmQsr",
  "name": "🎞️ Pompeo — Jellyfin Watch History [Schedule]",
  "nodes": [
    {
      "parameters": {
        "rule": {
          "interval": [
            {
              "triggerAtHour": 4
            }
          ]
        }
      },
      "id": "b76a6172-d497-42a5-b286-56263e0de523",
      "name": "⏰ Cron",
      "type": "n8n-nodes-base.scheduleTrigger",
      "typeVersion": 1,
      "position": [
        0,
        304
      ]
    },
    {
      "parameters": {
        "url": "http://jellyfin.media.svc.cluster.local:8096/Users/42369255a7c64917a28fc26d4c7f8265/Items?Recursive=true&IncludeItemTypes=Movie,Episode&Fields=Genres,UserData,SeriesName,ParentIndexNumber&SortBy=DatePlayed&SortOrder=Descending&Limit=100",
        "sendHeaders": true,
        "headerParameters": {
          "parameters": [
            {
              "name": "Authorization",
              "value": "MediaBrowser Token=\"d153606c1ca54574a20d2b40fcf1b02e\""
            }
          ]
        },
        "options": {}
      },
      "id": "6bfda9a6-3b1f-46cb-ac05-0c19b9720e30",
      "name": "🎞️ HTTP Jellyfin",
      "type": "n8n-nodes-base.httpRequest",
      "typeVersion": 4.2,
      "position": [
        224,
        304
      ]
    },
    {
      "parameters": {
        "jsCode": "const response = $input.first().json;\nconst allItems = response.Items || [];\n\nconst now = new Date();\nconst ninetyDaysAgo = new Date(now.getTime() - 90 * 24 * 60 * 60 * 1000);\n\nconst filtered = allItems\n  .filter(d => d.UserData && d.UserData.PlayCount > 0)\n  .filter(d => {\n    if (!d.UserData.LastPlayedDate) return false;\n    return new Date(d.UserData.LastPlayedDate) >= ninetyDaysAgo;\n  })\n  .map(d => ({\n    title: d.Type === 'Episode'\n      ? (d.SeriesName || '') + ' S' + String(d.ParentIndexNumber || '')\n      : (d.Name || ''),\n    type: d.Type === 'Episode' ? 'episode' : 'movie',\n    genres: d.Genres || [],\n    play_count: d.UserData.PlayCount,\n    played_pct: d.UserData.PlayedPercentage || 0,\n    last_played: d.UserData.LastPlayedDate,\n    is_favorite: d.UserData.IsFavorite || false\n  }));\n\nlet watch_summary = 'Contenuti visti di recente:\\n';\nfor (const item of filtered) {\n  const dateStr = item.last_played\n    ? new Date(item.last_played).toLocaleDateString('it-IT')\n    : 'N/A';\n  watch_summary += '- ' + item.title + ' (' + item.type + ', ' + dateStr + ') - ' + item.play_count + 'x\\n';\n}\n\nreturn [{ json: { items: filtered, watch_summary } }];"
      },
      "id": "11e8a16f-4b77-4d1e-987b-3b269d577f08",
      "name": "🔀 Filtra Visti",
      "type": "n8n-nodes-base.code",
      "typeVersion": 2,
      "position": [
        448,
        304
      ]
    },
    {
      "parameters": {
        "conditions": {
          "number": [
            {
              "value1": "={{ $json.items.length }}",
              "operation": "larger"
            }
          ]
        }
      },
      "id": "19de4739-efe2-495e-969a-fbb01cbd7eeb",
      "name": "❓ Ha Visti?",
      "type": "n8n-nodes-base.if",
      "typeVersion": 1,
      "position": [
        672,
        304
      ]
    },
    {
      "parameters": {},
      "id": "d0a1c6e7-06eb-4d74-ac8b-c3c18abbcdbb",
      "name": "⛔ Stop",
      "type": "n8n-nodes-base.noOp",
      "typeVersion": 1,
      "position": [
        880,
        480
      ]
    },
    {
      "parameters": {
        "url": "https://api.github.com/copilot_internal/v2/token",
        "authentication": "predefinedCredentialType",
        "nodeCredentialType": "httpHeaderAuth",
        "options": {}
      },
      "id": "52f1351c-594b-4e33-8c50-5318b7de67ff",
      "name": "🔑 Token Copilot",
      "type": "n8n-nodes-base.httpRequest",
      "typeVersion": 4.2,
      "position": [
        880,
        192
      ],
      "credentials": {
        "httpHeaderAuth": {
          "id": "vBwUxlzKrX3oDHyN",
          "name": "GitHub Copilot OAuth Token"
        }
      }
    },
    {
      "parameters": {
        "jsCode": "const data = $input.first().json;\nconst watch_summary = data.watch_summary;\n\nconst prompt = 'Analizza questi contenuti guardati di recente da Martin e restituisci un JSON:\\n' +\n  '{\\n' +\n  '  \"recent_favorites\": [\"titoli\", \"più\", \"visti\"],\\n' +\n  '  \"preferred_genres\": [\"generi\", \"prevalenti\"],\\n' +\n  '  \"watch_patterns\": \"descrizione in italiano dei pattern di visione\",\\n' +\n  '  \"completion_rate\": \"alta|media|bassa (basato su played_pct medio)\",\\n' +\n  '  \"notes\": \"osservazioni utili per l\\'assistente personale\"\\n' +\n  '}\\n\\n' +\n  'Cronologia:\\n' + watch_summary;\n\nreturn [{ json: { prompt } }];"
      },
      "id": "5d4d889c-bda7-4f7e-8873-277f2b8727d5",
      "name": "📝 Build Prompt",
      "type": "n8n-nodes-base.code",
      "typeVersion": 2,
      "position": [
        1104,
        192
      ]
    },
    {
      "parameters": {
        "method": "POST",
        "url": "https://api.githubcopilot.com/chat/completions",
        "sendHeaders": true,
        "headerParameters": {
          "parameters": [
            {
              "name": "Authorization",
              "value": "={{ 'Bearer ' + $('🔑 Token Copilot').first().json.token }}"
            },
            {
              "name": "Content-Type",
              "value": "application/json"
            },
            {
              "name": "Copilot-Integration-Id",
              "value": "vscode-chat"
            },
            {
              "name": "Editor-Version",
              "value": "vscode/1.85.0"
            }
          ]
        },
        "sendBody": true,
        "contentType": "raw",
        "rawContentType": "application/json",
        "body": "={{ JSON.stringify({\"model\":\"gpt-4.1\",\"messages\":[{\"role\":\"system\",\"content\":\"Rispondi SOLO con JSON valido.\"},{\"role\":\"user\",\"content\": $('📝 Build Prompt').first().json.prompt}],\"response_format\":{\"type\":\"json_object\"},\"max_tokens\":1024}) }}",
        "options": {}
      },
      "id": "5135bca5-5f8b-4464-83d1-495ec9855a4a",
      "name": "🤖 GPT-4.1",
      "type": "n8n-nodes-base.httpRequest",
      "typeVersion": 4.2,
      "position": [
        1328,
        192
      ]
    },
    {
      "parameters": {
        "jsCode": "const content = $input.first().json.choices[0].message.content;\nreturn [{ json: JSON.parse(content) }];"
      },
      "id": "8dd4c239-79c2-47de-b898-f0f3d5b00e40",
      "name": "🔍 Parse",
      "type": "n8n-nodes-base.code",
      "typeVersion": 2,
      "position": [
        1552,
        192
      ]
    },
    {
      "parameters": {
        "operation": "executeQuery",
        "query": "INSERT INTO memory_facts (user_id, source, category, subject, detail, expires_at, source_ref)\nVALUES (\n  'martin',\n  'jellyfin',\n  'watch_history',\n  'Cronologia Visione Recente',\n  '{{ $json.detail_json }}'::jsonb,\n  NOW() + INTERVAL '30 days',\n  'watch_history_summary'\n)\nON CONFLICT (user_id, source, source_ref) WHERE source_ref IS NOT NULL\nDO UPDATE SET\n  detail = EXCLUDED.detail,\n  expires_at = EXCLUDED.expires_at,\n  created_at = NOW();",
        "options": {}
      },
      "id": "93ca06bb-5a19-4931-a023-e701b367ce58",
      "name": "💾 PG — Upsert Cronologia",
      "type": "n8n-nodes-base.postgres",
      "typeVersion": 2,
      "position": [
        1904,
        192
      ],
      "credentials": {
        "postgres": {
          "id": "mRqzxhSboGscolqI",
          "name": "Pompeo — PostgreSQL"
        }
      }
    },
    {
      "parameters": {
        "jsCode": "const parsed = $input.first().json;\nconst detailJson = JSON.stringify(parsed).split(\"'\").join(\"''\");\nreturn [{ json: { detail_json: detailJson } }];"
      },
      "id": "599a48c0-dc77-4699-9060-ebccec1cc92c",
      "name": "🔧 Prepara Detail B2",
      "type": "n8n-nodes-base.code",
      "typeVersion": 2,
      "position": [
        1728,
        192
      ]
    }
  ],
  "connections": {
    "⏰ Cron": {
      "main": [
        [
          {
            "node": "🎞️ HTTP Jellyfin",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "🎞️ HTTP Jellyfin": {
      "main": [
        [
          {
            "node": "🔀 Filtra Visti",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "🔀 Filtra Visti": {
      "main": [
        [
          {
            "node": "❓ Ha Visti?",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "❓ Ha Visti?": {
      "main": [
        [
          {
            "node": "🔑 Token Copilot",
            "type": "main",
            "index": 0
          }
        ],
        [
          {
            "node": "⛔ Stop",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "🔑 Token Copilot": {
      "main": [
        [
          {
            "node": "📝 Build Prompt",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "📝 Build Prompt": {
      "main": [
        [
          {
            "node": "🤖 GPT-4.1",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "🤖 GPT-4.1": {
      "main": [
        [
          {
            "node": "🔍 Parse",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "🔍 Parse": {
      "main": [
        [
          {
            "node": "🔧 Prepara Detail B2",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "🔧 Prepara Detail B2": {
      "main": [
        [
          {
            "node": "💾 PG — Upsert Cronologia",
            "type": "main",
            "index": 0
          }
        ]
      ]
    }
  },
  "settings": {
    "executionOrder": "v1",
    "callerPolicy": "workflowsFromSameOwner",
    "availableInMCP": false
  },
  "triggerCount": 1,
  "versionId": "bbcf28d7-652d-4aa9-b2a0-74d5ec29b56c",
  "owner": {
    "type": "personal",
    "projectId": "Hdttz401OqqtObPo",
    "projectName": "Martin Tahiraj <tahiraj.martin@gmail.com>",
    "personalEmail": "tahiraj.martin@gmail.com"
  },
  "parentFolderId": null,
  "isArchived": false
}