| | import gradio as gr |
| | import yt_dlp |
| | import os |
| | import re |
| | import time |
| | from moviepy.video.io.VideoFileClip import VideoFileClip |
| |
|
| | |
| | def sanitize_filename(title): |
| | return re.sub(r'[<>:"/\\|?*]', '_', title) |
| |
|
| | |
| | def download_video(url): |
| | download_path = '/tmp/downloads' |
| | if not os.path.exists(download_path): |
| | os.makedirs(download_path) |
| | |
| | ydl_opts = { |
| | 'outtmpl': os.path.join(download_path, '%(title)s.%(ext)s'), |
| | 'format': 'best[ext=mp4]/best', |
| | 'merge_output_format': 'mp4', |
| | 'max_filesize': 100 * 1024 * 1024, |
| | } |
| | |
| | try: |
| | with yt_dlp.YoutubeDL(ydl_opts) as ydl: |
| | info = ydl.extract_info(url, download=True) |
| | video_path = ydl.prepare_filename(info) |
| | if os.path.exists(video_path): |
| | return video_path |
| | |
| | possible_path = video_path.rsplit('.', 1)[0] + '.mp4' |
| | return possible_path if os.path.exists(possible_path) else None |
| | except Exception as e: |
| | print(f"Download error: {str(e)}") |
| | return None |
| |
|
| | |
| | def crop_video(input_path, start_time, end_time): |
| | if not input_path or not os.path.exists(input_path): |
| | return None |
| | |
| | output_path = os.path.join('/tmp/downloads', f'cropped_{int(time.time())}.mp4') |
| | try: |
| | with VideoFileClip(input_path) as video: |
| | duration = video.duration |
| | end_time = min(end_time, duration) |
| | start_time = max(0, min(start_time, end_time - 1)) |
| | |
| | |
| | if end_time - start_time > 60: |
| | end_time = start_time + 60 |
| | |
| | cropped_video = video.subclip(start_time, end_time) |
| | |
| | cropped_video.write_videofile( |
| | output_path, |
| | codec='libx264', |
| | audio_codec='aac', |
| | preset='ultrafast', |
| | bitrate='1000k' |
| | ) |
| | return output_path if os.path.exists(output_path) else None |
| | except Exception as e: |
| | print(f"Cropping error: {str(e)}") |
| | return None |
| |
|
| | |
| | def process_video(url, start_time, end_time): |
| | try: |
| | if not url or not url.strip(): |
| | return gr.File.update(value=None, visible=True) |
| | |
| | |
| | if not url.startswith(('http://', 'https://')): |
| | return gr.File.update(value=None, visible=True) |
| | |
| | |
| | video_path = download_video(url) |
| | if not video_path: |
| | return gr.File.update(value=None, visible=True) |
| | |
| | |
| | cropped_path = crop_video(video_path, float(start_time), float(end_time)) |
| | if not cropped_path: |
| | return gr.File.update(value=None, visible=True) |
| | |
| | |
| | try: |
| | os.remove(video_path) |
| | except: |
| | pass |
| | |
| | return gr.File.update(value=cropped_path, visible=True) |
| | |
| | except Exception as e: |
| | print(f"Processing error: {str(e)}") |
| | return gr.File.update(value=None, visible=True) |
| |
|
| | |
| | def create_interface(): |
| | with gr.Blocks() as demo: |
| | gr.Markdown("# YouTube Video Downloader and Cropper") |
| | |
| | with gr.Row(): |
| | url_input = gr.Textbox( |
| | label="YouTube URL", |
| | placeholder="Enter YouTube video URL here...", |
| | max_lines=1 |
| | ) |
| | |
| | with gr.Row(): |
| | start_time_input = gr.Number( |
| | label="Start Time (seconds)", |
| | value=0, |
| | minimum=0, |
| | maximum=3600 |
| | ) |
| | end_time_input = gr.Number( |
| | label="End Time (seconds)", |
| | value=10, |
| | minimum=1, |
| | maximum=3600 |
| | ) |
| | |
| | with gr.Row(): |
| | process_btn = gr.Button("Download and Crop Video") |
| | |
| | with gr.Row(): |
| | output_file = gr.File(label="Cropped Video", visible=True) |
| | |
| | |
| | error_message = gr.Markdown(visible=False) |
| | |
| | def process_with_error_handling(*args): |
| | try: |
| | return process_video(*args) |
| | except Exception as e: |
| | return gr.File.update(value=None, visible=True) |
| | |
| | process_btn.click( |
| | fn=process_with_error_handling, |
| | inputs=[url_input, start_time_input, end_time_input], |
| | outputs=[output_file] |
| | ) |
| | |
| | return demo |
| |
|
| | |
| | if __name__ == "__main__": |
| | demo = create_interface() |
| | demo.queue() |
| | demo.launch( |
| | share=False, |
| | debug=True, |
| | server_name="0.0.0.0", |
| | server_port=7860, |
| | max_threads=3 |
| | ) |