rails media file stream accetta la richiesta dell’intervallo di byte attraverso il metodo send_data o send_file

Ho il seguente problema. I suoni sono nascosti dalla cartella pubblica, perché ci sono solo determinati utenti che dovrebbero avere accesso ai file audio. Così ho fatto un certo metodo, che si comporta come un url del suono, ma calcola per primo, se l’utente corrente è autorizzato ad accedere a questo file.

Il file viene inviato dal metodo send_data. Il problema è che io lavoro abbastanza lentamente se funziona anche … Lo sviluppatore del plugin jplayer, che uso per riprodurre il suono, mi ha detto che dovrei essere in grado di accettare richieste dell’intervallo di byte per farlo funzionare correttamente …

Come posso farlo all’interno di un controller di rail inviando il file con send_data o send_file?

Grazie, Markus

Sono stato in grado di servire i file con un certo successo usando send_file. Anche se ho un intoppo, cercare una parte precedente della canzone provoca una nuova richiesta che fa riavviare il brano da 0:00 invece della vera posizione dalla barra di ricerca. Questo è quello che ho lavorato finora per me:

file_begin = 0 file_size = @media.file_file_size file_end = file_size - 1 if !request.headers["Range"] status_code = "200 OK" else status_code = "206 Partial Content" match = request.headers['range'].match(/bytes=(\d+)-(\d*)/) if match file_begin = match[1] file_end = match[1] if match[2] && !match[2].empty? end response.header["Content-Range"] = "bytes " + file_begin.to_s + "-" + file_end.to_s + "/" + file_size.to_s end response.header["Content-Length"] = (file_end.to_i - file_begin.to_i + 1).to_s response.header["Last-Modified"] = @media.file_updated_at.to_s response.header["Cache-Control"] = "public, must-revalidate, max-age=0" response.header["Pragma"] = "no-cache" response.header["Accept-Ranges"]= "bytes" response.header["Content-Transfer-Encoding"] = "binary" send_file(DataAccess.getUserMusicDirectory(current_user.public_token) + @media.sub_path, :filename => @media.file_file_name, :type => @media.file_content_type, :disposition => "inline", :status => status_code, :stream => 'true', :buffer_size => 4096) 

Ecco la mia versione. Io uso gem ‘ogginfo-rb’ per calcolare la durata che è necessaria per servire correttamente i file ogg. ps ho sempre tre formati: wav, mp3, ogg.

 the_file = File.open(file_path) file_begin = 0 file_size = the_file.size file_end = file_size - 1 if request.headers['Range'] status_code = :partial_content match = request.headers['range'].match(/bytes=(\d+)-(\d*)/) if match file_begin = match[1] file_end = match[1] if match[2] and not match[2].empty? end response.headers['Content-Range'] = "bytes #{file_begin}-#{file_end.to_i + (match[2] == '1' ? 1 : 0)}/#{file_size}" else status_code = :ok end response.headers['Content-Length'] = (file_end.to_i - file_begin.to_i + 1).to_s response.headers['Last-Modified'] = the_file.mtime response.headers['Cache-Control'] = 'public, must-revalidate, max-age=0' response.headers['Pragma'] = 'no-cache' response.headers['Accept-Ranges'] = 'bytes' response.headers['Content-Transfer-Encoding'] = 'binary' require 'ogginfo-rb' ogginfo = Ogg::Info::open(the_file.path.gsub(/.mp3|.wav/,'.ogg')) duration = ogginfo.duration.to_f response.headers['Content-Duration'] = duration response.headers['X-Content-Duration'] = duration send_file file_path, filename: "#{call.id}.#{ext}", type: Mime::Type.lookup_by_extension(ext), status: status_code, disposition: 'inline', stream: 'true', buffer_size: 32768 

Un’altra versione modificata – stavo cercando di scaricare un file zip come contenuto binario e questo è quello che ha funzionato per me –

  def byte_range_response (request, response, content) file_begin = 0 file_size = content.bytesize file_end = file_size - 1 status_code = '206 Partial Content' match = request.headers['range'].match(/bytes=(\d+)-(\d*)/) if match file_begin = match[1] file_end = match[2] if match[2] && !match[2].empty? end content_length = file_end.to_i - file_begin.to_i + 1 response.header['Content-Range'] = 'bytes ' + file_begin.to_s + '-' + file_end.to_s + '/' + file_size.to_s response.header['Content-Length'] = content_length.to_s response.header['Cache-Control'] = 'public, must-revalidate, max-age=0' response.header['Pragma'] = 'no-cache' response.header['Accept-Ranges']= 'bytes' response.header['Content-Transfer-Encoding'] = 'binary' send_data get_partial_content(content, content_length, file_begin.to_i), type: 'application/octet-stream', status: status_code end def get_partial_content(content, content_length, offset) test_file = Tempfile.new(['test-file', '.zip']) test_file.puts(content) partial_content = IO.binread(test_file.path, content_length, offset) test_file.close test_file.unlink partial_content end