shcool/yuthon_school/controllers/main.py
2026-07-28 18:50:48 +08:00

78 lines
2.7 KiB
Python

import base64
import os
import re
from odoo import http
from odoo.http import request
class VideoPlaybackController(http.Controller):
@http.route('/yuthon_school/video/<int:video_id>', type='http', auth='user', methods=['GET'])
def serve_video(self, video_id, **kwargs):
"""提供视频流服务,支持 Range 请求以实现视频进度拖拽"""
video = request.env['yuthon.school.video'].sudo().browse(video_id)
if not video.exists() or not video.video_file:
return request.not_found()
video_data = self._decode_video(video.video_file)
file_size = len(video_data)
mime_map = {
'mp4': 'video/mp4',
'webm': 'video/webm',
'ogg': 'video/ogg',
'ogv': 'video/ogg',
'mov': 'video/quicktime',
'mkv': 'video/x-matroska',
'avi': 'video/x-msvideo',
}
mime_type = 'video/mp4'
if video.video_filename:
ext = os.path.splitext(video.video_filename)[1].lower().lstrip('.')
mime_type = mime_map.get(ext, 'video/mp4')
# 处理 Range 请求(视频进度条拖拽需要)
range_header = request.httprequest.headers.get('Range')
if range_header:
range_match = re.search(r'bytes=(\d+)-(\d*)', range_header)
if range_match:
start = int(range_match.group(1))
end = int(range_match.group(2)) if range_match.group(2) else file_size - 1
if start >= file_size:
headers = [('Content-Range', f'bytes */{file_size}')]
return request.make_response(b'', headers, status=416)
end = min(end, file_size - 1)
chunk = video_data[start:end + 1]
headers = [
('Content-Type', mime_type),
('Content-Length', str(len(chunk))),
('Content-Range', f'bytes {start}-{end}/{file_size}'),
('Accept-Ranges', 'bytes'),
]
return request.make_response(chunk, headers, status=206)
# 返回完整视频内容(在线播放)
headers = [
('Content-Type', mime_type),
('Content-Length', str(file_size)),
('Accept-Ranges', 'bytes'),
]
return request.make_response(video_data, headers)
@staticmethod
def _decode_video(raw_file):
"""解码 Odoo 18 Binary 字段数据"""
if isinstance(raw_file, bytes):
try:
return base64.b64decode(raw_file, validate=True)
except Exception:
return raw_file
elif isinstance(raw_file, str):
return base64.b64decode(raw_file)
return b''