import gradio as gr import os import tempfile import shutil from datetime import datetime from pathlib import Path import moviepy.editor as mp def extract_audio(video_path, filename=None): """Extract audio from video and save as MP3""" if video_path is None: return "❌ Please upload or record a video first!", None # Generate filename if not provided if not filename: timestamp = datetime.now().strftime("%Y%m%d_%H%M%S") if hasattr(video_path, 'name'): original_name = Path(video_path.name).stem filename = f"{original_name}_{timestamp}.mp3" else: filename = f"audio_{timestamp}.mp3" elif not filename.endswith('.mp3'): filename += '.mp3' # Create temp directory for the audio file temp_dir = tempfile.mkdtemp() audio_path = os.path.join(temp_dir, filename) try: # Extract audio using moviepy video = mp.VideoFileClip(video_path) audio = video.audio if audio is None: return "❌ No audio found in the video!", None # Write audio to file audio.write_audiofile(audio_path, verbose=False, logger=None) # Close the clips to free resources audio.close() video.close() return f"✅ Audio extracted successfully: {filename}", audio_path except Exception as e: return f"❌ Error extracting audio: {str(e)}", None def save_video(video_path, filename=None): """Save video to a temporary file for download""" if video_path is None: return "❌ Please upload or record a video first!", None # Generate filename if not provided if not filename: timestamp = datetime.now().strftime("%Y%m%d_%H%M%S") if hasattr(video_path, 'name'): original_name = Path(video_path.name).stem filename = f"{original_name}_{timestamp}.mp4" else: filename = f"video_{timestamp}.mp4" elif not filename.endswith('.mp4'): filename += '.mp4' # Create temp directory for the download file temp_dir = tempfile.mkdtemp() dest_path = os.path.join(temp_dir, filename) try: # Copy the video to temp location if isinstance(video_path, str) and os.path.exists(video_path): shutil.copy2(video_path, dest_path) else: # Handle Gradio's temporary file object with open(video_path, 'rb') as src: with open(dest_path, 'wb') as dst: shutil.copyfileobj(src, dst) return f"✅ Video ready for download: {filename}", dest_path except Exception as e: return f"❌ Error processing video: {str(e)}", None def process_all(video_path, video_filename=None, audio_filename=None): """Process both video and audio extraction""" if video_path is None: return "❌ Please upload or record a video first!", None, None, None, None # Process video video_status, video_file = save_video(video_path, video_filename) # Process audio extraction audio_status, audio_file = extract_audio(video_path, audio_filename) # Combine status messages combined_status = f"{video_status}\n{audio_status}" return combined_status, video_file, audio_file def clear_all(): """Clear all inputs and outputs""" return None, None, None, "", None, None def update_video_display(video_path): """Update the video display when a new video is uploaded/recorded""" if video_path: return video_path, f"📹 Video loaded: {os.path.basename(video_path) if hasattr(video_path, 'name') else 'Recorded video'}" return None, "" # Create the Gradio interface with gr.Blocks(title="🎥 Video Recorder with Audio Extraction") as demo: gr.Markdown(""" # 🎥 Video Recorder with Audio Extraction Record or upload a video, then download both the video file and extracted MP3 audio! """) with gr.Row(): with gr.Column(scale=1): gr.Markdown("### 📤 Input") video_input = gr.Video( label="Record or Upload Video", sources=["webcam", "upload"], interactive=True, include_audio=True, height=300 ) with gr.Group(): gr.Markdown("**📁 Filename Options**") video_filename = gr.Textbox( label="Video Filename (optional)", placeholder="my_video.mp4 or leave blank for auto-name", info="Leave blank for automatic naming" ) audio_filename = gr.Textbox( label="Audio Filename (optional)", placeholder="my_audio.mp3 or leave blank for auto-name", info="Leave blank for automatic naming" ) with gr.Row(): process_btn = gr.Button("📥 Process Video & Audio", variant="primary", scale=2) clear_btn = gr.Button("🗑️ Clear All", variant="secondary", scale=1) with gr.Column(scale=1): gr.Markdown("### 📥 Output") status_output = gr.Textbox( label="Status", value="👋 Ready to record or upload a video!", interactive=False, lines=5 ) video_display = gr.Video( label="Video Preview", interactive=False, height=300 ) with gr.Tabs(): with gr.TabItem("🎬 Download Video"): download_video = gr.File( label="Download Video File", interactive=False, file_types=[".mp4", ".mov", ".avi", ".webm"] ) with gr.TabItem("🎵 Download Audio"): download_audio = gr.File( label="Download MP3 Audio", interactive=False, file_types=[".mp3"] ) # Update video display and status when video is uploaded/recorded video_input.change( fn=update_video_display, inputs=[video_input], outputs=[video_display, status_output] ) # Process both video and audio process_btn.click( fn=process_all, inputs=[video_input, video_filename, audio_filename], outputs=[status_output, download_video, download_audio] ) # Clear all inputs and outputs clear_btn.click( fn=clear_all, outputs=[video_input, video_display, download_video, status_output, video_filename, audio_filename] ) # Instructions gr.Markdown(""" ## 📋 How to Use: 1. **Record**: Click the webcam icon to record a video 2. **Upload**: Click the upload button to select a video file 3. **Optional**: Enter custom filenames for video and audio 4. **Process**: Click "Process Video & Audio" to generate both files 5. **Download**: Use the tabs to download video (MP4) or audio (MP3) ## 📝 Notes: - Supported video formats: MP4, MOV, AVI, WebM - Audio is extracted and saved as MP3 - Videos are processed temporarily and can be downloaded immediately - Use "Clear All" to start fresh ## 🎵 Audio Extraction: - Extracts audio track from video files - Saves as high-quality MP3 - Works with any video that contains audio """) # Launch configuration if __name__ == "__main__": demo.launch( theme="soft", css=""" .gradio-container {max-width: 1000px !important;} .video-container {border-radius: 10px; overflow: hidden;} .status-box {background: #f0f7ff; padding: 15px; border-radius: 8px; border-left: 4px solid #4a90e2;} .tabs {margin-top: 20px;} """ )