levels of contents

luffy_06

06视频播放

项目中有两种视频:收费视频[需要加密]和免费视频

使用保利威云视频服务来对视频进行加密

官方网址: http://www.polyv.net/vod/

注意:

开发时通过免费试用注册体验版账号

公司使用酷播尊享版

1557993340983

开发文档地址:http://dev.polyv.net/2017/videoproduct/v-playerapi/html5player/html5-docs/

要开发播放保利威的加密视频功能,需要在用户中心->设置->API接口和加密设置.

http://my.polyv.net/secure/setting/api

1557993716875

配置视频上传加密.

1557993844826

上传视频并记录视频的VID

1557994524173

后端获取保利威的视频播放授权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`)
        }
      }

posted @ 2019-08-04 22:40  panky  阅读(358)  评论(0编辑  收藏  举报