video-producer

安装量: 286
排名: #3161

安装

npx skills add https://github.com/daffy0208/ai-dev-standards --skill video-producer

Video Producer Skill

I help you build video players, handle video streaming, and create engaging video experiences.

What I Do

Video Playback:

Custom video players with controls Adaptive bitrate streaming (HLS, DASH) Picture-in-picture mode Fullscreen support

Video Features:

Subtitles and captions Quality selection Playback speed control Thumbnail previews

Streaming:

Live video streaming Video on demand (VOD) Progressive download Adaptive streaming Custom Video Player // components/VideoPlayer.tsx 'use client' import { useRef, useState, useEffect } from 'react'

interface VideoPlayerProps { src: string poster?: string title?: string }

export function VideoPlayer({ src, poster, title }: VideoPlayerProps) { const videoRef = useRef(null) const [playing, setPlaying] = useState(false) const [currentTime, setCurrentTime] = useState(0) const [duration, setDuration] = useState(0) const [volume, setVolume] = useState(1) const [fullscreen, setFullscreen] = useState(false) const [showControls, setShowControls] = useState(true)

useEffect(() => { const video = videoRef.current if (!video) return

const updateTime = () => setCurrentTime(video.currentTime)
const updateDuration = () => setDuration(video.duration)
const handleEnded = () => setPlaying(false)

video.addEventListener('timeupdate', updateTime)
video.addEventListener('loadedmetadata', updateDuration)
video.addEventListener('ended', handleEnded)

return () => {
  video.removeEventListener('timeupdate', updateTime)
  video.removeEventListener('loadedmetadata', updateDuration)
  video.removeEventListener('ended', handleEnded)
}

}, [])

const togglePlay = () => { if (!videoRef.current) return

if (playing) {
  videoRef.current.pause()
} else {
  videoRef.current.play()
}
setPlaying(!playing)

}

const handleSeek = (e: React.ChangeEvent) => { const time = parseFloat(e.target.value) setCurrentTime(time) if (videoRef.current) { videoRef.current.currentTime = time } }

const handleVolumeChange = (e: React.ChangeEvent) => { const vol = parseFloat(e.target.value) setVolume(vol) if (videoRef.current) { videoRef.current.volume = vol } }

const toggleFullscreen = () => { if (!videoRef.current) return

if (!fullscreen) {
  videoRef.current.requestFullscreen()
} else {
  document.exitFullscreen()
}
setFullscreen(!fullscreen)

}

const formatTime = (seconds: number) => { const mins = Math.floor(seconds / 60) const secs = Math.floor(seconds % 60) return ${mins}:${secs.toString().padStart(2, '0')} }

return (

setShowControls(true)} onMouseLeave={() => setShowControls(playing ? false : true)} > {title && (

{title}

)}

  <video
    ref={videoRef}
    src={src}
    poster={poster}
    onClick={togglePlay}
    className="w-full"
  />

  {showControls && (
    <div className="absolute bottom-0 left-0 right-0 p-4 bg-gradient-to-t from-black/70 to-transparent">
      {/* Progress Bar */}
      <input
        type="range"
        min="0"
        max={duration || 0}
        value={currentTime}
        onChange={handleSeek}
        className="w-full mb-2"
      />

      <div className="flex items-center gap-4">
        {/* Play/Pause */}
        <button
          onClick={togglePlay}
          className="text-white text-2xl hover:scale-110 transition"
        >
          {playing ? '⏸️' : '▶️'}
        </button>

        {/* Time */}
        <span className="text-white text-sm">
          {formatTime(currentTime)} / {formatTime(duration)}
        </span>

        {/* Volume */}
        <div className="flex items-center gap-2">
          <span className="text-white">🔊</span>
          <input
            type="range"
            min="0"
            max="1"
            step="0.1"
            value={volume}
            onChange={handleVolumeChange}
            className="w-20"
          />
        </div>

        <div className="flex-1" />

        {/* Fullscreen */}
        <button
          onClick={toggleFullscreen}
          className="text-white hover:scale-110 transition"
        >
          {fullscreen ? '⬛' : '⬜'}
        </button>
      </div>
    </div>
  )}
</div>

) }

HLS Streaming (Adaptive Bitrate) npm install hls.js

// components/HLSPlayer.tsx 'use client' import { useEffect, useRef } from 'react' import Hls from 'hls.js'

export function HLSPlayer({ src }: { src: string }) { const videoRef = useRef(null)

useEffect(() => { const video = videoRef.current if (!video) return

if (Hls.isSupported()) {
  const hls = new Hls({
    enableWorker: true,
    lowLatencyMode: true
  })

  hls.loadSource(src)
  hls.attachMedia(video)

  hls.on(Hls.Events.MANIFEST_PARSED, () => {
    console.log('HLS manifest loaded, quality levels:', hls.levels)
  })

  hls.on(Hls.Events.ERROR, (event, data) => {
    console.error('HLS error:', data)
    if (data.fatal) {
      switch (data.type) {
        case Hls.ErrorTypes.NETWORK_ERROR:
          hls.startLoad()
          break
        case Hls.ErrorTypes.MEDIA_ERROR:
          hls.recoverMediaError()
          break
        default:
          hls.destroy()
          break
      }
    }
  })

  return () => {
    hls.destroy()
  }
} else if (video.canPlayType('application/vnd.apple.mpegurl')) {
  // Native HLS support (Safari)
  video.src = src
}

}, [src])

return

Picture-in-Picture // components/PIPVideoPlayer.tsx 'use client' import { useRef, useState } from 'react'

export function PIPVideoPlayer({ src }: { src: string }) { const videoRef = useRef(null) const [pipActive, setPipActive] = useState(false)

const togglePIP = async () => { if (!videoRef.current) return

try {
  if (!pipActive) {
    await videoRef.current.requestPictureInPicture()
    setPipActive(true)
  } else {
    await document.exitPictureInPicture()
    setPipActive(false)
  }
} catch (error) {
  console.error('PIP error:', error)
}

}

return (

返回排行榜