自製音樂播放器…好像很簡單?with Django Stream Response
<audio src="<path>/<file.mp3>" controls></audio>
寫完了!下課!
但如果要用 stream 播放 + 自製播放介面?
以下紀錄一下卡關的問題,如果你的 case 跟我一樣
- 檔案放在 aws s3
- 使用 django
- 不想直接把檔案 url 坎在 html 內 (保護檔案意味)
問題 1:Django 可以回傳 Stream Response?
按照 巨人的肩膀(StackOverflow) 的指示
我們知道 Django 有一個 Response Class 叫做StreamingHttpResponse
# code section 1 #
import requests
from django.http import **StreamingHttpResponse
...
def post(self, request, *args, **kwargs):
r = requests.get(url, stream=True)
response = StreamingHttpResponse(streaming_content=r)
問題 2:但我不想要讓 User 可以直接連這個 url ?
FireFox 透過 <audio></audio>
取得檔案時 header 會帶HTTP_ACCEPT_ENCODING
Chrome/Safari 則是會帶 HTTP_ACCEPT
這個關鍵字
內容則分別是 audio
與 identity
#FireFox
request.META.get('HTTP_ACCEPT_ENCODING') # audio
#Chrome/Safari
request.META.get('HTTP_ACCEPT') # identity
其他用網址列直接開的都可以由此判斷直接轉到 404
當然 此方式也只能防君子不防小人
問題 3: Safari 無法播放 Stream url 的 src?
其實可以,只有當 src 是 Stream url 的時候
Safari 不接受最初的一行式的寫法,所以要改成
<audio>
<source src="<stream url>" type="audio/mp3" />
</audio>
問題 4:Safari 又搞鬼? js 抓不到 duration?
這問題又複雜一點,應該說 Safari 比較老派?( 巨人的肩膀 again)
Safari 在使用 src 的 url 時 header 會帶入 RANGE
這個參數,
有這個參數在的時候,你的 response header 必須回應這下面三個參數Accept-Ranges
、Content-Length
、Content-Range
且 status
需回傳 206
而上面三個參數該怎麼生出來?
由於我的檔案放在 s3 透過 cloudfront 拿取 而這兩個服務都支援 Range Gets只需要把 Safari 傳進來的 Range 一併傳給 s3/cloud-front 再從其 response 拿取所需參數即可
# 接續 code section 1 #
headers = {}
if 'HTTP_RANGE' in request.META:
headers['Range'] = request.META.get('HTTP_RANGE')
# 帶入header
r = requests.get(<s3-url/cloud-front-url>, stream=True, headers=headers)
response = StreamingHttpResponse(streaming_content=r)
# 設置response header
response['Accept-Ranges'] = r.headers.get('Accept-Ranges')
response['Content-Length'] = r.headers.get('Content-Length')
response['Content-Range'] = r.headers.get('Content-Range')
response.status_code = 206
總結
其他 JS CSS 就自行憑空想像了吧? 應該都 google 得到
這次真的被 Safari 搞到 其他瀏覽器都順順的沒問題
氣到一定要上來寫一篇這樣
註:個人研究 有錯請見諒 歡迎指教