user2348114
user2348114

Reputation: 167

Need to write .wav files in Django app, but can't on Heroku (or S3)

I've got a Django application where users upload a .wav file, the backend does some processing, then spits out a processed .wav file for download. Upon deploying to Heroku, I've discovered that I can't write wav files to Heroku's "ephemeral file system" (locally, am writing .wav files to myapp/media).

The SO consensus is that you should use Amazon's S3 to store static files. I'm fine with that. The problem is, the python function I'm using (and all the other ones I've looked at), need a file path to write the file to. My code that writes the .wav files:

output_path = "..../some_folder"

output_wav = wave.open (output_path, "w")
output_wav.setparams((nchannels, sampwidth, framerate, nframes, comptype,  compname))
output_wav.writeframes(scaled_e)

I've researched boto, django-storages, and Heroku's Direct to S3 File Uploads in Python. However, these solutions appear to assume you already have a file to point to (exactly what I can't create without a path I can write to).

The tmp folder the Cedar stack makes available could work for my purposes (though it's not an ideal solution due to its instability), but I can't even find on Google how one would use that in a python/Django app...

Django/Heroku noob here going in circles and going crazy! Any help greatly appreciated.

Upvotes: 4

Views: 596

Answers (3)

Krishna Srinivas
Krishna Srinivas

Reputation: 1700

You can directly create objects on S3 with contents from memory using minio-py library like this:

import os
from minio import Minio

# find out your s3 end point here:
# http://docs.aws.amazon.com/general/latest/gr/rande.html#s3_region

client = Minio('https://<your-s3-endpoint>',
               access_key='YOUR-ACCESSKEYID',
               secret_key='YOUR-SECRETACCESSKEY')

client.put_object('my-bucket', 'my_file_name', <sizeofdata>, <data>)

Upvotes: 2

user2348114
user2348114

Reputation: 167

OK, I was able to get this working by:

  1. Creating a regular Python file object using Python's open() function.
  2. Writing a .wav file to said object using wav().
  3. Saving the file to S3 using the set_contents_from_file() function.

My working (locally and on Heroku) code:

output_filename = "my_file_name"
output_file = open(output_filename, "w+")
k = Key(bucket)
k.key = output_filename
k.set_contents_from_file(output_file, rewind=True)

Notes:

  • I needed to use 'w+' mode when opening the file.
  • I needed to use 'rewind=True' when writing to S3.
  • If there's a path in output_filename, that path gets recreated in my S3 bucket.
  • The output .wav file is written into the app root of my Django app before uploading to S3.

Upvotes: 2

sponrad
sponrad

Reputation: 690

You may be able to open an object from s3 with boto and read it to memory and then make the wave operation from memory like in this answer, How to play WAV data right from memory?:

import wave, StringIO

file_via_s3 = Key(objectkey).get_contents_as_string()  #via boto
output_path = StringIO(file_via_s3)
output_wav = wave.open(output_path, "w")
output_wav.setparams((nchannels, sampwidth, framerate, nframes, comptype,  compname))
output_wav.writeframes(scaled_e)
...
#save it back to s3
Key(objectkey).set_contents_from_string(output_wav)

Upvotes: 1

Related Questions