django视频边加载边播放,并且在chrome浏览器支持进度条
参考博客:https://blog.csdn.net/qq_44178248/article/details/102893367
在setting中多设置一个视频文件夹目录
# uploads
X_FRAME_OPTIONS = 'sameorigin'
VIDEO_FOLDER_PATH = "G:/movie/人民的名义"
# VIDEO_FOLDER_PATH = "C:/Users/Amazing/Videos"
STATICFILES_DIRS = (
os.path.join(BASE_DIR, "static"),
VIDEO_FOLDER_PATH,
)
url中配置:
# video_app_views
path('', video_app_views.main),
path('main/', video_app_views.main),
path('main/<path:folder_path>', video_app_views.main),
path('video/stream_video/', video_app_views.stream_video),
path('video/select_video/<path:video_path>', video_app_views.video),
其中main用来遍历目录
video/select_video用来选择需要播放的视频
video/stream_video用来返回浏览器请求的对应视频的对应字节内容
views
from django.shortcuts import render
from test_video.settings import VIDEO_FOLDER_PATH
from video_app.functions.functions import *
from django.http import StreamingHttpResponse
from wsgiref.util import FileWrapper
import mimetypes
import re
# Create your views here.
def file_iterator(file_name, chunk_size=8192, offset=0, length=None):
with open(file_name, "rb") as f:
f.seek(offset, os.SEEK_SET)
remaining = length
while True:
bytes_length = chunk_size if remaining is None else min(remaining, chunk_size)
data = f.read(bytes_length)
if not data:
break
if remaining:
remaining -= len(data)
yield data
def stream_video(request):
"""将视频文件以流媒体的方式响应"""
range_header = request.META.get('HTTP_RANGE', '').strip()
range_re = re.compile(r'bytes\s*=\s*(\d+)\s*-\s*(\d*)', re.I)
range_match = range_re.match(range_header)
path = request.GET.get('path')
path = VIDEO_FOLDER_PATH + "/" + path
size = os.path.getsize(path)
content_type, encoding = mimetypes.guess_type(path)
content_type = content_type or 'application/octet-stream'
if range_match:
first_byte, last_byte = range_match.groups()
first_byte = int(first_byte) if first_byte else 0
last_byte = first_byte + 1024 * 1024 * 10
if last_byte >= size:
last_byte = size - 1
length = last_byte - first_byte + 1
resp = StreamingHttpResponse(file_iterator(path, offset=first_byte, length=length), status=206, content_type=content_type)
resp['Content-Length'] = str(length)
resp['Content-Range'] = 'bytes %s-%s/%s' % (first_byte, last_byte, size)
else:
resp = StreamingHttpResponse(FileWrapper(open(path, 'rb')), content_type=content_type)
resp['Content-Length'] = str(size)
resp['Accept-Ranges'] = 'bytes'
return resp
def main(request, folder_path=""):
paths = get_files_path(VIDEO_FOLDER_PATH, folder_path)
context = {"paths": paths}
return render(request, "video_app/main.html", context)
def video(request, video_path=""):
context = {"video_path": video_path}
return render(request, "video_app/video.html", context)
functions.py
import os
class Path:
def __init__(self, relative_path, is_folder):
self.name = relative_path[relative_path.rfind("/")+1:]
if is_folder:
self.url = "/main/{0}".format(relative_path)
else:
suffix_start = self.name.rfind(".")
suffix = ""
if suffix_start != -1:
suffix = self.name[suffix_start+1:]
suffix = suffix.lower()
if suffix in ["mp4", "mov"]:
self.url = "/video/select_video/{0}".format(relative_path)
else:
self.url = "/static/{0}".format(relative_path)
def refine_path(path):
# 认为path最前面不是/
# 该函数想要去除..和.避免访问到不该访问的地址
path_split = path.split("/")
path_stack = []
for i in range(len(path_split)):
if path_split[i] == "..":
path_stack.pop()
elif path_split[i] == ".":
pass
else:
path_stack.append(path_split[i])
new_path = ""
for i in range(len(path_stack)):
if new_path != "":
new_path += "/"
new_path += path_stack[i]
return new_path
def get_files_path(root_folder_path, relative_path):
relative_path = refine_path(relative_path)
if relative_path == "":
absolute_path = root_folder_path
else:
absolute_path = root_folder_path + "/" + relative_path
# 先判断是否访问到了不该访问的文件夹
if os.path.exists(absolute_path) == False:
return []
files_name = os.listdir(absolute_path)
root_folder_path_size = len(root_folder_path)
paths = []
for i in range(len(files_name)):
file_path = absolute_path+"/"+files_name[i]
is_folder = os.path.isdir(file_path)
relative_path = file_path[root_folder_path_size+1:]
paths.append(Path(relative_path, is_folder))
return paths
处理文件夹遍历
video.html
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>{{ video_name }}</title>
<link rel="shortcut icon" href="/static/video_app/icons/avatar.ico"/>
<link rel="stylesheet" href="/static/video_app/css/video.css" />
</head>
<body>
<div>
<a href="/main">首页</a>
</div>
<div>
<h3>{{ video_name }}</h3>
</div>
<div class="div_video">
<video id="video" controls preload="auto" data-setup='{}'>
<source src="/video/stream_video/?path={{ video_path }}" type="video/mp4"></source>
<p class="vjs-no-js">
To view this video please enable JavaScript, and consider upgrading to a
web browser that
<a href="https://videojs.com/html5-video-support/" target="_blank">
supports HTML5 video
</a>
</p>
</video>
</div>
</body>
</html>
main.html
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>本地视频</title>
<link rel="stylesheet" href="/static/video_app/css/main.css" />
<link rel="shortcut icon" href="/static/video_app/icons/avatar.ico"/>
</head>
<body>
{% for p in paths %}
<a class="a" href="{{ p.url }}">{{ p.name }}</a>
{% endfor %}
</body>
</html>