| import gradio as gr |
| import os |
| import tempfile |
| import shutil |
| from datetime import datetime |
| from pathlib import Path |
|
|
| 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 |
| |
| |
| 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' |
| |
| |
| temp_dir = tempfile.mkdtemp() |
| dest_path = os.path.join(temp_dir, filename) |
| |
| try: |
| |
| if isinstance(video_path, str) and os.path.exists(video_path): |
| shutil.copy2(video_path, dest_path) |
| else: |
| |
| 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 clear_all(): |
| """Clear all inputs and outputs""" |
| return 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, "" |
|
|
| |
| with gr.Blocks(title="🎥 Simple Video Recorder") as demo: |
| |
| gr.Markdown(""" |
| # 🎥 Simple Video Recorder |
| Record a video using your webcam or upload an existing video file. Then download it with a custom filename! |
| """) |
| |
| 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 |
| ) |
| |
| filename_input = gr.Textbox( |
| label="Download Filename (optional)", |
| placeholder="my_video.mp4 or leave blank for auto-name", |
| info="Leave blank for automatic naming: originalname_timestamp.mp4" |
| ) |
| |
| with gr.Row(): |
| process_btn = gr.Button("📥 Prepare for Download", 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=3 |
| ) |
| |
| video_display = gr.Video( |
| label="Preview", |
| interactive=False, |
| height=300 |
| ) |
| |
| download_file = gr.File( |
| label="Download Video", |
| interactive=False, |
| file_types=[".mp4", ".mov", ".avi", ".webm"] |
| ) |
| |
| |
| video_input.change( |
| fn=update_video_display, |
| inputs=[video_input], |
| outputs=[video_display, status_output] |
| ) |
| |
| |
| process_btn.click( |
| fn=save_video, |
| inputs=[video_input, filename_input], |
| outputs=[status_output, download_file] |
| ) |
| |
| |
| clear_btn.click( |
| fn=clear_all, |
| outputs=[video_input, video_display, download_file, status_output] |
| ) |
| |
| |
| gr.Markdown(""" |
| ## 📋 How to Use: |
| 1. **Record**: Click the webcam icon to record a video using your camera |
| 2. **Upload**: Click the upload button to select a video file from your computer |
| 3. **Optional**: Enter a custom filename for download (or leave blank for auto-naming) |
| 4. **Prepare**: Click "Prepare for Download" to generate the downloadable file |
| 5. **Download**: Click the download button that appears in the Download section |
| |
| ## 📝 Notes: |
| - Supported formats: MP4, MOV, AVI, WebM |
| - Videos are processed temporarily and can be downloaded immediately |
| - Use "Clear All" to start fresh |
| """) |
|
|
| |
| if __name__ == "__main__": |
| demo.launch( |
| theme="soft", |
| css=""" |
| .gradio-container {max-width: 900px !important;} |
| .video-container {border-radius: 10px; overflow: hidden;} |
| .status-box {background: #f0f7ff; padding: 15px; border-radius: 8px; border-left: 4px solid #4a90e2;} |
| """ |
| ) |