File size: 15,357 Bytes
ee9377a
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
import React, { useState } from 'react';
import { Youtube, Download, Play, Pause, Volume2, FileAudio, FileVideo, Loader2, CheckCircle, AlertCircle, Globe, Mic, Languages, Speaker } from 'lucide-react';

interface ProcessingStep {
  id: string;
  title: string;
  description: string;
  status: 'pending' | 'processing' | 'completed' | 'error';
  icon: React.ReactNode;
}

function App() {
  const [youtubeUrl, setYoutubeUrl] = useState('');
  const [isProcessing, setIsProcessing] = useState(false);
  const [currentStep, setCurrentStep] = useState(0);
  const [isPlaying, setIsPlaying] = useState(false);
  const [showResults, setShowResults] = useState(false);

  const processingSteps: ProcessingStep[] = [
    {
      id: 'extract',
      title: 'Extract Audio',
      description: 'Downloading video and extracting high-quality audio',
      status: 'pending',
      icon: <FileAudio className="w-5 h-5" />
    },
    {
      id: 'transcribe',
      title: 'Transcribe Speech',
      description: 'Converting English audio to accurate text',
      status: 'pending',
      icon: <Mic className="w-5 h-5" />
    },
    {
      id: 'translate',
      title: 'Translate Content',
      description: 'Translating English text to natural Hindi',
      status: 'pending',
      icon: <Languages className="w-5 h-5" />
    },
    {
      id: 'synthesize',
      title: 'Generate Audio',
      description: 'Creating Hindi speech with natural voice',
      status: 'pending',
      icon: <Speaker className="w-5 h-5" />
    },
    {
      id: 'sync',
      title: 'Synchronize Video',
      description: 'Matching audio timing with original video',
      status: 'pending',
      icon: <FileVideo className="w-5 h-5" />
    }
  ];

  const [steps, setSteps] = useState(processingSteps);

  const isValidYouTubeUrl = (url: string) => {
    const youtubeRegex = /^(https?:\/\/)?(www\.)?(youtube\.com|youtu\.be)\/.+/;
    return youtubeRegex.test(url);
  };

  const handleSubmit = async (e: React.FormEvent) => {
    e.preventDefault();
    if (!isValidYouTubeUrl(youtubeUrl)) return;

    setIsProcessing(true);
    setCurrentStep(0);
    setShowResults(false);

    // Simulate processing steps
    for (let i = 0; i < steps.length; i++) {
      setCurrentStep(i);
      
      // Update step to processing
      setSteps(prev => prev.map((step, index) => 
        index === i ? { ...step, status: 'processing' } : step
      ));

      // Simulate processing time
      await new Promise(resolve => setTimeout(resolve, 2000 + Math.random() * 1000));

      // Update step to completed
      setSteps(prev => prev.map((step, index) => 
        index === i ? { ...step, status: 'completed' } : step
      ));
    }

    setIsProcessing(false);
    setShowResults(true);
  };

  const getStepStatusIcon = (step: ProcessingStep, index: number) => {
    if (step.status === 'completed') {
      return <CheckCircle className="w-5 h-5 text-emerald-500" />;
    } else if (step.status === 'processing') {
      return <Loader2 className="w-5 h-5 text-indigo-500 animate-spin" />;
    } else if (step.status === 'error') {
      return <AlertCircle className="w-5 h-5 text-red-500" />;
    } else {
      return <div className="w-5 h-5 rounded-full border-2 border-gray-300 flex items-center justify-center">
        <div className="w-2 h-2 rounded-full bg-gray-300"></div>
      </div>;
    }
  };

  return (
    <div className="min-h-screen bg-gradient-to-br from-indigo-50 via-white to-purple-50">
      {/* Header */}
      <header className="bg-white/80 backdrop-blur-sm border-b border-gray-100 sticky top-0 z-50">
        <div className="max-w-7xl mx-auto px-4 sm:px-6 lg:px-8 py-4">
          <div className="flex items-center space-x-3">
            <div className="bg-gradient-to-r from-indigo-500 to-purple-600 p-2 rounded-xl">
              <Globe className="w-6 h-6 text-white" />
            </div>
            <div>
              <h1 className="text-xl font-bold text-gray-900">YouTube Translator</h1>
              <p className="text-sm text-gray-600">English to Hindi Video Dubbing</p>
            </div>
          </div>
        </div>
      </header>

      <div className="max-w-4xl mx-auto px-4 sm:px-6 lg:px-8 py-8">
        {/* Hero Section */}
        <div className="text-center mb-12">
          <div className="inline-flex items-center space-x-2 bg-indigo-100 text-indigo-700 px-4 py-2 rounded-full text-sm font-medium mb-6">
            <Youtube className="w-4 h-4" />
            <span>Powered by Advanced AI Translation</span>
          </div>
          <h2 className="text-4xl font-bold text-gray-900 mb-4">
            Transform English Videos to
            <span className="bg-gradient-to-r from-indigo-600 to-purple-600 bg-clip-text text-transparent"> Hindi</span>
          </h2>
          <p className="text-xl text-gray-600 max-w-2xl mx-auto">
            Automatically extract, transcribe, translate, and dub YouTube videos with natural-sounding Hindi voiceovers
          </p>
        </div>

        {/* Input Form */}
        <div className="bg-white rounded-2xl shadow-xl border border-gray-100 p-8 mb-8">
          <form onSubmit={handleSubmit} className="space-y-6">
            <div>
              <label htmlFor="youtube-url" className="block text-sm font-semibold text-gray-700 mb-3">
                YouTube Video URL
              </label>
              <div className="relative">
                <Youtube className="absolute left-4 top-1/2 transform -translate-y-1/2 text-gray-400 w-5 h-5" />
                <input
                  type="url"
                  id="youtube-url"
                  value={youtubeUrl}
                  onChange={(e) => setYoutubeUrl(e.target.value)}
                  placeholder="https://www.youtube.com/watch?v=..."
                  className="w-full pl-12 pr-4 py-4 border border-gray-200 rounded-xl focus:ring-2 focus:ring-indigo-500 focus:border-transparent transition-all duration-200 text-lg"
                  required
                />
              </div>
              {youtubeUrl && !isValidYouTubeUrl(youtubeUrl) && (
                <p className="mt-2 text-sm text-red-600 flex items-center space-x-1">
                  <AlertCircle className="w-4 h-4" />
                  <span>Please enter a valid YouTube URL</span>
                </p>
              )}
            </div>

            <button
              type="submit"
              disabled={!isValidYouTubeUrl(youtubeUrl) || isProcessing}
              className="w-full bg-gradient-to-r from-indigo-500 to-purple-600 text-white py-4 px-6 rounded-xl font-semibold text-lg hover:from-indigo-600 hover:to-purple-700 disabled:opacity-50 disabled:cursor-not-allowed transition-all duration-200 flex items-center justify-center space-x-2"
            >
              {isProcessing ? (
                <>
                  <Loader2 className="w-5 h-5 animate-spin" />
                  <span>Processing...</span>
                </>
              ) : (
                <>
                  <Languages className="w-5 h-5" />
                  <span>Start Translation</span>
                </>
              )}
            </button>
          </form>
        </div>

        {/* Processing Steps */}
        {(isProcessing || showResults) && (
          <div className="bg-white rounded-2xl shadow-xl border border-gray-100 p-8 mb-8">
            <h3 className="text-2xl font-bold text-gray-900 mb-6">Processing Pipeline</h3>
            <div className="space-y-4">
              {steps.map((step, index) => (
                <div key={step.id} className="flex items-center space-x-4 p-4 rounded-xl bg-gray-50 hover:bg-gray-100 transition-colors duration-200">
                  <div className="flex-shrink-0">
                    {getStepStatusIcon(step, index)}
                  </div>
                  <div className="flex-1">
                    <div className="flex items-center space-x-2">
                      {step.icon}
                      <h4 className="font-semibold text-gray-900">{step.title}</h4>
                    </div>
                    <p className="text-gray-600 text-sm mt-1">{step.description}</p>
                  </div>
                  {step.status === 'processing' && (
                    <div className="flex-shrink-0">
                      <div className="w-32 bg-gray-200 rounded-full h-2">
                        <div className="bg-indigo-500 h-2 rounded-full animate-pulse" style={{ width: '60%' }}></div>
                      </div>
                    </div>
                  )}
                </div>
              ))}
            </div>
          </div>
        )}

        {/* Results Section */}
        {showResults && (
          <div className="bg-white rounded-2xl shadow-xl border border-gray-100 p-8">
            <div className="flex items-center space-x-3 mb-6">
              <CheckCircle className="w-8 h-8 text-emerald-500" />
              <div>
                <h3 className="text-2xl font-bold text-gray-900">Translation Complete!</h3>
                <p className="text-gray-600">Your Hindi dubbed video is ready</p>
              </div>
            </div>

            {/* Audio Player */}
            <div className="bg-gradient-to-r from-gray-50 to-gray-100 rounded-xl p-6 mb-6">
              <div className="flex items-center justify-between mb-4">
                <h4 className="font-semibold text-gray-900">Hindi Audio Preview</h4>
                <div className="flex items-center space-x-2 text-sm text-gray-600">
                  <Volume2 className="w-4 h-4" />
                  <span>2:34 duration</span>
                </div>
              </div>
              
              {/* Waveform Visualization */}
              <div className="bg-white rounded-lg p-4 mb-4">
                <div className="flex items-center justify-center space-x-1 h-16">
                  {Array.from({ length: 50 }).map((_, i) => (
                    <div
                      key={i}
                      className="bg-indigo-400 rounded-full animate-pulse"
                      style={{
                        width: '3px',
                        height: `${Math.random() * 40 + 10}px`,
                        animationDelay: `${i * 0.1}s`
                      }}
                    ></div>
                  ))}
                </div>
              </div>

              {/* Audio Controls */}
              <div className="flex items-center justify-center space-x-4">
                <button
                  onClick={() => setIsPlaying(!isPlaying)}
                  className="bg-indigo-500 hover:bg-indigo-600 text-white p-3 rounded-full transition-colors duration-200"
                >
                  {isPlaying ? <Pause className="w-6 h-6" /> : <Play className="w-6 h-6" />}
                </button>
                <div className="flex-1 bg-gray-200 rounded-full h-2 max-w-md">
                  <div className="bg-indigo-500 h-2 rounded-full" style={{ width: '30%' }}></div>
                </div>
                <span className="text-sm text-gray-600">0:45 / 2:34</span>
              </div>
            </div>

            {/* Download Options */}
            <div className="grid md:grid-cols-2 gap-4">
              <button className="flex items-center justify-center space-x-3 bg-emerald-50 hover:bg-emerald-100 text-emerald-700 border border-emerald-200 p-4 rounded-xl transition-colors duration-200">
                <Download className="w-5 h-5" />
                <div className="text-left">
                  <div className="font-semibold">Download Hindi Audio</div>
                  <div className="text-sm opacity-75">MP3 • 3.2 MB</div>
                </div>
              </button>
              <button className="flex items-center justify-center space-x-3 bg-purple-50 hover:bg-purple-100 text-purple-700 border border-purple-200 p-4 rounded-xl transition-colors duration-200">
                <Download className="w-5 h-5" />
                <div className="text-left">
                  <div className="font-semibold">Download Dubbed Video</div>
                  <div className="text-sm opacity-75">MP4 • 15.7 MB</div>
                </div>
              </button>
            </div>

            {/* Quality Metrics */}
            <div className="mt-6 p-4 bg-gray-50 rounded-xl">
              <h5 className="font-semibold text-gray-900 mb-3">Translation Quality</h5>
              <div className="grid grid-cols-2 md:grid-cols-4 gap-4">
                <div className="text-center">
                  <div className="text-2xl font-bold text-emerald-600">98%</div>
                  <div className="text-sm text-gray-600">Accuracy</div>
                </div>
                <div className="text-center">
                  <div className="text-2xl font-bold text-indigo-600">Natural</div>
                  <div className="text-sm text-gray-600">Voice Quality</div>
                </div>
                <div className="text-center">
                  <div className="text-2xl font-bold text-purple-600">+99%</div>
                  <div className="text-sm text-gray-600">Sync Match</div>
                </div>
                <div className="text-center">
                  <div className="text-2xl font-bold text-orange-600">2:34</div>
                  <div className="text-sm text-gray-600">Duration</div>
                </div>
              </div>
            </div>
          </div>
        )}

        {/* Feature Highlights */}
        {!isProcessing && !showResults && (
          <div className="grid md:grid-cols-3 gap-6 mt-12">
            <div className="bg-white rounded-xl p-6 shadow-lg border border-gray-100 hover:shadow-xl transition-shadow duration-200">
              <div className="bg-indigo-100 w-12 h-12 rounded-lg flex items-center justify-center mb-4">
                <Mic className="w-6 h-6 text-indigo-600" />
              </div>
              <h3 className="font-semibold text-gray-900 mb-2">High-Quality Transcription</h3>
              <p className="text-gray-600 text-sm">Advanced AI accurately converts speech to text with 99%+ accuracy</p>
            </div>

            <div className="bg-white rounded-xl p-6 shadow-lg border border-gray-100 hover:shadow-xl transition-shadow duration-200">
              <div className="bg-emerald-100 w-12 h-12 rounded-lg flex items-center justify-center mb-4">
                <Languages className="w-6 h-6 text-emerald-600" />
              </div>
              <h3 className="font-semibold text-gray-900 mb-2">Natural Translation</h3>
              <p className="text-gray-600 text-sm">Context-aware translation that preserves meaning and cultural nuances</p>
            </div>

            <div className="bg-white rounded-xl p-6 shadow-lg border border-gray-100 hover:shadow-xl transition-shadow duration-200">
              <div className="bg-purple-100 w-12 h-12 rounded-lg flex items-center justify-center mb-4">
                <Speaker className="w-6 h-6 text-purple-600" />
              </div>
              <h3 className="font-semibold text-gray-900 mb-2">Realistic Voice Synthesis</h3>
              <p className="text-gray-600 text-sm">Natural-sounding Hindi voices with proper intonation and emotion</p>
            </div>
          </div>
        )}
      </div>
    </div>
  );
}

export default App;