npm package discovery and stats viewer.

Discover Tips

  • General search

    [free text search, go nuts!]

  • Package details

    pkg:[package-name]

  • User packages

    @[username]

Sponsor

Optimize Toolset

I’ve always been into building performant and accessible sites, but lately I’ve been taking it extremely seriously. So much so that I’ve been building a tool to help me optimize and monitor the sites that I build to make sure that I’m making an attempt to offer the best experience to those who visit them. If you’re into performant, accessible and SEO friendly sites, you might like it too! You can check it out at Optimize Toolset.

About

Hi, 👋, I’m Ryan Hefner  and I built this site for me, and you! The goal of this site was to provide an easy way for me to check the stats on my npm packages, both for prioritizing issues and updates, and to give me a little kick in the pants to keep up on stuff.

As I was building it, I realized that I was actually using the tool to build the tool, and figured I might as well put this out there and hopefully others will find it to be a fast and useful way to search and browse npm packages as I have.

If you’re interested in other things I’m working on, follow me on Twitter or check out the open source projects I’ve been publishing on GitHub.

I am also working on a Twitter bot for this site to tweet the most popular, newest, random packages from npm. Please follow that account now and it will start sending out packages soon–ish.

Open Software & Tools

This site wouldn’t be possible without the immense generosity and tireless efforts from the people who make contributions to the world and share their work via open source initiatives. Thank you 🙏

© 2024 – Pkg Stats / Ryan Hefner

video-printscreen-selector

v1.0.3

Published

视频截图选择器

Downloads

8

Readme

Installation

$ npm install video-printscreen-selector

Description

有这么一个需求:上传视频后需要用户上传视频封面,但是用户上传(截取)的封面尺寸跟视频尺寸大小不一,因为封面图片尺寸小于视频尺寸,当开始播放时,图片会给用户一种视频放大了的感觉,体验不太友好。这个组件是通过获取视频的大小,再通过截取视频画面提供上传视频者更方便选择视频封面。

Demo

图中结合ant-design-vue UI 走马灯组件实现选取组件

https://sm.ms/image/dnNhgSuCUk7A2XJ

Usage

示例1:
上传视频文件时实例化(多用于新建)

父组件:
<script>
// 子组件
import videoModal from '@/components/videoController/index.vue'
import VideoController from 'video-printscreen-selector'

beforeUpload (file) {
  if (!validMajorBrowser(this)) return false
  const that = this
  const isJpgOrPng = file.type === 'video/mp4'
  // 判断视频格式
  if (!isJpgOrPng) {
    this.$message.error('目前只能上传 MP4 格式的视频!')
    return false
  }
  // 判断视频大小
  const isLt2M = file.size / 1024 / 1024 < 20
  if (!isLt2M) {
    this.$message.error('视频只能上传 20 M以内!')
    return false
  }
  this.uploading = true
  // 实例化
  this.videoController = new VideoController()
  // 获取视频宽、高、视频长度
  this.videoController.getVidewInfo(file)
  uploadOSS(file).then((results) => {
    // 上传完成后, 赋值视频连接
    this.$set(that.form, 'url', results.res.requestUrls[0].toString())
    this.$refs.videoUrl.clearValidate()
    that.$message.info(`上传成功`)
    this.uploading = false
    this.showVideoModal = true // 弹出子组件
  })
  return false
},
// 附赠base64转file文件方法
onSelectImage (img) {
  const that = this
  // base64转blob
  const base64ToBlob = (base64Data) => {
    const arr = base64Data.split(',')
    const fileType = arr[0].match(/:(.*?)/)[1]
    const bstr = atob(arr[1])
    let l = bstr.length
    const u8Arr = new Uint8Array(l)
    while (l--) {
      u8Arr[l] = bstr.charCodeAt(l)
    }
    return new Blob([u8Arr], {
      type: fileType
    })
  }
  // blob转file
  const blobToFile = (newBlob, fileName) => {
    newBlob.lastModifiedDate = new Date()
    newBlob.name = fileName
    return newBlob
  }
  // 生成blob
  const blob = base64ToBlob(img)
  // 实例化水印对象
  const watermarkMaker = new Watermark()
  // 生成file文件
  const file = blobToFile(blob, Date.parse(new Date()))
  // 这个是作者另外一个图片水印插件
  watermarkMaker.drawWatermarkImg(file, watermark, res => {
    // 图片/视频上传方法
    uploadOSS(res).then((results) => {
      this.$set(that.form, 'image', results.res.requestUrls[0].toString())
      that.$message.info(`上传成功`)
    })
  })
}
</script>

子组件:
<template>
  <a-modal class="modal-group" v-model="showModal" title="视频封面" :width="900" :maskClosable="false">
    <a-carousel class="swiper-group" arrows dots-class="slick-dots slick-thumb">
      <a slot="customPaging" slot-scope="props">
        <img :src="getImgUrl(props.i)" @click="onSelectImage(props.i)" />
      </a>
      <div v-for="(item, i) in imageList" :key="i">
        <img :width="videoController.videoWidth / 3" :height="videoController.videoHeight / 3" :src="item" />
      </div>
    </a-carousel>
    <div class="pages">
      <a-button type="link" :disabled="page.pageIndex === 1" @click="handlePage(0)">上一页</a-button>
      <a-button type="link" :disabled="page.pageIndex === videoController.maxPage" @click="handlePage(1)">下一页</a-button>
    </div>
    <div class="modal-footer" slot="footer">
      <div>
        视频长度:{{ videoController.videoDuration }}s
        &nbsp;
        总页数:{{ videoController.maxPage }}
        &nbsp;
        当前页:
        <a-input-number v-model="page.pageIndex" :min="1" :max="videoController.maxPage" @change="onChangePage" />
      </div>
      <div>
        <a-button @click="showModal = false">取消</a-button>
        <a-button type="primary" @click="submit">确定</a-button>
      </div>
    </div>
    <a-spin class="spin" v-if="loading" tip="图片生成中..." size="large"></a-spin>
    <div v-if="loading" class="spin-mask"></div>
  </a-modal>
</template>

<script>
import VideoController from 'video-printscreen-selector'
  export default {
    data () {
      return {
        showModal: false,
        imageList: [],
        loading: false,
        current: '',
        page: {
          pageIndex: 1,
          pageSize: 10
        }
      }
    },
    props: {
      value: {
        type: Boolean,
        default: false
      },
      videoController: {
        type: Object,
        required: true,
        default: () => {
          return new VideoController() // 默认实例化方法
        }
      },
      videoUrl: {
        type: String,
        default: ''
      }
    },
    watch: {
      value (c) {
        this.showModal = c
      },
      showModal (c) {
        if (!c) {
          this.current = ''
          this.$emit('input', c)
        } else {
          this.getImageList()
        }
      }
    },
    methods: {
      async getImageList () {
        try {
          this.loading = true
          this.imageList = await this.videoController.createVideoImagesList(this.videoUrl, 'multi', this.page) // 通过这个方法获取所需截取的图片范围
          this.$nextTick(() => {
            this.current = this.imageList[0] // 默认选择第一张图片
          })
        } catch (e) {
          this.$message.error(e)
        } finally {
          this.loading = false
        }
      },
      onSelectImage (i) {
        this.current = this.imageList[i]
      },
      getImgUrl (i) {
        return this.imageList[i]
      },
      handlePage (c) {
        if (c) {
          // 下一页
          this.page.pageIndex += 1
        } else {
          // 上一页
          this.page.pageIndex -= 1
        }
        this.getImageList()
      },
      onChangePage (c) {
        this.page.pageIndex = c
        this.getImageList()
      },
      submit () {
        this.$emit('onSelect', this.current)
        this.showModal = false
      }
    }
  }
</script>

示例2:
直接通过视频连接获取(多用于编辑)
import VideoController from 'video-printscreen-selector'

<script>
export default {
    methods: {
        async buildController () {
            const controller = new VideoController()
            const img = await controller.createVideoImagesList(
                '视频链接',
                11
            )
        }
    }
}
</script>

API

实例化后可以获取到的参数/方法:

| 属性 | 说明 | 类型 | 默认值 | |---- | ---- |---- | ---- | | videoWidth | 视频宽度 | number | 0 | | videoHeight | 视频高度 | number | 0 | | maxPage | 分页最大页数 | number | 0 | | videoDuration | 视频长度(秒) | number | 0 | | createVideoImagesList | 截取方法,type为single时默认截取视频第1秒,type也可以具体到某一秒(类型必须为number),当type为'multi'为范围截取,此时page参数必传 | function | url, type = 'single', page = { pageIndex: 1, pageSize: 10 } |