import os from textwrap import dedent import subprocess from colorama import Fore, Style import re videosPATH = os.path.expanduser('~/storage/downloads/videos') dlFilePATH = os.path.expanduser('~/storage/downloads/videos/dl.txt') def main(): bienvenida = """ Bienvenido a los scripts de yt-dlp. Por favor, selecciona una opción. 1. Normal (mejor calidad) 2. Extraer audio a wav 3. Seleccionar tiempo del video 4. Múltiples videos con archivo """ print(dedent(bienvenida)) numero_opcion = input('Selecciona una opción de descarga: ') if numero_opcion.isdigit(): dlCase(int(numero_opcion)) else: print('Número seleccionado incorrecto') return main() def obtenerFormatos(url): resultado = subprocess.run(['yt-dlp', '-F', url], capture_output=True, text=True) imprimirListaFormatosConColor(resultado.stdout) def descargaNormal(url): # Obtener el título del video y el nombre del archivo usando yt-dlp try: output = subprocess.run(['yt-dlp', '--get-title', '--get-filename', '--', url], capture_output=True, text=True) output_lines = output.stdout.strip().split('\n') video_title = output_lines[0] if len(output_lines) > 0 else 'desconocido' video_filename = output_lines[1] if len(output_lines) > 1 else 'desconocido' # Extensión para el archivo de salida video_extension = 'mp4' # Cambia la extensión si es diferente print(f"Title: {video_title}") print(f"Filename: {video_filename}") obtenerFormatos(url) formato = input('Introduce el número de formato que deseas descargar o ingresa "b" para el mejor video y audio: ') # Obtener lista de formatos disponibles formatos_disponibles = obtenerFormatosDisponibles(url) if formato.lower() == 'b': descargarMejorVideoYAudio(url, video_title, video_extension) elif formato in formatos_disponibles: subprocess.run(['yt-dlp', '-f', formato, '-o', f'{videosPATH}/{video_title}.%(ext)s', url], check=True) print(f'Archivo descargado como: {videosPATH}/{video_title}.{video_extension}') else: print(f'Formato {formato} no disponible para esta URL.') return descargaNormal(url) except subprocess.CalledProcessError as e: print(f'Error al intentar descargar el video: {e}') except Exception as e: print(f'Ocurrió un error inesperado: {e}') finally: return main() def obtenerFormatosDisponibles(url): resultado = subprocess.run(['yt-dlp', '-F', url], capture_output=True, text=True) lineas = resultado.stdout.splitlines() formatos_disponibles = [] for linea in lineas: match = re.search(r'^\s*(\d+)\s+', linea) if match: formato = match.group(1) formatos_disponibles.append(formato) return formatos_disponibles def descargarMejorVideoYAudio(url, video_title, video_extension): # Descargar el mejor video y el mejor audio video_output = f'{videosPATH}/bestvideo.%(ext)s' audio_output = f'{videosPATH}/bestaudio.%(ext)s' subprocess.run(['yt-dlp', '-f', 'bestvideo', '-o', video_output, url], check=True) subprocess.run(['yt-dlp', '-f', 'bestaudio', '-o', audio_output, url], check=True) # Obtener nombres de los archivos descargados video_files = [f for f in os.listdir(videosPATH) if re.match(r'bestvideo\..*', f)] audio_files = [f for f in os.listdir(videosPATH) if re.match(r'bestaudio\..*', f)] if video_files and audio_files: best_video_path = os.path.join(videosPATH, video_files[0]) best_audio_path = os.path.join(videosPATH, audio_files[0]) # Unir video y audio en un archivo temporal temp_output = f'{videosPATH}/temp.mp4' subprocess.run(['ffmpeg', '-i', best_video_path, '-i', best_audio_path, '-c', 'copy', temp_output], check=True) # Eliminar archivos originales os.remove(best_video_path) os.remove(best_audio_path) # Convertir el archivo temporal al formato deseado final_output = f'{videosPATH}/{video_title}.{video_extension}' subprocess.run(['ffmpeg', '-i', temp_output, '-c:v', 'libx264', '-crf', '23', '-preset', 'ultrafast', '-c:a', 'aac', '-b:a', '192k', '-ac', '2', final_output], check=True) # Eliminar el archivo temporal os.remove(temp_output) print(f'Archivo convertido y guardado como: {final_output}') else: print("No se pudo encontrar los archivos de video o audio descargados.") def seleccionarTiempo(horaInicio, horaFin, url): try: subprocess.run(['yt-dlp', '-f', '(best)[protocol!*=dash]', '--external-downloader', 'ffmpeg', '--external-downloader-args', f'ffmpeg_i:-ss {horaInicio} -to {horaFin}', '-o', f'{videosPATH}/seleccionado.%(ext)s', url], check=True) except subprocess.CalledProcessError as e: print(f'Error al seleccionar el tiempo del video: {e}') except Exception as e: print(f'Ocurrió un error inesperado: {e}') finally: return main() def multiplesVideos(): try: subprocess.run(['yt-dlp', '-f', 'best', '-o', f'{videosPATH}/%(title)s.%(ext)s', '-a', dlFilePATH], check=True) except subprocess.CalledProcessError as e: print(f'Error al descargar múltiples videos: {e}') except Exception as e: print(f'Ocurrió un error inesperado: {e}') finally: return main() def extractAudio(url): try: # Descargar el mejor audio en formato WAV subprocess.run(['yt-dlp', '-f', 'bestaudio', '-x', '--audio-format', 'wav', '-o', f'{videosPATH}/audio.%(ext)s', url], check=True) # Obtener nombres de los archivos descargados audio_files = [f for f in os.listdir(videosPATH) if re.match(r'audio\..*', f)] if audio_files: audio_path = os.path.join(videosPATH, audio_files[0]) # Mostrar ruta del archivo de audio WAV print(f'Audio descargado como: {audio_path}') else: print("No se pudo encontrar el archivo de audio descargado.") except subprocess.CalledProcessError as e: print(f'Error al extraer el audio: {e}') except Exception as e: print(f'Ocurrió un error inesperado: {e}') finally: return main() def menuDescargaBestQuality(): try: url = input('Introduce la URL: ') video_title = obtenerTituloVideo(url) descargarMejorVideoYAudio(url, video_title, 'mp4') except Exception as e: print(f'Ocurrió un error: {e}') finally: return main() def obtenerTituloVideo(url): try: output = subprocess.run(['yt-dlp', '--get-title', '--', url], capture_output=True, text=True) return output.stdout.strip() except Exception as e: print(f'Error al obtener el título del video: {e}') return 'video_desconocido' def dlCase(numero_opcion): match numero_opcion: case 1: url = input('Introduce la URL: ') return descargaNormal(url) case 2: url = input('Introduce la URL: ') return extractAudio(url) case 3: hora_inicio = input('Introduce la hora de inicio (hh:mm:ss): ') if not re.match(r'^\d{2}:\d{2}:\d{2}$', hora_inicio): print("Formato de tiempo inválido. Usa hh:mm:ss") return main() hora_fin = input('Introduce la hora de fin (hh:mm:ss): ') if not re.match(r'^\d{2}:\d{2}:\d{2}$', hora_fin): print("Formato de tiempo inválido. Usa hh:mm:ss") return main() url = input('Introduce la URL: ') return seleccionarTiempo(hora_inicio, hora_fin, url) case 4: instrucciones_multivideo = """ Antes de proceder, asegúrate de que - dl.txt existe en ~/storage/downloads/videos """ print(dedent(instrucciones_multivideo)) confirmar = input('¿dl.txt es correcto? (S/N): ') if confirmar.lower() != 's': return main() return multiplesVideos() case _: print('Número seleccionado incorrecto') return main() def imprimirFormatoConColor(formato): if 'audio only' in formato: return f"{Fore.YELLOW}{formato}{Style.RESET_ALL}" elif 'video only' in formato: return f"{Fore.CYAN}{formato}{Style.RESET_ALL}" else: return formato def imprimirListaFormatosConColor(formatos): lineas = formatos.splitlines() for linea in lineas: if 'audio only' in linea and 'video only' in linea: print(f"{Fore.GREEN}AV {linea}{Style.RESET_ALL}") elif 'audio only' in linea: print(f"{Fore.YELLOW}A {linea}{Style.RESET_ALL}") elif 'video only' in linea: print(f"{Fore.CYAN}V {linea}{Style.RESET_ALL}") else: print(linea) if __name__ == "__main__": main()