06视频播放
项目中有两种视频:收费视频[需要加密]和免费视频
使用保利威云视频服务来对视频进行加密
官方网址: http://www.polyv.net/vod/
注意:
开发时通过
免费试用
注册体验版账号公司使用酷播尊享版
开发文档地址:http://dev.polyv.net/2017/videoproduct/v-playerapi/html5player/html5-docs/
要开发播放保利威的加密视频功能,需要在用户中心->设置->API接口和加密设置.
http://my.polyv.net/secure/setting/api
配置视频上传加密.
上传视频并记录视频的VID
后端获取保利威的视频播放授权token,提供接口api给前端
参考文档:http://dev.polyv.net/2019/videoproduct/v-api/v-api-play/create-playsafe-token/
根据官方文档的案例,已经有其他人开源了,针对polvy的token生成的python版本了,我们可以直接拿来使用.
在libs下创建polyv.py,编写token生成工具函数
from django.conf import settings import time import requests import hashlib class PolyvPlayer(object): userId = settings.POLYV_CONFIG['userId'] secretkey = settings.POLYV_CONFIG['secretkey'] def tomd5(self, value): """取md5值""" return hashlib.md5(value.encode()).hexdigest() # 获取视频数据的token def get_video_token(self, videoId, viewerIp, viewerId=None, viewerName='', extraParams='HTML5'): """ :param videoId: 视频id :param viewerId: 看视频用户id :param viewerIp: 看视频用户ip :param viewerName: 看视频用户昵称 :param extraParams: 扩展参数 :param sign: 加密的sign :return: 返回点播的视频的token """ ts = int(time.time() * 1000) # 时间戳 plain = { "userId": self.userId, 'videoId': videoId, 'ts': ts, 'viewerId': viewerId, 'viewerIp': viewerIp, 'viewerName': viewerName, 'extraParams': extraParams } # 按照ASCKII升序 key + value + key + value... + value 拼接 plain_sorted = {} key_temp = sorted(plain) for key in key_temp: plain_sorted[key] = plain[key] print(plain_sorted) plain_string = '' for k, v in plain_sorted.items(): plain_string += str(k) + str(v) print(plain_string) sign_data = self.secretkey + plain_string + self.secretkey # 取sign_data的md5的大写 sign = self.tomd5(sign_data).upper() # 新的带有sign的字典 plain.update({'sign': sign}) result = requests.post( url='https://hls.videocc.net/service/v1/token', headers={"Content-type": "application/x-www-form-urlencoded"}, data=plain ).json() data = {} if isinstance(result, str) else result.get("data", {}) return {"token": data}
配置文件settings/dev.py,代码:
# 保利威视频加密服务 POLYV_CONFIG = { "userId":"62dc475e3f", "secretkey":"h6FiaEBRMU", "servicesUrl":"https://hls.videocc.net/service/v1/token", }
视图代码:
from rest_framework.views import APIView from luffy.libs.polyv import PolyvPlayer from rest_framework.response import Response from rest_framework.permissions import IsAuthenticated class PolyvAPIView(APIView): """视屏加密服务""" """生成播放视频的playsafetoken""" """播放页面的当前访问者只能是用户,不能是游客""" def get(self, request): # 获取客户端要播放的视屏的vid vid = request.query_parms.get('vid') # 获取客户端的IP remote_addr = request.META.get('REMOTE_ADDR') # 获取用户的ID和用户名--test user_id = 1 user_name = 'test' # 生成token polyv_video = PolyvPlayer() verify_data = polyv_video.get_video_token(vid, remote_addr, user_id, user_name) return Response(verify_data["token"])
路由代码:
path(r"polyv/token/",views.PolyvAPIView.as_view()),
客户端请求token并播放视频
在 vue项目的入口文件index.html 中加载保利威视频播放器的js核心类库
<script src='https://player.polyv.net/script/polyvplayer.min.js'></script>
创建视频播放页面的组件Player.vue,组件中直接配置保利威播放器需要的参数。
Player.vue,代码:
<template> <div class="player"> <div id="player"></div> </div> </template> <script> export default { name:"Player", data () { return { } }, methods: { }, mounted(){ let _this = this; var player = polyvObject('#player').videoPlayer({ wrap: '#player', width: document.documentElement.clientWidth, // 宽度 height: document.documentElement.clientHeight, // 高度 forceH5: true, vid: '62dc475e3f09b6db69447011eed4415a_6', code: '骑士3期', // 一般是用户昵称 // 视频加密播放的配置 playsafe: function (vid, next) { // 向后端发送请求获取加密的token _this.$axios.get(_this.$settings.Host+`/courses/polyv/token/`,{ params:{ vid: "62dc475e3f09b6db69447011eed4415a_6", } }).then(function (response) { console.log(response); next(response.data.token); }) } }); }, computed: { } } </script> <style scoped> </style>
前端路由,代码:
{ name:"Player", path:"/player", component: Player, },
完善点击课程详情页的立即试学按钮跳转到视频播放页面,并发送vid
Detail.vue,代码:
课时章节:
<button class="try" v-if="lesson.free_trail"><router-link :to="{path: '/player',query:{'vid':lesson.section_link}}">立即试学</router-link></button>
courses/serializers.py add 'section_link'
class CourseLessonModelSerializer(serializers.ModelSerializer): """课程课时""" class Meta: model = CourseLesson fields = ['id', 'name', 'duration', 'free_trail', 'section_link']
Player.vue,代码:
获取vid视频ID
<template> <div class="player"> <div id="player"></div> </div> </template> <script> export default { name:"Player", data () { return { } }, methods: { }, mounted(){ let _this = this; let video_id = this.$route.query.vid; var player = polyvObject('#player').videoPlayer({ wrap: '#player', width: document.documentElement.clientWidth, // 宽度 height: document.documentElement.clientHeight, // 高度 forceH5: true, vid:video_id, // vid:vid,的简写 code: '骑士3期', // 一般是用户昵称 // 视频加密播放的配置 playsafe: function (vid, next) { // 向后端发送请求获取加密的token _this.$axios.get(_this.$settings.Host+`/courses/polyv/token/`,{ params:{ vid:video_id, } }).then(function (response) { console.log(response); next(response.data.token); }) } }); }, computed: { } } </script> <style scoped> </style>
完善API接口的身份认证
试学必须在用户登录以后才能进行,所以后端的tokenAPI接口必须保证用户登陆以后,
所以后端视图代码中增加对jwt token的识别认证,代码:
from rest_framework.views import APIView from luffy.libs.polyv import PolyvPlayer from rest_framework.response import Response from rest_framework.permissions import IsAuthenticated class PolyvAPIView(APIView): """生成播放视频的playsafetoken""" """播放页面的当前访问者只能是用户,不能是游客""" permission_classes = (IsAuthenticated,) def get(self,request): # 获取客户端要播放的视频vid vid = request.query_params.get("vid") # 获取客户端的IP地址 remote_addr = request.META.get("REMOTE_ADDR") # 获取用户的ID和用户名[测试] user_id = request.user.id user_name = request.user.username # 生成token polyv = PolyvPlayer() data = polyv.get_video_token(vid, remote_addr,user_id, user_name) return Response(data["token"])
前端在请求后端提供视频加密播放的token时需要附带 jwt token
Player.vue,代码:
<template> <div class="player"> <div id="player"></div> </div> </template> <script> export default { name:"Player", data () { return { token: sessionStorage.token || localStorage.token, user_id: sessionStorage.user_id || localStorage.user_id, user_name: sessionStorage.user_name || localStorage.user_name, } }, methods: { }, created(){ // 判断用户用户是否已经登录了 if(!this.token){ let _this = this; this.$alert("对不起,您尚未登录!请登录!","警告",{ callback(){ _this.$router.push("/login"); } }) } }, mounted(){ let _this = this; let video_id = this.$route.query.vid; var player = polyvObject('#player').videoPlayer({ wrap: '#player', width: document.documentElement.clientWidth, // 宽度 height: document.documentElement.clientHeight, // 高度 forceH5: true, vid:video_id, // vid:vid,的简写 code: _this.user_name, // 跑马灯的显示信息,一般是用户昵称 // 视频加密播放的配置 playsafe: function (vid, next) { // 向后端发送请求获取加密的token _this.$axios.get(_this.$settings.Host+`/courses/polyv/token/`,{ // 附带jwt token headers:{ // 注意下方的空格!!! "Authorization":"jwt " + _this.token }, params:{ vid:video_id, } }).then(function (response) { console.log(response); next(response.data.token); }) } }); }, computed: { } } </script> <style scoped> </style>
详情页的视频免费播放
在课程模型Courses/models.py中新增一个视频的字段
from ckeditor_uploader.fields import RichTextUploadingField class Course(BaseModel): """ 专题课程 """ video = models.FileField(upload_to="video", null=True,blank=True,default=None, verbose_name="封面视频")
执行数据迁移
python manage.py makemigrations python manage.py migrate
前端修改播放器中关于视频地址和视频封面的地址
watch:{ course(data){ // while(data.brief.search(`"/media`) != -1 ){ // data.brief = data.brief.replace(`"/media`,`"${this.$settings.Host}/media`) // // 替换视频地址 this.playerOptions.sources[0].src = data.video; // 替换视频封面 this.playerOptions.poster = data.course_img; // 替换科恒信息中的详情介绍里面的图片路径 while(data.brief.search(`"/media`) != -1 ){ data.brief = data.brief.replace(`"/media`,`"${this.$settings.Host}/media`) } }
来源:https://www.cnblogs.com/pankypan/p/11300273.html