我目前正在尝试使用Python提供MP3文件。问题是我只能播放一次MP3。之后媒体控制停止响应,我需要完全重新加载页面才能再次收听MP3。 (在Chrome中测试)
问题:运行下面的脚本,在我的浏览器上输入http://127.0.0.1/test.mp3将返回一个MP3文件,只有刷新页面才可以重播
注意:
将页面保存为HTML并直接使用Chrome加载(不使用Python服务器)会使问题消失。
使用Apache提供文件可以解决问题,但这是过度的:我想使脚本非常易于使用而不需要安装Apache 。
以下是我使用的代码:
import string
import os
import urllib
import socket
# Setup web server import string,cgi,time
import string,cgi,time
from os import curdir, sep
from BaseHTTPServer import BaseHTTPRequestHandler, HTTPServer
import hashlib
class MyHandler(BaseHTTPRequestHandler):
def do_GET(self):
try:
# serve mp3 files
if self.path.endswith(".mp3"):
print curdir + sep + self.path
f = open(curdir + sep + self.path, 'rb')
st = os.fstat( f.fileno() )
length = st.st_size
data = f.read()
md5 = hashlib.md5()
md5.update(data)
md5_key = self.headers.getheader('If-None-Match')
if md5_key:
if md5_key[1:-1] == md5.hexdigest():
self.send_response(304)
self.send_header('ETag', '"{0}"'.format(md5.hexdigest()))
self.send_header('Keep-Alive', 'timeout=5, max=100')
self.end_headers()
return
self.send_response(200)
self.send_header('Content-type', 'audio/mpeg')
self.send_header('Content-Length', length )
self.send_header('ETag', '"{0}"'.format(md5.hexdigest()))
self.send_header('Accept-Ranges', 'bytes')
self.send_header('Last-Modified', time.strftime("%a %d %b %Y %H:%M:%S GMT",time.localtime(os.path.getmtime('test.mp3'))))
self.end_headers()
self.wfile.write(data)
f.close()
return
except IOError:
self.send_error(404,'File Not Found: %s' % self.path)
from SocketServer import ThreadingMixIn
class ThreadedHTTPServer(ThreadingMixIn, HTTPServer):
pass
if __name__ == "__main__":
try:
server = ThreadedHTTPServer(('', 80), MyHandler)
print 'started httpserver...'
server.serve_forever()
except KeyboardInterrupt:
print '^C received, shutting down server'
server.socket.close()
答案 0 :(得分:2)
如果您愿意将其作为wsgi app运行(我建议使用vanilla CGI获得任何真正的可扩展性),您可以使用我在下面提供的脚本。
我冒昧地修改你的来源...这适用于上面的假设..顺便说一句,你应该花一些时间检查你的html是否合理合规......这将有助于确保你获得更好的跨浏览器兼容性...原始版本没有<head>
或<body>
标签...我的(下方)是严格的原型html,可以改进。
要运行它,你只需在你的shell中运行python可执行文件并在8080上冲到机器的ipaddress。如果你是为生产网站做这个,我们应该使用lighttpd或apache来提供文件,但是这只是供实验室使用,嵌入式wsgi参考服务器应该没问题。如果要在apache或lighttpd中运行,请替换文件底部的WSGIServer
行。
from webob import Request
import re
import os
import sys
####
#### Run with:
#### twistd -n web --port 8080 --wsgi mp3.mp3_app
_MP3DIV = """<div id="musicHere"></div>"""
_MP3EMBED = """<embed src="mp3/" loop="true" autoplay="false" width="145" height="60"></embed>"""
_HTML = '''<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN" "http://www.w3.org/TR/html4/loose.dtd"><html><head></head><body> Hello %s %s</body></html> ''' % (_MP3DIV, _MP3EMBED)
def mp3_html(environ, start_response):
"""This function will be mounted on "/" and refer the browser to the mp3 serving URL."""
start_response('200 OK', [('Content-Type', 'text/html')])
return [_HTML]
def mp3_serve(environ, start_response):
"""Serve the MP3, one chunk at a time with a generator"""
file_path = "/file/path/to/test.mp3"
mimetype = "application/x-mplayer2"
size = os.path.getsize(file_path)
headers = [
("Content-type", mimetype),
("Content-length", str(size)),
]
start_response("200 OK", headers)
return send_file(file_path, size)
def send_file(file_path, size):
BLOCK_SIZE = 4096
fh = open(file_path, 'r')
while True:
block = fh.read(BLOCK_SIZE)
if not block:
fh.close()
break
yield block
def _not_found(environ,start_response):
"""Called if no URL matches."""
start_response('404 NOT FOUND', [('Content-Type', 'text/plain')])
return ['Not Found']
def mp3_app(environ,start_response):
"""
The main WSGI application. Dispatch the current request to
the functions andd store the regular expression
captures in the WSGI environment as `mp3app.url_args` so that
the functions from above can access the url placeholders.
If nothing matches call the `not_found` function.
"""
# map urls to functions
urls = [
(r'^$', mp3_html),
(r'mp3/?$', mp3_serve),
]
path = environ.get('PATH_INFO', '').lstrip('/')
for regex, callback in urls:
match = re.search(regex, path)
if match is not None:
# assign http environment variables...
environ['mp3app.url_args'] = match.groups()
return callback(environ, start_response)
return _not_found(environ, start_response)
从保存mp3.py的目录中使用:twistd -n web --port 8080 --wsgi mp3.mp3_app
从bash shell运行(或者只将mp3.py放在$PYTHONPATH
中的某处)。
现在冲到外部ip(即http://some.ip.local:8080/),它将直接为mp3服务。
我尝试运行原来的应用程序,因为它已经发布了,并且无法获取它来源mp3,它在我的Linux中出错了...
答案 1 :(得分:2)
BaseServer
是单线程的,您应该使用ForkingMixIn
或ThreadingMixIn
来支持多个连接。
例如替换行:
server = HTTPServer(('', 80), MyHandler)
带
from SocketServer import ThreadingMixIn
class ThreadedHTTPServer(ThreadingMixIn, HTTPServer):
pass
server = ThreadedHTTPServer(('', 80), MyHandler)