Files
Alpha/workflows/K07e4PPANXDkmQsr.json

337 lines
10 KiB
JSON

{
"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
}