Artificial-superintelligence commited on
Commit
716c1e6
·
verified ·
1 Parent(s): 735f163

Update app.py

Browse files
Files changed (1) hide show
  1. app.py +78 -39
app.py CHANGED
@@ -7,31 +7,30 @@ from moviepy.video.io.VideoFileClip import VideoFileClip
7
 
8
  # Function to sanitize the filename
9
  def sanitize_filename(title):
10
- # Replace invalid characters with an underscore
11
  return re.sub(r'[<>:"/\\|?*]', '_', title)
12
 
13
  # Function to download video and return the file path
14
  def download_video(url):
15
- # Use /tmp for temporary storage in Hugging Face Spaces
16
  download_path = '/tmp/downloads'
17
  if not os.path.exists(download_path):
18
  os.makedirs(download_path)
19
 
20
  ydl_opts = {
21
  'outtmpl': os.path.join(download_path, '%(title)s.%(ext)s'),
22
- 'format': 'mp4/bestvideo[ext=mp4]+bestaudio[ext=m4a]/best[ext=mp4]/best', # Prefer MP4 format
23
  'merge_output_format': 'mp4',
 
24
  }
25
 
26
  try:
27
  with yt_dlp.YoutubeDL(ydl_opts) as ydl:
28
- info_dict = ydl.extract_info(url, download=True)
29
- title = info_dict.get('title', None)
30
- if title:
31
- sanitized_title = sanitize_filename(title)
32
- file_path = os.path.join(download_path, f"{sanitized_title}.mp4")
33
- return file_path if os.path.exists(file_path) else None
34
- return None
35
  except Exception as e:
36
  print(f"Download error: {str(e)}")
37
  return None
@@ -41,17 +40,26 @@ def crop_video(input_path, start_time, end_time):
41
  if not input_path or not os.path.exists(input_path):
42
  return None
43
 
44
- output_path = os.path.join('/tmp/downloads', 'cropped_video.mp4')
45
  try:
46
  with VideoFileClip(input_path) as video:
47
- # Ensure end_time doesn't exceed video duration
48
  duration = video.duration
49
  end_time = min(end_time, duration)
50
- if start_time >= end_time:
51
- return None
 
 
 
52
 
53
  cropped_video = video.subclip(start_time, end_time)
54
- cropped_video.write_videofile(output_path, codec='libx264', audio_codec='aac')
 
 
 
 
 
 
 
55
  return output_path if os.path.exists(output_path) else None
56
  except Exception as e:
57
  print(f"Cropping error: {str(e)}")
@@ -59,25 +67,35 @@ def crop_video(input_path, start_time, end_time):
59
 
60
  # Main processing function
61
  def process_video(url, start_time, end_time):
62
- if not url:
63
- return None
64
-
65
  try:
66
- # Download the video
 
 
 
 
 
 
 
67
  video_path = download_video(url)
68
  if not video_path:
69
- return None
70
 
71
- # Crop the video
72
- cropped_path = crop_video(video_path, start_time, end_time)
73
- if cropped_path and os.path.exists(cropped_path):
74
- time.sleep(1) # Ensure file is fully written
75
- return cropped_path
76
 
77
- return None
 
 
 
 
 
 
 
78
  except Exception as e:
79
  print(f"Processing error: {str(e)}")
80
- return None
81
 
82
  # Create Gradio interface
83
  def create_interface():
@@ -87,34 +105,55 @@ def create_interface():
87
  with gr.Row():
88
  url_input = gr.Textbox(
89
  label="YouTube URL",
90
- placeholder="Enter YouTube video URL here..."
 
91
  )
92
-
93
  with gr.Row():
94
  start_time_input = gr.Number(
95
  label="Start Time (seconds)",
96
  value=0,
97
- minimum=0
 
98
  )
99
  end_time_input = gr.Number(
100
  label="End Time (seconds)",
101
  value=10,
102
- minimum=0
 
103
  )
104
-
105
  with gr.Row():
106
  process_btn = gr.Button("Download and Crop Video")
107
- output_file = gr.File(label="Download Cropped Video")
 
 
108
 
109
- # Connect the button to the processing function
 
 
 
 
 
 
 
 
110
  process_btn.click(
111
- fn=process_video,
112
  inputs=[url_input, start_time_input, end_time_input],
113
- outputs=output_file
114
  )
115
-
116
  return demo
117
 
118
  # Launch the app
119
- demo = create_interface()
120
- demo.launch()
 
 
 
 
 
 
 
 
 
7
 
8
  # Function to sanitize the filename
9
  def sanitize_filename(title):
 
10
  return re.sub(r'[<>:"/\\|?*]', '_', title)
11
 
12
  # Function to download video and return the file path
13
  def download_video(url):
 
14
  download_path = '/tmp/downloads'
15
  if not os.path.exists(download_path):
16
  os.makedirs(download_path)
17
 
18
  ydl_opts = {
19
  'outtmpl': os.path.join(download_path, '%(title)s.%(ext)s'),
20
+ 'format': 'best[ext=mp4]/best', # Simplified format selection
21
  'merge_output_format': 'mp4',
22
+ 'max_filesize': 100 * 1024 * 1024, # 100MB limit
23
  }
24
 
25
  try:
26
  with yt_dlp.YoutubeDL(ydl_opts) as ydl:
27
+ info = ydl.extract_info(url, download=True)
28
+ video_path = ydl.prepare_filename(info)
29
+ if os.path.exists(video_path):
30
+ return video_path
31
+ # If the file extension is different from mp4, look for the actual file
32
+ possible_path = video_path.rsplit('.', 1)[0] + '.mp4'
33
+ return possible_path if os.path.exists(possible_path) else None
34
  except Exception as e:
35
  print(f"Download error: {str(e)}")
36
  return None
 
40
  if not input_path or not os.path.exists(input_path):
41
  return None
42
 
43
+ output_path = os.path.join('/tmp/downloads', f'cropped_{int(time.time())}.mp4')
44
  try:
45
  with VideoFileClip(input_path) as video:
 
46
  duration = video.duration
47
  end_time = min(end_time, duration)
48
+ start_time = max(0, min(start_time, end_time - 1))
49
+
50
+ # Limit output duration to 60 seconds
51
+ if end_time - start_time > 60:
52
+ end_time = start_time + 60
53
 
54
  cropped_video = video.subclip(start_time, end_time)
55
+ # Use lower quality settings for faster processing
56
+ cropped_video.write_videofile(
57
+ output_path,
58
+ codec='libx264',
59
+ audio_codec='aac',
60
+ preset='ultrafast',
61
+ bitrate='1000k'
62
+ )
63
  return output_path if os.path.exists(output_path) else None
64
  except Exception as e:
65
  print(f"Cropping error: {str(e)}")
 
67
 
68
  # Main processing function
69
  def process_video(url, start_time, end_time):
 
 
 
70
  try:
71
+ if not url or not url.strip():
72
+ return gr.File.update(value=None, visible=True)
73
+
74
+ # Add basic URL validation
75
+ if not url.startswith(('http://', 'https://')):
76
+ return gr.File.update(value=None, visible=True)
77
+
78
+ # Download video
79
  video_path = download_video(url)
80
  if not video_path:
81
+ return gr.File.update(value=None, visible=True)
82
 
83
+ # Crop video
84
+ cropped_path = crop_video(video_path, float(start_time), float(end_time))
85
+ if not cropped_path:
86
+ return gr.File.update(value=None, visible=True)
 
87
 
88
+ # Clean up original video
89
+ try:
90
+ os.remove(video_path)
91
+ except:
92
+ pass
93
+
94
+ return gr.File.update(value=cropped_path, visible=True)
95
+
96
  except Exception as e:
97
  print(f"Processing error: {str(e)}")
98
+ return gr.File.update(value=None, visible=True)
99
 
100
  # Create Gradio interface
101
  def create_interface():
 
105
  with gr.Row():
106
  url_input = gr.Textbox(
107
  label="YouTube URL",
108
+ placeholder="Enter YouTube video URL here...",
109
+ max_lines=1
110
  )
111
+
112
  with gr.Row():
113
  start_time_input = gr.Number(
114
  label="Start Time (seconds)",
115
  value=0,
116
+ minimum=0,
117
+ maximum=3600 # 1 hour max
118
  )
119
  end_time_input = gr.Number(
120
  label="End Time (seconds)",
121
  value=10,
122
+ minimum=1,
123
+ maximum=3600 # 1 hour max
124
  )
125
+
126
  with gr.Row():
127
  process_btn = gr.Button("Download and Crop Video")
128
+
129
+ with gr.Row():
130
+ output_file = gr.File(label="Cropped Video", visible=True)
131
 
132
+ # Add error message component
133
+ error_message = gr.Markdown(visible=False)
134
+
135
+ def process_with_error_handling(*args):
136
+ try:
137
+ return process_video(*args)
138
+ except Exception as e:
139
+ return gr.File.update(value=None, visible=True)
140
+
141
  process_btn.click(
142
+ fn=process_with_error_handling,
143
  inputs=[url_input, start_time_input, end_time_input],
144
+ outputs=[output_file]
145
  )
146
+
147
  return demo
148
 
149
  # Launch the app
150
+ if __name__ == "__main__":
151
+ demo = create_interface()
152
+ demo.queue() # Enable queuing
153
+ demo.launch(
154
+ share=False,
155
+ debug=True,
156
+ server_name="0.0.0.0",
157
+ server_port=7860,
158
+ max_threads=3
159
+ )