gnosticdev commited on
Commit
2acde19
verified
1 Parent(s): abed2e9

Update app.py

Browse files
Files changed (1) hide show
  1. app.py +36 -16
app.py CHANGED
@@ -6,6 +6,7 @@ from moviepy.editor import (
6
  concatenate_audioclips, concatenate_videoclips, vfx, CompositeVideoClip,
7
  ColorClip
8
  )
 
9
  import asyncio
10
  import os
11
  import json
@@ -30,6 +31,7 @@ os.makedirs(temp_dir, exist_ok=True)
30
  FOLDER_ID = "12S6adpanAXjf71pKKGRRPqpzbJa5XEh3"
31
 
32
  def cleanup_temp_files():
 
33
  for filename in os.listdir(temp_dir):
34
  file_path = os.path.join(temp_dir, filename)
35
  try:
@@ -39,37 +41,44 @@ def cleanup_temp_files():
39
  print(f"Error deleting {file_path}: {e}")
40
 
41
  def resize_and_blur_video(clip, target_width=1920, target_height=1080):
 
42
  try:
43
  w, h = clip.size
44
  current_aspect_ratio = w / h
45
  target_aspect_ratio = target_width / target_height
46
 
47
  if abs(current_aspect_ratio - target_aspect_ratio) < 0.1:
 
48
  return clip.resize((target_width, target_height))
49
 
 
50
  background = ColorClip(size=(target_width, target_height), color=[0, 0, 0]).set_duration(clip.duration)
51
  try:
52
- background = background.fx(vfx.blur, sigma=50)
 
53
  except Exception as e:
54
- print(f"Error al aplicar blur: {e}")
55
 
56
- if current_aspect_ratio < target_aspect_ratio:
 
57
  new_height = target_height
58
  new_width = int(new_height * current_aspect_ratio)
59
  x_center = (target_width - new_width) / 2
60
  resized_clip = clip.resize(width=new_width).set_position((x_center, 0))
61
- else:
62
  new_width = target_width
63
  new_height = int(new_width / current_aspect_ratio)
64
  y_center = (target_height - new_height) / 2
65
  resized_clip = clip.resize(height=new_height).set_position((0, y_center))
66
 
 
67
  return CompositeVideoClip([background, resized_clip], size=(target_width, target_height))
68
  except Exception as e:
69
  print(f"Error en resize_and_blur_video: {e}")
70
  return clip
71
 
72
  def download_video(link):
 
73
  try:
74
  video_response = requests.get(link)
75
  if video_response.status_code != 200:
@@ -83,12 +92,14 @@ def download_video(link):
83
  return None
84
 
85
  def concatenate_pixabay_videos(keywords, num_videos_per_keyword=1):
 
86
  keyword_list = [keyword.strip() for keyword in keywords.split(",") if keyword.strip()]
87
  if not keyword_list:
88
- keyword_list = ["nature"]
89
  video_clips = []
90
  for keyword in keyword_list:
91
  try:
 
92
  links = search_pixabay(keyword, num_results=num_videos_per_keyword)
93
  if not links:
94
  print(f"No se encontraron videos para '{keyword}', probando con 'nature'")
@@ -100,16 +111,18 @@ def concatenate_pixabay_videos(keywords, num_videos_per_keyword=1):
100
  clip = VideoFileClip(temp_video_path)
101
  processed_clip = resize_and_blur_video(clip)
102
  video_clips.append(processed_clip)
103
- os.remove(temp_video_path)
104
  except Exception as e:
105
  print(f"Error procesando palabra clave '{keyword}': {e}")
106
  continue
107
  if not video_clips:
 
108
  return ColorClip(size=(1920, 1080), color=[0, 0, 0], duration=5)
109
  random.shuffle(video_clips)
110
  return concatenate_videoclips(video_clips, method="compose")
111
 
112
  def adjust_background_music(video_duration, music_file):
 
113
  try:
114
  music = AudioFileClip(music_file)
115
  if music.duration < video_duration:
@@ -122,57 +135,63 @@ def adjust_background_music(video_duration, music_file):
122
  print(f"Error ajustando m煤sica: {e}")
123
  return None
124
 
125
- def calculate_real_duration(video):
126
- frame_time = 1 / video.fps
127
- total_frames = int(video.duration * video.fps)
128
- real_duration = total_frames * frame_time
129
- return real_duration
130
-
131
  def combine_audio_video(audio_file, video_clip, music_clip=None):
 
132
  try:
133
  audio_clip = AudioFileClip(audio_file)
134
- total_duration = audio_clip.duration + 2
135
 
136
- # Ajustar la duraci贸n del video al 煤ltimo fotograma v谩lido
137
- real_duration = calculate_real_duration(video_clip)
138
- video_clip = video_clip.subclip(0, min(real_duration, total_duration)).loop(duration=total_duration)
139
  video_clip = video_clip.set_duration(total_duration).fadeout(2)
140
 
 
141
  final_clip = video_clip.set_audio(audio_clip)
 
142
  if music_clip:
143
  music_clip = music_clip.set_duration(total_duration).audio_fadeout(2)
144
  final_clip = final_clip.set_audio(CompositeAudioClip([audio_clip, music_clip]))
145
 
 
146
  output_filename = f"final_video_{int(time.time())}.mp4"
147
  output_path = os.path.join(output_folder, output_filename)
 
 
148
  final_clip.write_videofile(output_path, codec="libx264", audio_codec="aac", fps=24)
 
 
149
  final_clip.close()
150
  video_clip.close()
151
  audio_clip.close()
152
  if music_clip:
153
  music_clip.close()
 
154
  return output_path
155
  except Exception as e:
156
  print(f"Error combinando audio y video: {e}")
157
  return None
158
 
159
  def upload_to_google_drive(file_path, folder_id):
 
160
  try:
161
  creds = service_account.Credentials.from_service_account_file(
162
  'service-account.json', scopes=['https://www.googleapis.com/auth/drive']
163
  )
164
  service = build('drive', 'v3', credentials=creds)
 
165
  file_metadata = {
166
  'name': os.path.basename(file_path),
167
  'parents': [folder_id]
168
  }
169
  media = MediaFileUpload(file_path, resumable=True)
170
  file = service.files().create(body=file_metadata, media_body=media, fields='id').execute()
 
171
  permission = {
172
  'type': 'anyone',
173
  'role': 'reader'
174
  }
175
  service.permissions().create(fileId=file['id'], body=permission).execute()
 
176
  file_id = file['id']
177
  download_link = f"https://drive.google.com/uc?export=download&id={file_id}"
178
  return download_link
@@ -181,6 +200,7 @@ def upload_to_google_drive(file_path, folder_id):
181
  return None
182
 
183
  def process_input(text, txt_file, mp3_file, selected_voice, rate, pitch, keywords):
 
184
  try:
185
  if text.strip():
186
  final_text = text
 
6
  concatenate_audioclips, concatenate_videoclips, vfx, CompositeVideoClip,
7
  ColorClip
8
  )
9
+ from scipy.ndimage import gaussian_filter
10
  import asyncio
11
  import os
12
  import json
 
31
  FOLDER_ID = "12S6adpanAXjf71pKKGRRPqpzbJa5XEh3"
32
 
33
  def cleanup_temp_files():
34
+ """Elimina todos los archivos temporales de la carpeta temp_files."""
35
  for filename in os.listdir(temp_dir):
36
  file_path = os.path.join(temp_dir, filename)
37
  try:
 
41
  print(f"Error deleting {file_path}: {e}")
42
 
43
  def resize_and_blur_video(clip, target_width=1920, target_height=1080):
44
+ """Redimensiona el video al tama帽o 1080p (16:9) y aplica desenfoque si es necesario."""
45
  try:
46
  w, h = clip.size
47
  current_aspect_ratio = w / h
48
  target_aspect_ratio = target_width / target_height
49
 
50
  if abs(current_aspect_ratio - target_aspect_ratio) < 0.1:
51
+ # Si la relaci贸n de aspecto ya es cercana a 16:9, solo redimensionamos
52
  return clip.resize((target_width, target_height))
53
 
54
+ # Crear un fondo borroso con las dimensiones objetivo
55
  background = ColorClip(size=(target_width, target_height), color=[0, 0, 0]).set_duration(clip.duration)
56
  try:
57
+ # Aplicar filtro gaussiano como alternativa al blur
58
+ background = background.fx(vfx, lambda gf: gaussian_filter(gf, sigma=5))
59
  except Exception as e:
60
+ print(f"Error al aplicar filtro gaussiano: {e}")
61
 
62
+ # Redimensionar el video original para mantener su proporci贸n
63
+ if current_aspect_ratio < target_aspect_ratio: # Video vertical
64
  new_height = target_height
65
  new_width = int(new_height * current_aspect_ratio)
66
  x_center = (target_width - new_width) / 2
67
  resized_clip = clip.resize(width=new_width).set_position((x_center, 0))
68
+ else: # Video horizontal
69
  new_width = target_width
70
  new_height = int(new_width / current_aspect_ratio)
71
  y_center = (target_height - new_height) / 2
72
  resized_clip = clip.resize(height=new_height).set_position((0, y_center))
73
 
74
+ # Combinar el fondo borroso con el video redimensionado
75
  return CompositeVideoClip([background, resized_clip], size=(target_width, target_height))
76
  except Exception as e:
77
  print(f"Error en resize_and_blur_video: {e}")
78
  return clip
79
 
80
  def download_video(link):
81
+ """Descarga un video desde un enlace y lo guarda en la carpeta temporal."""
82
  try:
83
  video_response = requests.get(link)
84
  if video_response.status_code != 200:
 
92
  return None
93
 
94
  def concatenate_pixabay_videos(keywords, num_videos_per_keyword=1):
95
+ """Concatena videos de Pixabay basados en palabras clave."""
96
  keyword_list = [keyword.strip() for keyword in keywords.split(",") if keyword.strip()]
97
  if not keyword_list:
98
+ keyword_list = ["nature"] # Palabra clave por defecto
99
  video_clips = []
100
  for keyword in keyword_list:
101
  try:
102
+ print(f"Buscando videos para la palabra clave '{keyword}'...")
103
  links = search_pixabay(keyword, num_results=num_videos_per_keyword)
104
  if not links:
105
  print(f"No se encontraron videos para '{keyword}', probando con 'nature'")
 
111
  clip = VideoFileClip(temp_video_path)
112
  processed_clip = resize_and_blur_video(clip)
113
  video_clips.append(processed_clip)
114
+ os.remove(temp_video_path) # Eliminar archivo temporal despu茅s de usarlo
115
  except Exception as e:
116
  print(f"Error procesando palabra clave '{keyword}': {e}")
117
  continue
118
  if not video_clips:
119
+ # Si no hay videos, creamos un clip negro de 5 segundos
120
  return ColorClip(size=(1920, 1080), color=[0, 0, 0], duration=5)
121
  random.shuffle(video_clips)
122
  return concatenate_videoclips(video_clips, method="compose")
123
 
124
  def adjust_background_music(video_duration, music_file):
125
+ """Ajusta la m煤sica de fondo para que coincida con la duraci贸n del video."""
126
  try:
127
  music = AudioFileClip(music_file)
128
  if music.duration < video_duration:
 
135
  print(f"Error ajustando m煤sica: {e}")
136
  return None
137
 
 
 
 
 
 
 
138
  def combine_audio_video(audio_file, video_clip, music_clip=None):
139
+ """Combina el audio y el video en un archivo final."""
140
  try:
141
  audio_clip = AudioFileClip(audio_file)
142
+ total_duration = audio_clip.duration + 2 # A帽adimos 2 segundos extra
143
 
144
+ # Aseguramos que el video tenga la duraci贸n correcta
145
+ video_clip = video_clip.loop(duration=total_duration)
 
146
  video_clip = video_clip.set_duration(total_duration).fadeout(2)
147
 
148
+ # Combinamos el audio principal
149
  final_clip = video_clip.set_audio(audio_clip)
150
+ # A帽adimos la m煤sica de fondo si existe
151
  if music_clip:
152
  music_clip = music_clip.set_duration(total_duration).audio_fadeout(2)
153
  final_clip = final_clip.set_audio(CompositeAudioClip([audio_clip, music_clip]))
154
 
155
+ # Generamos el nombre del archivo y la ruta
156
  output_filename = f"final_video_{int(time.time())}.mp4"
157
  output_path = os.path.join(output_folder, output_filename)
158
+
159
+ # Guardamos el video
160
  final_clip.write_videofile(output_path, codec="libx264", audio_codec="aac", fps=24)
161
+
162
+ # Limpiamos los clips
163
  final_clip.close()
164
  video_clip.close()
165
  audio_clip.close()
166
  if music_clip:
167
  music_clip.close()
168
+
169
  return output_path
170
  except Exception as e:
171
  print(f"Error combinando audio y video: {e}")
172
  return None
173
 
174
  def upload_to_google_drive(file_path, folder_id):
175
+ """Sube un archivo a Google Drive y devuelve el enlace p煤blico."""
176
  try:
177
  creds = service_account.Credentials.from_service_account_file(
178
  'service-account.json', scopes=['https://www.googleapis.com/auth/drive']
179
  )
180
  service = build('drive', 'v3', credentials=creds)
181
+
182
  file_metadata = {
183
  'name': os.path.basename(file_path),
184
  'parents': [folder_id]
185
  }
186
  media = MediaFileUpload(file_path, resumable=True)
187
  file = service.files().create(body=file_metadata, media_body=media, fields='id').execute()
188
+
189
  permission = {
190
  'type': 'anyone',
191
  'role': 'reader'
192
  }
193
  service.permissions().create(fileId=file['id'], body=permission).execute()
194
+
195
  file_id = file['id']
196
  download_link = f"https://drive.google.com/uc?export=download&id={file_id}"
197
  return download_link
 
200
  return None
201
 
202
  def process_input(text, txt_file, mp3_file, selected_voice, rate, pitch, keywords):
203
+ """Procesa la entrada del usuario y genera el video final."""
204
  try:
205
  if text.strip():
206
  final_text = text