ComposeWithMe

Add Your Track (File Upload)

Name a track, pick a file, upload

Overview

The primary way to add a track: name it, pick a local audio file (WAV, MP3, AIFF, M4A, OGG, FLAC), upload. Works the same regardless of which storage backend the song uses — see Storage Backends for what actually happens on upload.

How it works

  • A track name is required before the file input is enabled (trackName.trim()) — this is what the uploaded filename gets slugified to, not the original filename.
  • uploadTrackFile() in src/lib/trackUpload.ts is the single shared upload path — it's also used by GarageBand import and mic recording, so all three entry points hit the same GitHub/Blob branching logic and never diverge.
  • On success, onTracksChanged() triggers a re-fetch of the live track listing (no local caching — see the storage backends doc) and the form resets (track name cleared, file input cleared).

iPhone / Voice Memos note

iOS sandboxes Voice Memos recordings inside that app's own container — they are not visible to Safari's file picker until manually exported. A help note in the upload panel tells users to open the recording in Voice Memos, tap Share → Save to Files, then use "Choose file" here. The alternative is recording directly in the browser instead — see In-Browser Mic Recording, which was added specifically to route around this.

Key files

FileRole
src/components/MultiTrackPlayer.tsxUpload panel UI (track name input, file picker)
src/lib/trackUpload.tsuploadTrackFile() — shared upload path, slugifyTrackName()

Limitations / notes

  • No drag-and-drop — file selection only.
  • No upload progress bar beyond a short status string (Authorizing… / Uploading… etc.) — no percentage/byte progress.
  • Only the song's owner can actually upload — enforced server-side (onBeforeGenerateToken in /api/blob/upload, and the GitHub token lookup being scoped to the requesting user). The upload panel itself isn't hidden or disabled for non-owner viewers, though, so a signed-in collaborator without upload rights sees the same "Choose file"/"Record" controls and only finds out via a failed request.