Open-Source Transcript Player
React-based video player with a synchronized transcript and editor for notes, or AI summaries.
Overview
This React application provides a simple video player with a synchronized transcript display. Key features include:- Video playback with standard controls
- Synchronized transcript display
- Current word highlighting in the transcript
- Video navigation by clicking on transcript words
- Responsive interface with resizable split view
Data is loaded from a mock JSON file, which matches the typical format of the transcript data returned by a transcription API, in this case the
/GET
route of Meeting Baas.The project is under the MIT license, free to use and modify it.
For a full-featured example, including a back-end which stores the data, check out the Transcript Seeker repository.
Main Components
- App.tsx: Manages global state and layout
- VideoPlayer.tsx: Wrapper for video.js
- Transcript.tsx: Displays synchronized transcript
- Card.tsx: Reusable component for content display
View on GitHubimport { Box, Center, Flex, Text } from '@chakra-ui/react' import React, { useCallback, useEffect, useState } from 'react' import Player from 'video.js/dist/types/player' import { Card } from './components/Card' import Editor from './components/Editor' import Transcript from './components/Transcript' import { VideoPlayer } from './components/VideoPlayer' import videoExample from './fakeData/customer_service_480x360.mp4' import jsonData from './fakeData/fakedata.json' import { VideoData } from './type' const videoData: VideoData = jsonData as VideoData const App: React.FC = () => { const [isHover, setIsHover] = useState(false) const [width, setWidth] = useState(30) const [isDragging, setIsDragging] = useState(false) const [currentTime, setCurrentTime] = useState(0) const [videoPlayer, setVideoPlayer] = useState<Player | null>(null) const [editorData, setEditorData] = useState({}) const handleEditorChange = (data: any) => { setEditorData(data) } const handleMouseDown = useCallback(() => { setIsDragging(true) }, []) const handleMouseMove = useCallback( (e: MouseEvent) => { if (isDragging) { let newWidth = (e.clientX / window.innerWidth) * 100 newWidth = Math.min(Math.max(newWidth, 35), 65) setWidth(newWidth) } }, [isDragging] ) const handleMouseUp = useCallback(() => { setIsDragging(false) }, []) useEffect(() => { window.addEventListener('mousemove', handleMouseMove) window.addEventListener('mouseup', handleMouseUp) return () => { window.removeEventListener('mousemove', handleMouseMove) window.removeEventListener('mouseup', handleMouseUp) } }, [handleMouseMove, handleMouseUp]) const handleTimeUpdate = useCallback((time: number) => { setCurrentTime(time) }, []) const handleSeek = useCallback( (time: number) => { if (videoPlayer) { videoPlayer.currentTime(time) } }, [videoPlayer] ) const setPlayerRef = useCallback((player: Player) => { setVideoPlayer(player) }, []) return ( <Flex h="100vh" w="100vw" bg="gray.100" gap="4" p="4" flexDir={{ base: 'column', lg: 'row' }} > <Flex flexDir={'column'} h="full" minW={{ base: 'full', lg: `${width}%` }} w={{ base: 'full', lg: `${width}%` }} gap="4" > <VideoPlayer url={videoExample} onTimeUpdate={handleTimeUpdate} setPlayerRef={setPlayerRef} /> <Card header={ <Text size="md" fontWeight={'semibold'}> Transcript </Text> } title="Transcript" isOpen={true} toggleCard={() => {}} bodyContent={ <Transcript transcript={videoData.data.transcript} currentTime={currentTime} onWordClick={handleSeek} /> } /> </Flex> <Center display={{ base: 'none', lg: 'flex' }} onMouseEnter={() => setIsHover(true)} onMouseLeave={() => setIsHover(false)} px="2px" h="full" gap="2px" cursor="ew-resize" onMouseDown={handleMouseDown} opacity={isHover || isDragging ? '1' : '0'} > <Box h="50px" cursor="ew-resize" w="4px" bg="black" rounded="full" /> <Box h="50px" cursor="ew-resize" w="4px" bg="black" rounded="full" /> </Center> <Card header={ <Text size="md" fontWeight={'semibold'}> Editor </Text> } title="Editor" isOpen={true} toggleCard={() => {}} bodyContent={ <Editor data={editorData} onChange={handleEditorChange} /> } /> </Flex> ) } export default App
Here's a simple script that clones the code repo and launches the example:
View on GitHub#!/bin/bash # 🚀 Quick Start for Video Player with Synchronized Transcript 🚀 # Save this file as run.sh, chmod +x run.sh, and run it # ⚠️ Make sure you have Git, Node.js, and Yarn installed before proceeding! # Clone the repository echo "📥 Cloning the repository..." git clone https://github.com/Meeting-Baas/meeting-bot-as-a-service && cd meeting-bot-as-a-service || { echo "❌ Error: Failed to clone repository"; exit 1; } # Navigate to the player interface directory echo "📂 Navigating to player interface directory..." cd apps/player-interface || { echo "❌ Error: Failed to navigate to player interface directory"; exit 2; } # Install dependencies echo "🔧 Installing dependencies..." yarn install || { echo "❌ Error: Failed to install dependencies"; exit 3; } # Run the application echo "🚀 Starting the development server..." yarn dev || { echo "❌ Error: Failed to start the development server"; exit 4; } echo "✅ Setup complete! The application should now be running on your local development server at http://localhost:3000"
Usage
The application loads a video and its transcript from mock data. Users can:
- Play the video and see synchronized transcript
- Click on words in the transcript to navigate the video
- Resize the split between video and transcript on larger screens
Customization
The data structure in fakedata.json
aligns with the Meeting Baas API /GET route
format. This structure is compatible with various transcription API outputs, facilitating integration with different services.
The Transcript
component processes this data, rendering speaker information and individual words. It tracks the current playback time, highlighting the corresponding word and enabling navigation on word click.
View on GitHub// types.ts export interface Word { start: number end: number word: string } export interface TranscriptEntry { speaker: string words: Word[] } export interface VideoData { event: string data: { bot_id: string transcript: TranscriptEntry[] speakers: string[] mp4: string } }
Resources
Open-Source
Product
PlansFeature ListMeeting Transcription APIMeeting AgentsAI Meeting Assistant APIAPI to Record and Transcribe Video MeetingsMeeting bots with transcriptionMeeting bot API for Google MeetAlternative Recording API for Google MeetAlternatives to Recall AIRecall AI vs Meeting BaaSMeeting bot API for ZoomMeeting bot API for Microsoft Teams