1

I understand that Heroku dynos are ephemeral and files cannot be stored between requests. I have a Flask app that should get an MP3 from Spotify, pass it to LibROSA for analysis, then return a visualization.

I have a script that works locally to download the file with urllib.urlopen, save it to a file, then load that file with librosa.load. However, I can't seem to load the file from the filesystem on Heroku. How can I load the downloaded file when I don't control the filesystem?

song_url = "https://p.scdn.co/mp3-preview/8e29d103eba74b5cef8600722fff3c491e37fc9a.mp3"
sample_30s = urlopen(song_url)
mp3_path = os.path.join(os.path.dirname(__file__), 'static/data/temp.mp3')

output = open(mp3_path, 'wb')
output.write(sample_30s.read())

y, sr = librosa.load(mp3_filepath)
davidism
  • 121,510
  • 29
  • 395
  • 339
Jasper Croome
  • 93
  • 1
  • 6

1 Answers1

3

librosa.load can take a file-like object, as an alternative to a file path. The object returns by urlopen is file-like. It can be passed directly to librosa.

from urllib.request import urlopen
import librosa

with urlopen(song_url) as response:
    y, sr = librosa.load(response)

However, librosa only supports loading MP3 files from the filesystem. You can see what formats are supported for file-like objects with soundfile.available_formats(). Either obtain the file in a different format, or use a library such as pydub to convert it to WAV.

import io
from urllib.request import urlopen
import librosa
import pydub

wav = io.BytesIO()

with urlopen(mp3_url) as r:
    r.seek = lambda *args: None  # allow pydub to call seek(0)
    pydub.AudioSegment.from_file(r).export(wav, "wav")

wav.seek(0)
y, sr = librosa.load(wav)
davidism
  • 121,510
  • 29
  • 395
  • 339