Large Recording Uploads to Amazon S3
In 2024, one customer needed a way for global teams to send in finished recordings, organized by series and episode. Many of the team members don’t speak English as a first language, and each recording can run to several gigabytes. I built a one-page web app for it. A team fills in a form, drops in their files and clicks Upload, and the recordings land in the customer’s Amazon S3 bucket. The files go straight from the browser to S3, so the web server never handles a byte of them.
What It Does
- No accounts. Teams don’t need a login or an FTP client. Five numbered steps on the page take them through the form, so they never need a manual.
- A language picker. It autocompletes from about 25 languages the teams use, many of them spoken by small communities. Teams can also type in a language that isn’t on the list.
- Titles in two languages. Every series and episode has an English title. When the language isn’t English, the form also asks for the title in that language, labeled with that language’s name.
- Many episodes at once. A team sets how many episodes they’re sending, and a card appears for each one, with its own drop zone for its file.
- Checks before anything uploads. Missing fields, an episode without a file, and the same file picked for two episodes all show in one list, so teams can fix everything in a single pass.
- Up to 10 GB per recording, straight to S3. The browser sends each file to S3 as a multipart upload in 5 MB pieces. The web server only gives out short-lived signed links, so a 10 GB upload costs it almost no bandwidth or disk.
- Built for slow connections. Each piece retries on its own, so a weak connection doesn’t restart the whole upload. If an upload fails anyway, the app cancels the partial upload on S3, so unfinished data doesn’t pile up storage charges.
- Files arrive organized. Teams can name their files anything. The server renames each one to a standard format and files it by language and series. Every batch also comes with a JSON file describing the series and its episodes (English and local titles, episode order, original and new filenames) for whoever processes the files next.
- Kept to its own folder. Teams can’t see or download files other teams have sent. File names are cleaned up, and the server only works inside a dedicated folder, so a crafted request can’t write anywhere else in the bucket.
The page uses Angular and Angular Material, with Dropzone.js for drag-and-drop and chunking. The only server code is a single PHP script using the AWS SDK. There’s no database and no framework to keep upgraded, so hosting it means copying a folder to any PHP server.
Its Limits
Anyone with the link can upload. Keeping the link unpublished is the access control, which keeps things easy for teams who would struggle with logins. It’s still a risk: an open upload form lets strangers put malicious files in your bucket, and run up your bill for storage.
To limit the damage, the PHP script has its own AWS user with a strict IAM policy that allows nothing but uploads, and bucket versioning means any overwritten file can be restored.
Where It Is Now
It’s still in use, and received over 1 TB of recordings in its first two years. The only maintenance it has needed came when the customer received its first file over 5 GB. AWS limits POST uploads to 5 GB, so I switched the uploads from POST to PUT.