{
  "nodes": [
    {
      "id": "195edaa5-5e07-46d5-b1c6-96f1b1a8a42c",
      "name": "Schedule Trigger",
      "type": "n8n-nodes-base.scheduleTrigger",
      "position": [
        -128,
        288
      ],
      "parameters": {
        "rule": {
          "interval": [
            {
              "triggerAtHour": 7
            }
          ]
        }
      },
      "typeVersion": 1.2
    },
    {
      "id": "0f850e79-b5d8-47ea-b9ca-127decc062c8",
      "name": "Variables",
      "type": "n8n-nodes-base.set",
      "position": [
        96,
        288
      ],
      "parameters": {
        "options": {},
        "assignments": {
          "assignments": [
            {
              "id": "478e44fb-f945-483b-8dc3-bad606febefe",
              "name": "jellyfin_user_id",
              "type": "string",
              "value": ""
            },
            {
              "id": "c6528b2e-4a52-4390-958d-8c914639f794",
              "name": "jellyfin_url",
              "type": "string",
              "value": ""
            },
            {
              "id": "fda395be-f579-4c4a-a1d7-f5ba0172cdaa",
              "name": "transmission_url",
              "type": "string",
              "value": ""
            }
          ]
        }
      },
      "typeVersion": 3.4
    },
    {
      "id": "7d7af74c-35e8-4a6b-bc72-37af911b9aab",
      "name": "Jellyfin: get items",
      "type": "n8n-nodes-base.httpRequest",
      "position": [
        352,
        0
      ],
      "parameters": {
        "url": "={{ $('Variables').first().json.jellyfin_url }}/Users/{{ $('Variables').first().json.jellyfin_user_id }}/Items",
        "options": {},
        "sendQuery": true,
        "authentication": "genericCredentialType",
        "genericAuthType": "httpHeaderAuth",
        "queryParameters": {
          "parameters": [
            {
              "name": "Recursive",
              "value": "true"
            },
            {
              "name": "IncludeItemTypes",
              "value": "Movie,Episode"
            },
            {
              "name": "Filters",
              "value": "=IsPlayed"
            }
          ]
        }
      },
      "typeVersion": 4.2
    },
    {
      "id": "7225f31f-9ccc-4b37-a2ba-69c60d489af0",
      "name": "Jellyfin: delete item",
      "type": "n8n-nodes-base.httpRequest",
      "onError": "continueRegularOutput",
      "position": [
        576,
        0
      ],
      "parameters": {
        "url": "={{ $('Variables').first().json.jellyfin_url }}/Items/{{ $json.media_id }}",
        "method": "DELETE",
        "options": {},
        "authentication": "genericCredentialType",
        "genericAuthType": "httpHeaderAuth"
      },
      "retryOnFail": false,
      "typeVersion": 4.2
    },
    {
      "id": "88bb2629-140b-4c53-8872-41ee5aa101cf",
      "name": "Jellyfin: refresh library",
      "type": "n8n-nodes-base.httpRequest",
      "position": [
        800,
        0
      ],
      "parameters": {
        "url": "={{ $('Variables').first().json.jellyfin_url }}/Library/Refresh",
        "method": "POST",
        "options": {},
        "authentication": "genericCredentialType",
        "genericAuthType": "httpHeaderAuth"
      },
      "typeVersion": 4.2
    },
    {
      "id": "bf8fb108-e779-442e-b69c-c66aa22990e8",
      "name": "Get session id",
      "type": "n8n-nodes-base.httpRequest",
      "onError": "continueRegularOutput",
      "position": [
        320,
        384
      ],
      "parameters": {
        "url": "={{ $('Variables').first().json.transmission_url }}/transmission/rpc",
        "method": "POST",
        "options": {},
        "jsonBody": "{\n  \"method\": \"torrent-get\",\n  \"arguments\": {\n    \"fields\": [\n      \"id\",\n      \"name\",\n      \"status\"\n    ]\n  }\n}",
        "sendBody": true,
        "sendHeaders": true,
        "specifyBody": "json",
        "authentication": "genericCredentialType",
        "genericAuthType": "httpBearerAuth",
        "headerParameters": {
          "parameters": [
            {}
          ]
        }
      },
      "credentials": {
        "httpBearerAuth": {
          "name": "<your credential>"
        }
      },
      "typeVersion": 4.2
    },
    {
      "id": "f7249522-beab-4189-9904-3250f5196107",
      "name": "Extract session id",
      "type": "n8n-nodes-base.set",
      "position": [
        544,
        384
      ],
      "parameters": {
        "options": {},
        "assignments": {
          "assignments": [
            {
              "id": "7eb6904c-01fc-42dc-979e-4d20414d37de",
              "name": "sessionId",
              "type": "string",
              "value": "={{ $json.error.message.split('<code>')[1].split('</code>')[0].split(': ')[1] }}"
            }
          ]
        }
      },
      "typeVersion": 3.4
    },
    {
      "id": "8a0a0167-0b57-4ef3-bdf0-4d1269748485",
      "name": "Check all torrents",
      "type": "n8n-nodes-base.httpRequest",
      "onError": "continueErrorOutput",
      "position": [
        768,
        384
      ],
      "parameters": {
        "url": "={{ $('Variables').first().json.transmission_url }}/transmission/rpc",
        "method": "POST",
        "options": {},
        "jsonBody": "{\n  \"method\": \"torrent-get\",\n  \"arguments\": {\n    \"fields\": [\n      \"id\",\n      \"name\",\n      \"status\"\n    ]\n  }\n}",
        "sendBody": true,
        "sendHeaders": true,
        "specifyBody": "json",
        "headerParameters": {
          "parameters": [
            {
              "name": "X-Transmission-Session-Id",
              "value": "={{ $json.sessionId }}"
            }
          ]
        }
      },
      "typeVersion": 4.2
    },
    {
      "id": "42c2afac-24de-445a-95fa-372d44233110",
      "name": "Split Out",
      "type": "n8n-nodes-base.splitOut",
      "position": [
        992,
        384
      ],
      "parameters": {
        "options": {},
        "fieldToSplitOut": "arguments.torrents"
      },
      "typeVersion": 1
    },
    {
      "id": "e324d9a5-9795-4521-8cdc-a2d78a710ccd",
      "name": "If torrent transferred to Jellyfin",
      "type": "n8n-nodes-base.if",
      "position": [
        1216,
        384
      ],
      "parameters": {
        "options": {},
        "conditions": {
          "options": {
            "version": 2,
            "leftValue": "",
            "caseSensitive": true,
            "typeValidation": "strict"
          },
          "combinator": "and",
          "conditions": [
            {
              "id": "11fe9b7b-6a0f-4ab7-a06c-9098e68c0c1b",
              "operator": {
                "type": "number",
                "operation": "equals"
              },
              "leftValue": "={{ $json.status }}",
              "rightValue": 6
            }
          ]
        }
      },
      "typeVersion": 2.2
    },
    {
      "id": "3acf8a6e-eefa-4ee0-aa82-c369e824772f",
      "name": "Delete torrent",
      "type": "n8n-nodes-base.httpRequest",
      "position": [
        1440,
        384
      ],
      "parameters": {
        "url": "={{ $('Variables').first().json.transmission_url }}/transmission/rpc",
        "method": "POST",
        "options": {},
        "jsonBody": "={ \"method\": \"torrent-remove\", \"arguments\": { \"ids\": [{{ $json.id }}], \"delete-local-data\": true } }",
        "sendBody": true,
        "sendHeaders": true,
        "specifyBody": "json",
        "headerParameters": {
          "parameters": [
            {
              "name": "X-Transmission-Session-Id",
              "value": "={{ $('Extract session id').item.json.sessionId }}"
            }
          ]
        }
      },
      "typeVersion": 4.2
    },
    {
      "id": "4296b10e-a8fb-440e-ae97-2e79f39e8d04",
      "name": "Overview",
      "type": "n8n-nodes-base.stickyNote",
      "position": [
        -960,
        -304
      ],
      "parameters": {
        "width": 776,
        "height": 924,
        "content": "## \ud83e\uddf9 Jellyfin & Transmission daily clean-up\n\n**Who is this for?**\nAnyone self-hosting Jellyfin + Transmission who wants watched movies and episodes automatically deleted from their library and the originating torrents removed \u2014 no manual housekeeping needed.\n\n**What it does**\nEvery morning at 07:00 this workflow:\n- Deletes all *watched* movies and episodes from Jellyfin\n- Refreshes the Jellyfin library so the UI stays clean\n- Removes all *seeding-complete* torrents (status 6) from Transmission, including their local data\n\nBoth branches run in parallel from the same trigger.\n\n---\n\n### \u2699\ufe0f How it works\n1. **Schedule Trigger** fires daily at 07:00\n2. **Variables** node holds your Jellyfin URL, user ID, and Transmission URL \u2014 edit these before activating\n3. **Jellyfin branch**: fetches all played Movies & Episodes \u2192 deletes each one \u2192 refreshes library\n4. **Transmission branch**: performs an initial request to obtain the CSRF session ID \u2192 re-requests with the session ID to list all torrents \u2192 filters for seeding-complete torrents (status = 6) \u2192 removes them with local data\n\n---\n\n### \ud83d\udee0 Setup\n1. **Jellyfin API key** \u2014 create one in Jellyfin \u2192 Dashboard \u2192 API Keys and add it as an *HTTP Header Auth* credential (`X-Emby-Token: <key>`)\n2. **Transmission** \u2014 add a *Bearer Token* HTTP credential for your Transmission instance\n3. In the **Variables** node, fill in:\n   - `jellyfin_url` \u2014 e.g. `http://192.168.1.10:8096`\n   - `jellyfin_user_id` \u2014 find it in Jellyfin \u2192 Dashboard \u2192 Users\n   - `transmission_url` \u2014 e.g. `http://192.168.1.10:9091`\n4. Activate the workflow"
      },
      "typeVersion": 1
    },
    {
      "id": "113df971-267b-49f2-b8cf-933ad7b6fa72",
      "name": "Section - Jellyfin",
      "type": "n8n-nodes-base.stickyNote",
      "position": [
        288,
        -112
      ],
      "parameters": {
        "color": 5,
        "width": 724,
        "height": 280,
        "content": "### \ud83c\udfac Jellyfin: delete watched items & refresh library"
      },
      "typeVersion": 1
    },
    {
      "id": "14e12c91-e75d-4c9d-b8fc-15a09f369334",
      "name": "Section - Transmission",
      "type": "n8n-nodes-base.stickyNote",
      "position": [
        928,
        288
      ],
      "parameters": {
        "color": 4,
        "width": 700,
        "height": 280,
        "content": "### \ud83c\udf0a Transmission: remove completed torrents (status = 6)"
      },
      "typeVersion": 1
    }
  ],
  "connections": {
    "Split Out": {
      "main": [
        [
          {
            "node": "If torrent transferred to Jellyfin",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "Variables": {
      "main": [
        [
          {
            "node": "Jellyfin: get items",
            "type": "main",
            "index": 0
          },
          {
            "node": "Get session id",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "Get session id": {
      "main": [
        [
          {
            "node": "Extract session id",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "Schedule Trigger": {
      "main": [
        [
          {
            "node": "Variables",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "Check all torrents": {
      "main": [
        [
          {
            "node": "Split Out",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "Extract session id": {
      "main": [
        [
          {
            "node": "Check all torrents",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "Jellyfin: get items": {
      "main": [
        [
          {
            "node": "Jellyfin: delete item",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "Jellyfin: delete item": {
      "main": [
        [
          {
            "node": "Jellyfin: refresh library",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "If torrent transferred to Jellyfin": {
      "main": [
        [
          {
            "node": "Delete torrent",
            "type": "main",
            "index": 0
          }
        ]
      ]
    }
  }
}