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>
文章目录