项目中引入视频插件
此种方式引入视频播放不能对视频进行加密。
1.安装依赖
npm install vue-video-player --save
2. 在前端项目,main.js文件中引入
//2. 在main.js中注册加载组件
require('video.js/dist/video-js.css');
require('vue-video-player/src/custom-theme.css');
import VideoPlayer from 'vue-video-player'
Vue.use(VideoPlayer);
3. 在需要引入播放器的页面引入播放器
例: 在课程详情页中的script标签里面加入以下代码:
<template> <div class="warp-left" style="width: 600px;height: 388px;background-color: #000;"> <--! vjs-custom-skin 不能少不然会出错 --> <video-player class="video-player vjs-custom-skin" //不能少vjs-custom-skin ref="videoPlayer" :playsinline="true" :options="playerOptions" @play="onPlayerPlay($event)" @pause="onPlayerPause($event)" > </video-player> </div> </template> <script> import {videoPlayer} from 'vue-video-player'; export default { name: 'CourseDetail', data(){ return { // vue-video的配置选项 playerOptions: { playbackRates: [0.7, 1.0, 1.5, 2.0], // 播放速度 autoplay: false, //如果true,则打开页面以后自动播放 muted: false, // 默认情况下将会消除任何音频。 loop: false, // 循环播放 preload: 'auto', // 建议浏览器在<video>加载元素后是否应该开始下载视频数据。auto浏览器选择最佳行为,立即开始加载视频(如果浏览器支持) language: 'zh-CN', aspectRatio: '16:9', // 将播放器置于流畅模式,并在计算播放器的动态大小时使用该值。值应该代表一个比例 - 用冒号分隔的两个数字(例如"16:9"或"4:3") fluid: true, // 当true时,Video.js player将拥有流体大小。换句话说,它将按比例缩放以适应其容器。 sources: [{ // 播放资源类型和地址 type: "video/mp4", // src: "http://img.ksbbs.com/asset/Mon_1703/05cacb4e02f9d9e.mp4" //你的视频地址(必填) src: "https://video.pearvideo.com/mp4/third/20190402/cont-1538041-10001982-232510-hd.mp4" //你的视频地址(必填) }], poster: "../static/courses/675076.jpeg", //视频封面图 width: document.documentElement.clientWidth, notSupportedMessage: '此视频暂无法播放,请稍后再试', //允许覆盖Video.js无法播放媒体源时显示的默认信息。 } } }, components:{ videoPlayer, // 引入vue-viedeo播放器组件 }, methods:{ }, computed: { player() { return this.$refs.videoPlayer.player } } }; </script> <style> </style>
详情页代码:
![](https://images.cnblogs.com/OutliningIndicators/ContractedBlock.gif)
<template> <div class="detail"> <Header></Header> <div class="warp"> <div class="course-info"> <div class="warp-left" style="width: 600px;height: 388px;background-color: #000;"> <--! vjs-custom-skin 不能少不然会出错 --> <video-player class="video-player vjs-custom-skin" ref="videoPlayer" :playsinline="true" :options="playerOptions" @play="onPlayerPlay($event)" @pause="onPlayerPause($event)" > </video-player> </div> <div class="warp-right"> <h3 class="course-title">Python开发21天入门</h3> <p class="course-data">37400人在学 课程总时长:154课时/30小时 难度:初级</p> <div class="preferential"> <p class="price-service">限时免费</p> <p class="timer">距离结束:仅剩 28天 14小时 10分 <span>57</span> 秒</p> </div> <p class="course-price"> <span>活动价</span> <span class="real-price">¥0.00</span> <span class="old-price">¥9.00</span> </p> <div class="buy-course"> <p class="buy-btn"> <span class="btn1">立即购买</span> <span class="btn2">免费试学</span> </p> <p class="add-cart"> <img src="../../static/images/cart.svg" alt="">加入购物车 </p> </div> </div> </div> <div class="course-tab"> <ul> <li class="active">详情介绍</li> <li>课程章节 <span>(试学)</span></li> <li>用户评论 (83)</li> <li>常见问题</li> </ul> </div> <div class="course-section"> <section class="course-section-left"> <img src="../../static/images/21天01_1547098127.6672518.jpeg" alt=""> </section> </div> </div> <Footer></Footer> </div> </template> <script> import Header from "./common/Header" import Footer from "./common/Footer" import {videoPlayer} from 'vue-video-player'; export default { name: 'CourseDetail', data(){ return { // vue-video的配置选项 playerOptions: { playbackRates: [0.7, 1.0, 1.5, 2.0], // 播放速度 autoplay: false, //如果true,则打开页面以后自动播放 muted: false, // 默认情况下将会消除任何音频。 loop: false, // 循环播放 preload: 'auto', // 建议浏览器在<video>加载元素后是否应该开始下载视频数据。auto浏览器选择最佳行为,立即开始加载视频(如果浏览器支持) language: 'zh-CN', aspectRatio: '16:9', // 将播放器置于流畅模式,并在计算播放器的动态大小时使用该值。值应该代表一个比例 - 用冒号分隔的两个数字(例如"16:9"或"4:3") fluid: true, // 当true时,Video.js player将拥有流体大小。换句话说,它将按比例缩放以适应其容器。 sources: [{ // 播放资源类型和地址 type: "video/mp4", // src: "http://img.ksbbs.com/asset/Mon_1703/05cacb4e02f9d9e.mp4" //你的视频地址(必填) src: "https://video.pearvideo.com/mp4/third/20190402/cont-1538041-10001982-232510-hd.mp4" //你的视频地址(必填) }], poster: "../static/courses/675076.jpeg", //视频封面图 width: document.documentElement.clientWidth, notSupportedMessage: '此视频暂无法播放,请稍后再试', //允许覆盖Video.js无法播放媒体源时显示的默认信息。 } } }, components:{ Header, Footer, videoPlayer, // 引入vue-viedeo播放器组件 }, methods:{ }, computed: { player() { return this.$refs.videoPlayer.player } } }; </script> <style scoped> .detail{ margin-top: 80px; } .course-info{ padding-top: 30px; width:1200px; height: 388px; margin: auto; } .warp-left,.warp-right{ float: left; } .warp-right{ height: 388px; position: relative; } .course-title{ font-size: 20px; color: #333; padding: 10px 23px; letter-spacing: .45px; font-weight: normal; } .course-data{ padding-left: 23px; padding-right: 23px; padding-bottom: 16px; font-size: 14px; color: #9b9b9b; } .preferential{ width: 100%; height: auto; background: #fa6240; font-size: 14px; color: #4a4a4a; display: -ms-flexbox; display: flex; -ms-flex-align: center; align-items: center; -ms-flex-pack: justify; justify-content: space-between; padding: 10px 23px; } .price-service{ font-size: 16px; color: #fff; letter-spacing: .36px; } .timer{ font-size: 14px; color: #fff; } .course-price{ width: 100%; background: #fff; height: auto; font-size: 14px; color: #4a4a4a; display: -ms-flexbox; display: flex; -ms-flex-align: end; align-items: flex-end; padding: 5px 23px; } .real-price{ font-size: 26px; color: #fa6240; margin-left: 10px; display: inline-block; margin-bottom: -5px; } .old-price{ font-size: 14px; color: #9b9b9b; margin-left: 10px; text-decoration: line-through; } .buy-course{ position: absolute; left: 0; bottom: 20px; width: 100%; height: auto; -ms-flex-pack: justify; justify-content: space-between; padding-left: 23px; padding-right: 23px; } .buy-btn{ float: left; } .buy-btn .btn1{ display: inline-block; width: 125px; height: 40px; background: #ffc210; border-radius: 4px; color: #fff; cursor: pointer; margin-right: 15px; text-align: center; vertical-align: middle; line-height: 40px; } .buy-btn .btn2{ width: 125px; height: 40px; border-radius: 4px; cursor: pointer; margin-right: 15px; display: inline-block; background: #fff; color: #ffc210; border: 1px solid #ffc210; text-align: center; vertical-align: middle; line-height: 40px; } .add-cart{ font-size: 14px; color: #ffc210; text-align: center; cursor: pointer; float: right; margin-top: 10px; } .add-cart img{ width: 20px; height: auto; margin-right: 7px; } .course-tab{ width: 1200px; margin: auto; height: auto; background: #fff; margin-bottom: 30px; box-shadow: 0 2px 4px 0 #f0f0f0; } .course-tab>ul{ padding: 0; margin: 0; list-style: none; width: 1200px; height: auto; display: -ms-flexbox; display: flex; -ms-flex-align: center; align-items: center; color: #4a4a4a; } .course-tab>ul>li{ margin-right: 15px; padding: 26px 20px 16px; font-size: 17px; cursor: pointer; } .course-tab>ul>.active{ color: #ffc210; border-bottom: 2px solid #ffc210; } .course-section{ background: #FAFAFA; overflow: hidden; padding-bottom: 40px; width: 1200px; height: auto; margin: 0 auto; } .course-section-left{ width: 880px; height: auto; padding: 20px; background: #fff; float: left; box-sizing: border-box; overflow: hidden; position: relative; box-shadow: 0 2px 4px 0 #f0f0f0; } </style>
方式二 使用保利威云视频服务来对视频进行加密
官方网址: http://www.polyv.net/vod/
开发文档地址:http://dev.polyv.net/2017/videoproduct/v-playerapi/html5player/html5-docs/
后端获取保利威的视频播放授权token,提供接口api给前端
1. 注册保利威账号
可以得到user_id和secretkey 中两个参数
2. 上传视频
可得到视频的vid ,这些视频的vid 需要手动的存到我们的数据库中,作为一个model的字段。以后访问需要有这个字段
此处上传了两个视频就有两个vid
vid :
7319d6869ef6d5b848818059e136c268_7
7319d6869e499c94e1ae8e128560a564_7
后端代码:
1. 在项目utils文件夹中创建文件:polyv.py 文件
2.以上两个参数配置到项目的settings文件中:
polyv.py 中的代码,以后可以直接使用,只需要到项目中配置如下代码:
#保利威 视频 settings.py 中配置,并 把user_id secretkey 改一就可以。 POLYV_CONFIG = { 'userId': '7319d6869e', 'secretkey': 'pzR6hojnzj' }
polyv.py 代码: 可以当模块使用,主要在视图中使用该模块。
根据官方文档的案例,已经有其他人开源了,针对polvy的token生成的python版本了,我们可以直接拿来使用.
![](https://images.cnblogs.com/OutliningIndicators/ContractedBlock.gif)
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}
3. 后端视图
视图代码如下:
from luf.utils import polyv class PolyvAPIView(APIView): def get(self,request): vid = request.query_params.get('vid') remote_addr = request.META.get('REMOTE_ADDR') # 如果免费 就可以默认为 1 user_id = 1 user_name = 'test' polyv_video = polyv.PolyvPlayer() verify_data = polyv_video.get_video_token(vid,remote_addr,user_id,user_name) return Response(verify_data["token"],status=status.HTTP_200_OK)
4. 路由
后端路由:courses/urls.py 中
from django.urls import path from . import views urlpatterns=[ path(r'cate/',views.CourseCategoryAPIView.as_view()), path('',views.CourseAPIView.as_view()), path('polyv/',views.PolyvAPIView.as_view()) ]
总路由:
urlpatterns = [ ...... path('courses/',include('courses.urls')) , ....... ]
视图接口获取保利威提供的token 接口格式:
http://127.0.0.1:8000/courses/polyv?vid=7319d6869e499c94e1ae8e128560a564_7
2.在组件中,直接配置保利威播放器需要的参数:
<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: 800, height: 533, forceH5: true, vid: '3df10095cd7aa7a0f0ca6ff876a2907a_3', code: 'myRandomCodeValue', playsafe: function (vid, next) {// 向后端发送请求获取加密的token _this.$axios.get("http://127.0.0.1:8000/courses/polyv",{ params:{ vid: vid, } }).then(function (data) { console.log(data); next(data.data.token) }) } }); }, computed: { } } </script> <style scoped> </style>
player.vue代码:
![](https://images.cnblogs.com/OutliningIndicators/ContractedBlock.gif)
<template> <div class="player"> <div id="video"></div> </div> </template> <script> export default { name:"Player", data () { return { vid: "7319d6869e499c94e1ae8e128560a564_7", } }, methods: { }, mounted(){ let _this = this let player = polyvPlayer({ wrap: '#video', // 播放器的容器div width: document.documentElement.clientWidth, height: document.documentElement.clientHeight, vid: _this.vid, playsafe: function(vid, next) { // next 表示回调函数,专门用户接受token,转发给保利威服务器 // 发送请求到后端获取token _this.$axios.get("http://127.0.0.1:8000/courses/polyv",{ params:{ vid: vid, } }).then(function (data) { next(data.data.token) }) } }); } } </script> <style scoped> </style>
有疑问可以加wx:18179641802,进行探讨