Use Cases

Claude Code के साथ a Custom Video Player Build करना

Claude Code का उपयोग करके building a custom video player सीखें। Practical code examples शामिल हैं।

カスタム動画プレーヤーको Claude Code सेबनाना

デフォルトのブラウザ動画プレーヤーではデザインの統一が難しく、featuresも限定され है।Claude Code का उपयोग करके、ブランドに合ったデザインで、再生速度変更・字幕・ピクチャーインピクチャー आदिのfeaturesを備えたカスタムプレーヤー build किया जा सकता है。

プレーヤーの要件

> HTML5 Videoベースのカスタム動画プレーヤーを作って。
> 再生/一時停止、シークバー、音量、再生速度変更、
> フルスクリーン、ピクチャーインピクチャー、字幕displayにsupportして。

メインプレーヤーcomponent

// src/components/VideoPlayer.tsx
'use client';
import { useRef, useState, useEffect } from 'react';

interface VideoPlayerProps {
  src: string;
  poster?: string;
  subtitles?: { src: string; label: string; lang: string }[];
}

export function VideoPlayer({ src, poster, subtitles }: VideoPlayerProps) {
  const videoRef = useRef<HTMLVideoElement>(null);
  const [isPlaying, setIsPlaying] = useState(false);
  const [currentTime, setCurrentTime] = useState(0);
  const [duration, setDuration] = useState(0);
  const [volume, setVolume] = useState(1);
  const [playbackRate, setPlaybackRate] = useState(1);
  const [showControls, setShowControls] = useState(true);

  const video = videoRef.current;

  useEffect(() => {
    if (!video) return;
    const handleTimeUpdate = () => setCurrentTime(video.currentTime);
    const handleLoadedMetadata = () => setDuration(video.duration);
    video.addEventListener('timeupdate', handleTimeUpdate);
    video.addEventListener('loadedmetadata', handleLoadedMetadata);
    return () => {
      video.removeEventListener('timeupdate', handleTimeUpdate);
      video.removeEventListener('loadedmetadata', handleLoadedMetadata);
    };
  }, [video]);

  const togglePlay = () => {
    if (!video) return;
    if (video.paused) {
      video.play();
      setIsPlaying(true);
    } else {
      video.pause();
      setIsPlaying(false);
    }
  };

  const handleSeek = (e: React.ChangeEvent<HTMLInputElement>) => {
    if (!video) return;
    const time = Number(e.target.value);
    video.currentTime = time;
    setCurrentTime(time);
  };

  const handleVolumeChange = (e: React.ChangeEvent<HTMLInputElement>) => {
    if (!video) return;
    const vol = Number(e.target.value);
    video.volume = vol;
    setVolume(vol);
  };

  const changePlaybackRate = (rate: number) => {
    if (!video) return;
    video.playbackRate = rate;
    setPlaybackRate(rate);
  };

  const toggleFullscreen = () => {
    const container = videoRef.current?.parentElement;
    if (!container) return;
    if (document.fullscreenElement) {
      document.exitFullscreen();
    } else {
      container.requestFullscreen();
    }
  };

  const togglePiP = async () => {
    if (!video) return;
    if (document.pictureInPictureElement) {
      await document.exitPictureInPicture();
    } else {
      await video.requestPictureInPicture();
    }
  };

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

  return (
    <div
      className="relative group bg-black rounded-xl overflow-hidden"
      onMouseEnter={() => setShowControls(true)}
      onMouseLeave={() => isPlaying && setShowControls(false)}
    >
      <video
        ref={videoRef}
        src={src}
        poster={poster}
        onClick={togglePlay}
        className="w-full cursor-pointer"
      >
        {subtitles?.map((sub) => (
          <track key={sub.lang} kind="subtitles" src={sub.src} label={sub.label} srcLang={sub.lang} />
        ))}
      </video>

      {/* コントロールバー */}
      <div className={`absolute bottom-0 left-0 right-0 bg-gradient-to-t from-black/80 to-transparent p-4 transition-opacity ${showControls ? 'opacity-100' : 'opacity-0'}`}>
        {/* シークバー */}
        <input
          type="range"
          min={0}
          max={duration}
          value={currentTime}
          onChange={handleSeek}
          className="w-full h-1 mb-3 accent-blue-500"
        />
        <div className="flex items-center justify-between text-white text-sm">
          <div className="flex items-center gap-3">
            <button onClick={togglePlay} className="text-xl">
              {isPlaying ? '⏸' : '▶'}
            </button>
            <span>{formatTime(currentTime)} / {formatTime(duration)}</span>
            <input
              type="range"
              min={0}
              max={1}
              step={0.1}
              value={volume}
              onChange={handleVolumeChange}
              className="w-20 h-1 accent-white"
            />
          </div>
          <div className="flex items-center gap-3">
            <select
              value={playbackRate}
              onChange={(e) => changePlaybackRate(Number(e.target.value))}
              className="bg-transparent text-white text-sm"
            >
              {[0.5, 0.75, 1, 1.25, 1.5, 2].map((rate) => (
                <option key={rate} value={rate} className="text-black">
                  {rate}x
                </option>
              ))}
            </select>
            <button onClick={togglePiP} title="ピクチャーインピクチャー">🖼</button>
            <button onClick={toggleFullscreen} title="フルスクリーン">⛶</button>
          </div>
        </div>
      </div>
    </div>
  );
}

keyボードショートカット

// src/hooks/useVideoShortcuts.ts
import { useEffect } from 'react';

export function useVideoShortcuts(videoRef: React.RefObject<HTMLVideoElement>) {
  useEffect(() => {
    const handleKeyDown = (e: KeyboardEvent) => {
      const video = videoRef.current;
      if (!video) return;

      switch (e.key) {
        case ' ':
          e.preventDefault();
          video.paused ? video.play() : video.pause();
          break;
        case 'ArrowRight':
          video.currentTime = Math.min(video.currentTime + 10, video.duration);
          break;
        case 'ArrowLeft':
          video.currentTime = Math.max(video.currentTime - 10, 0);
          break;
        case 'f':
          document.fullscreenElement
            ? document.exitFullscreen()
            : video.parentElement?.requestFullscreen();
          break;
        case 'm':
          video.muted = !video.muted;
          break;
      }
    };

    window.addEventListener('keydown', handleKeyDown);
    return () => window.removeEventListener('keydown', handleKeyDown);
  }, [videoRef]);
}

use करने का तरीकाの例

<VideoPlayer
  src="/videos/demo.mp4"
  poster="/images/poster.jpg"
  subtitles={[
    { src: '/subtitles/ja.vtt', label: '日本語', lang: 'ja' },
    { src: '/subtitles/en.vtt', label: 'English', lang: 'en' },
  ]}
/>

関連記事

メディア関連ではオーディオプレーヤーのimplementation、accessibilitysupportはaccessibilityimplementationガイドもदेखें。

Web動画のformatやエンコーディングके बारे मेंはMDN Web Docs(developer.mozilla.org)が詳しい है।

#Claude Code #動画プレーヤー #HTML5 #React #メディア
मुफ़्त

मुफ़्त PDF: 5 मिनट में Claude Code चीटशीट

बस अपना ईमेल दर्ज करें और हम तुरंत A4 एक-पृष्ठ चीटशीट PDF भेज देंगे।

हम आपकी व्यक्तिगत जानकारी की सुरक्षा करते हैं और स्पैम नहीं भेजते।

Masa

लेखक के बारे में

Masa

Claude Code का गहराई से उपयोग करने वाले इंजीनियर। claudecode-lab.com चलाते हैं, जो 10 भाषाओं में 2,000 से अधिक पेजों वाला टेक मीडिया है।