Hello everyone, I'm currently developing an online musicplayer for private use ( in fact it's an simple webinterface, which allows friends of mine to play and download self produced music files from my private server in a user friendly way ). The application is build as flask app using jplayer and some simple javascript controls on the client-side. Currently I'm extending the app by adding a sqlalchemy database for the files, but there's still one major problem left: Jplayer doesn't display the duration time correctly ( in fact, the duration time increases until the file is fully transmitted, which is very annoying ). After a little bit of investigation I found out, that there is a byte range request, which seems to be unsupported. I can see the range request being transmitted in the chrome debugger, but there is no answer from my server. Now I'm not shure how to answer the request. I think I have to filter for the range request in the view function ( perhaps by look for the request.headers["Range"] ) and then raise a special response, but as I found nothing about this in the doc I have no idea how to alter the response object. I found out that Werkzeug seems to support manipulation of the range header: http://werkzeug.pocoo.org/docs/datastructures/?highlight=range#werkzeug.datastructures.Range ... but how do I deal with it? Any help appreciated Christoph
As I don't want to leave the question unanswered in the mailinglist,
I'll post my own solution. Perhaps it will help someone, who has a
similiar problem.
In fact I found a php function in the jplayer doc
(https://groups.google.com/forum/#!msg/jplayer/nSM2UmnSKKA/bC-l3k0pCPMJ)
to solve my problem, so I rewrote it in python.
from flask import Response, request
from werkzeug.datastructures import Headers
from time import time
from re import findall
def send_file( musicFile , cachetimout, stream=True):
headers = Headers()
headers.add('Content-Disposition',
'attachment',filename=musicFile.filename)
headers.add('Content-Transfer-Encoding','binary')
status = 200
size = getsize(musicFile.path)
begin=0;
end=size-1;
if request.headers.has_key("Range") and rangerequest:
status = 206
headers.add('Accept-Ranges','bytes')
ranges=findall(r"\d+", request.headers["Range"])
begin = int( ranges[0] )
if len(ranges)>1:
end=int( ranges[1] )
headers.add('Content-Range','bytes %s-%s/%s' %
(str(begin),str(end),str(end-begin)) )
headers.add('Content-Length',str((end-begin)+1))
#Add mimetype
mimetypes = {u"mp3":"audio/mpeg",u"ogg":"audio/ogg"}
if stream==True:
mimetype = mimetypes[musicFile.filetype]
else:
mimetype = "application/octet-stream"
response = Response( file(musicFile.path), status=status,
mimetype=mimetype, headers=headers, direct_passthrough=True)
#enable browser file caching with etags
response.cache_control.public = True
response.cache_control.max_age = int(cachetimout)
response.last_modified = int(musicFile.changetime)
response.expires=int( time() + int(cachetimout) )
response.set_etag('%s%s' % ( musicFile.id,musicFile.changetime ))
response.make_conditional(request)
return response
Can I ask why you are using send_file instead of just letting your front end server deliver it? You can keep all the file information in the database (url, title, etc) but don't have flask deliver the file itself. Let me know if I'm missing something. On Sun, Oct 23, 2011 at 9:53 PM, Christoph Weyer <crazzyman2526@gmx.de> wrote: > As I don't want to leave the question unanswered in the mailinglist, > I'll post my own solution. Perhaps it will help someone, who has a > similiar problem. > In fact I found a php function in the jplayer doc > (https://groups.google.com/forum/#!msg/jplayer/nSM2UmnSKKA/bC-l3k0pCPMJ) > to solve my problem, so I rewrote it in python. > > > from flask import Response, request > from werkzeug.datastructures import Headers > from time import time > from re import findall > > def send_file( musicFile , cachetimout, stream=True): > headers = Headers() > headers.add('Content-Disposition', > 'attachment',filename=musicFile.filename) > headers.add('Content-Transfer-Encoding','binary') > > status = 200 > size = getsize(musicFile.path) > begin=0; > end=size-1; > > if request.headers.has_key("Range") and rangerequest: > status = 206 > headers.add('Accept-Ranges','bytes') > ranges=findall(r"\d+", request.headers["Range"]) > begin = int( ranges[0] ) > if len(ranges)>1: > end=int( ranges[1] ) > headers.add('Content-Range','bytes %s-%s/%s' % > (str(begin),str(end),str(end-begin)) ) > > headers.add('Content-Length',str((end-begin)+1)) > > #Add mimetype > mimetypes = {u"mp3":"audio/mpeg",u"ogg":"audio/ogg"} > if stream==True: > mimetype = mimetypes[musicFile.filetype] > else: > mimetype = "application/octet-stream" > > response = Response( file(musicFile.path), status=status, > mimetype=mimetype, headers=headers, direct_passthrough=True) > > #enable browser file caching with etags > response.cache_control.public = True > response.cache_control.max_age = int(cachetimout) > response.last_modified = int(musicFile.changetime) > response.expires=int( time() + int(cachetimout) ) > response.set_etag('%s%s' % ( musicFile.id,musicFile.changetime )) > response.make_conditional(request) > > return response >
I think you aren't missing something... I thought abour serving the files directly by the server, but before using this feature I wanted the app working by itself... and I didn't want to give up early as I thought that this has to work... so it was more a learning exercise if you want so ;) On 10/24/2011 03:40 AM, Adam Patterson wrote: > Can I ask why you are using send_file instead of just letting your > front end server deliver it? You can keep all the file information in > the database (url, title, etc) but don't have flask deliver the file > itself. Let me know if I'm missing something.