{
  "meta": {
    "templateCredsSetupCompleted": false
  },
  "name": "Karaoke instrumental request form with StemSplit AI and Google Drive",
  "nodes": [
    {
      "id": "a1000000-0000-4000-8000-000000000001",
      "name": "Sticky Note - Overview",
      "type": "n8n-nodes-base.stickyNote",
      "position": [
        -480,
        0
      ],
      "parameters": {
        "color": 7,
        "width": 400,
        "height": 600,
        "content": "# Karaoke instrumental request form\n\n## Who it is for\nKaraoke hosts, DJs, music teachers, and community teams who want visitors to request a vocal-free instrumental by email without manual processing.\n\n## What it does\nCollects song details through an n8n form, removes vocals with the [StemSplit](https://stemsplit.io) AI API, uploads the MP3 to Google Drive, and emails the requester a download link.\n\n## How it works\n1. Visitor submits email, song title, and a public audio URL on the form.\n2. The workflow validates the URL and checks the StemSplit credit balance.\n3. StemSplit separates the track and returns an instrumental MP3.\n4. The file uploads to Google Drive and Gmail sends the link to the requester.\n\n## How to use\n1. Connect credentials listed in **Sticky Note - Setup**.\n2. Activate the workflow and copy the Form Trigger **Production URL**.\n3. Test with a short public MP3 and an inbox you control."
      },
      "typeVersion": 1
    },
    {
      "id": "a1000000-0000-4000-8000-000000000002",
      "name": "Sticky Note - Setup",
      "type": "n8n-nodes-base.stickyNote",
      "position": [
        -480,
        640
      ],
      "parameters": {
        "color": 5,
        "width": 380,
        "height": 280,
        "content": "## Setup\n\n1. **StemSplit API** on both StemSplit nodes \u2014 [stemsplit.io/app/settings/api](https://stemsplit.io/app/settings/api)\n2. **Google Drive OAuth2** on **Upload to Google Drive** (choose a folder or keep root)\n3. **Gmail OAuth2** on all three Gmail nodes\n4. Install **n8n-nodes-stemsplit** if it is not already available ([verified integration](https://n8n.io/integrations/stemsplit/))"
      },
      "typeVersion": 1
    },
    {
      "id": "a1000000-0000-4000-8000-000000000003",
      "name": "Section - Form intake",
      "type": "n8n-nodes-base.stickyNote",
      "position": [
        60,
        160
      ],
      "parameters": {
        "color": 4,
        "width": 580,
        "height": 200,
        "content": "## 1. Form intake and validation"
      },
      "typeVersion": 1
    },
    {
      "id": "a1000000-0000-4000-8000-000000000004",
      "name": "Section - Credit check",
      "type": "n8n-nodes-base.stickyNote",
      "position": [
        760,
        80
      ],
      "parameters": {
        "color": 6,
        "width": 340,
        "height": 180,
        "content": "## 2. Credit check"
      },
      "typeVersion": 1
    },
    {
      "id": "a1000000-0000-4000-8000-000000000005",
      "name": "Section - Create and deliver",
      "type": "n8n-nodes-base.stickyNote",
      "position": [
        1200,
        -20
      ],
      "parameters": {
        "color": 3,
        "width": 860,
        "height": 220,
        "content": "## 3. Separate, upload, and email"
      },
      "typeVersion": 1
    },
    {
      "id": "a1000000-0000-4000-8000-000000000006",
      "name": "Section - Error notifications",
      "type": "n8n-nodes-base.stickyNote",
      "position": [
        740,
        240
      ],
      "parameters": {
        "color": 2,
        "width": 640,
        "height": 260,
        "content": "## 4. Error notifications\n\nEmails the requester when the URL is invalid or when StemSplit credits are below 60 seconds."
      },
      "typeVersion": 1
    },
    {
      "id": "a1000000-0000-4000-8000-000000000007",
      "name": "Sticky Note - Google Drive",
      "type": "n8n-nodes-base.stickyNote",
      "position": [
        1680,
        -140
      ],
      "parameters": {
        "color": 5,
        "width": 300,
        "height": 180,
        "content": "## Google Drive\n\nSet a destination folder in **Upload to Google Drive**, or keep the default root. The uploaded file name is derived from the song title submitted on the form."
      },
      "typeVersion": 1
    },
    {
      "id": "a1000000-0000-4000-8000-000000000010",
      "name": "On karaoke form submission",
      "type": "n8n-nodes-base.formTrigger",
      "position": [
        120,
        220
      ],
      "parameters": {
        "options": {
          "path": "karaoke-instrumental-request",
          "respondWithOptions": {
            "values": {
              "respondWith": "text",
              "formSubmittedText": "Thanks! We're creating your instrumental \u2014 check your inbox in a few minutes."
            }
          }
        },
        "formTitle": "Request a karaoke instrumental",
        "formFields": {
          "values": [
            {
              "fieldName": "requesterEmail",
              "fieldType": "email",
              "fieldLabel": "Your email",
              "requiredField": true
            },
            {
              "fieldName": "songTitle",
              "fieldType": "text",
              "fieldLabel": "Song title",
              "placeholder": "e.g. Summer Nights",
              "requiredField": true
            },
            {
              "fieldName": "songUrl",
              "fieldType": "text",
              "fieldLabel": "Song URL",
              "placeholder": "https://example.com/song.mp3",
              "requiredField": true
            }
          ]
        },
        "formDescription": "Submit a public link to your song (MP3, WAV, or FLAC). We'll remove the vocals with StemSplit AI, save the instrumental to Google Drive, and email you the link."
      },
      "typeVersion": 2.2
    },
    {
      "id": "a1000000-0000-4000-8000-000000000011",
      "name": "Normalize form data",
      "type": "n8n-nodes-base.set",
      "position": [
        340,
        220
      ],
      "parameters": {
        "options": {},
        "assignments": {
          "assignments": [
            {
              "id": "b1b1b1b1-1111-4111-8111-bbbbbbbbbbbb",
              "name": "requesterEmail",
              "type": "string",
              "value": "={{ $json.requesterEmail }}"
            },
            {
              "id": "b2b2b2b2-2222-4222-8222-bbbbbbbbbbbb",
              "name": "songTitle",
              "type": "string",
              "value": "={{ $json.songTitle }}"
            },
            {
              "id": "b3b3b3b3-3333-4333-8333-bbbbbbbbbbbb",
              "name": "songUrl",
              "type": "string",
              "value": "={{ ($json.songUrl || '').trim() }}"
            },
            {
              "id": "b4b4b4b4-4444-4444-8444-bbbbbbbbbbbb",
              "name": "safeFileName",
              "type": "string",
              "value": "={{ ($json.songTitle || 'karaoke').replace(/[^a-zA-Z0-9-_ ]/g, '').trim().replace(/\\s+/g, '-') }}-instrumental.mp3"
            }
          ]
        }
      },
      "typeVersion": 3.4
    },
    {
      "id": "a1000000-0000-4000-8000-000000000012",
      "name": "Is song URL valid?",
      "type": "n8n-nodes-base.if",
      "position": [
        560,
        220
      ],
      "parameters": {
        "options": {},
        "conditions": {
          "options": {
            "version": 2,
            "leftValue": "",
            "caseSensitive": true,
            "typeValidation": "strict"
          },
          "combinator": "and",
          "conditions": [
            {
              "id": "c1c1c1c1-1111-4111-8111-cccccccccccc",
              "operator": {
                "type": "string",
                "operation": "startsWith"
              },
              "leftValue": "={{ $json.songUrl }}",
              "rightValue": "https://"
            }
          ]
        }
      },
      "typeVersion": 2.2
    },
    {
      "id": "a1000000-0000-4000-8000-000000000013",
      "name": "StemSplit: check credits",
      "type": "n8n-nodes-stemsplit.stemSplit",
      "position": [
        800,
        120
      ],
      "parameters": {
        "operation": "getBalance"
      },
      "typeVersion": 1
    },
    {
      "id": "a1000000-0000-4000-8000-000000000014",
      "name": "Enough StemSplit credits?",
      "type": "n8n-nodes-base.if",
      "position": [
        1020,
        120
      ],
      "parameters": {
        "options": {},
        "conditions": {
          "options": {
            "version": 2,
            "leftValue": "",
            "caseSensitive": true,
            "typeValidation": "strict"
          },
          "combinator": "and",
          "conditions": [
            {
              "id": "d1d1d1d1-1111-4111-8111-dddddddddddd",
              "operator": {
                "type": "number",
                "operation": "gte"
              },
              "leftValue": "={{ $json.balanceSeconds }}",
              "rightValue": 60
            }
          ]
        }
      },
      "typeVersion": 2.2
    },
    {
      "id": "a1000000-0000-4000-8000-000000000015",
      "name": "StemSplit: create instrumental",
      "type": "n8n-nodes-stemsplit.stemSplit",
      "position": [
        1260,
        40
      ],
      "parameters": {
        "quality": "BEST",
        "operation": "separateStemsWait",
        "sourceUrl": "={{ $('Normalize form data').item.json.songUrl }}",
        "outputType": "INSTRUMENTAL",
        "inputSource": "url",
        "outputFormat": "MP3",
        "timeoutSeconds": 600,
        "additionalOptions": {
          "fileName": "={{ $('Normalize form data').item.json.songTitle }}"
        },
        "pollIntervalSeconds": 5
      },
      "typeVersion": 1
    },
    {
      "id": "a1000000-0000-4000-8000-000000000016",
      "name": "Download instrumental MP3",
      "type": "n8n-nodes-base.httpRequest",
      "position": [
        1500,
        40
      ],
      "parameters": {
        "url": "={{ $json.instrumentalUrl }}",
        "options": {
          "response": {
            "response": {
              "responseFormat": "file",
              "outputPropertyName": "data"
            }
          }
        }
      },
      "typeVersion": 4.2
    },
    {
      "id": "a1000000-0000-4000-8000-000000000017",
      "name": "Upload to Google Drive",
      "type": "n8n-nodes-base.googleDrive",
      "position": [
        1740,
        40
      ],
      "parameters": {
        "name": "={{ $('Normalize form data').item.json.safeFileName }}",
        "driveId": {
          "__rl": true,
          "mode": "list",
          "value": "My Drive"
        },
        "options": {},
        "folderId": {
          "__rl": true,
          "mode": "list",
          "value": "root",
          "cachedResultName": "/ (Root folder)"
        },
        "resource": "file",
        "operation": "upload",
        "inputDataFieldName": "data"
      },
      "typeVersion": 3
    },
    {
      "id": "a1000000-0000-4000-8000-000000000018",
      "name": "Gmail: send download link",
      "type": "n8n-nodes-base.gmail",
      "position": [
        1980,
        40
      ],
      "parameters": {
        "sendTo": "={{ $('Normalize form data').item.json.requesterEmail }}",
        "message": "=Hi,\n\nYour karaoke instrumental for \"{{ $('Normalize form data').item.json.songTitle }}\" is ready.\n\nDownload from Google Drive:\n{{ $json.webViewLink }}\n\nDirect link (if shared):\n{{ $json.webContentLink || $json.webViewLink }}\n\n\u2014 Sent automatically via n8n + StemSplit",
        "options": {},
        "subject": "=Your karaoke instrumental is ready: {{ $('Normalize form data').item.json.songTitle }}",
        "emailType": "text"
      },
      "typeVersion": 2.1
    },
    {
      "id": "a1000000-0000-4000-8000-000000000019",
      "name": "Gmail: invalid URL notice",
      "type": "n8n-nodes-base.gmail",
      "position": [
        800,
        400
      ],
      "parameters": {
        "sendTo": "={{ $('Normalize form data').item.json.requesterEmail }}",
        "message": "=Hi,\n\nWe received your karaoke instrumental request for \"{{ $('Normalize form data').item.json.songTitle }}\", but the song URL was invalid.\n\nPlease submit again with a direct, publicly accessible link to an MP3, WAV, or FLAC file (must start with https://).\n\nURL you provided:\n{{ $('Normalize form data').item.json.songUrl }}",
        "options": {},
        "subject": "=We could not process your karaoke request: {{ $('Normalize form data').item.json.songTitle }}",
        "emailType": "text"
      },
      "typeVersion": 2.1
    },
    {
      "id": "a1000000-0000-4000-8000-00000000001a",
      "name": "Gmail: insufficient credits",
      "type": "n8n-nodes-base.gmail",
      "position": [
        1260,
        280
      ],
      "parameters": {
        "sendTo": "={{ $('Normalize form data').item.json.requesterEmail }}",
        "message": "=Hi,\n\nWe received your request for \"{{ $('Normalize form data').item.json.songTitle }}\", but the StemSplit account does not have enough credits to process the track right now.\n\nPlease try again later or contact the site owner to top up credits at stemsplit.io.\n\nYour song URL (not processed):\n{{ $('Normalize form data').item.json.songUrl }}",
        "options": {},
        "subject": "=Karaoke request paused \u2014 StemSplit credits low",
        "emailType": "text"
      },
      "typeVersion": 2.1
    }
  ],
  "settings": {
    "executionOrder": "v1"
  },
  "connections": {
    "Is song URL valid?": {
      "main": [
        [
          {
            "node": "StemSplit: check credits",
            "type": "main",
            "index": 0
          }
        ],
        [
          {
            "node": "Gmail: invalid URL notice",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "Normalize form data": {
      "main": [
        [
          {
            "node": "Is song URL valid?",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "Upload to Google Drive": {
      "main": [
        [
          {
            "node": "Gmail: send download link",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "StemSplit: check credits": {
      "main": [
        [
          {
            "node": "Enough StemSplit credits?",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "Download instrumental MP3": {
      "main": [
        [
          {
            "node": "Upload to Google Drive",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "Enough StemSplit credits?": {
      "main": [
        [
          {
            "node": "StemSplit: create instrumental",
            "type": "main",
            "index": 0
          }
        ],
        [
          {
            "node": "Gmail: insufficient credits",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "On karaoke form submission": {
      "main": [
        [
          {
            "node": "Normalize form data",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "StemSplit: create instrumental": {
      "main": [
        [
          {
            "node": "Download instrumental MP3",
            "type": "main",
            "index": 0
          }
        ]
      ]
    }
  }
}