Añadir detección automática de FFmpeg

- Agregar funciones check_ffmpeg() y install_ffmpeg() para detectar e instalar FFmpeg
- Implementar verificación previa a descargas MP3 para asegurar disponibilidad de FFmpeg
- Crear endpoints /api/ffmpeg/status y /api/ffmpeg/install para gestión de FFmpeg
- Mejorar frontend con detección de estado de FFmpeg y opción de instalación automática
- Deshabilitar opción MP3 si FFmpeg no está disponible
- Añadir mensajes de error específicos para problemas de FFmpeg

🤖 Generated with [Claude Code](https://claude.com/claude-code)

Co-Authored-By: Claude <noreply@anthropic.com>
This commit is contained in:
renato97
2025-11-10 15:15:28 +00:00
parent f6a51f1f67
commit a5332b2d38
2 changed files with 163 additions and 0 deletions

86
app.py
View File

@@ -4,6 +4,8 @@ import os
import uuid
from datetime import datetime
import threading
import subprocess
import shutil
import time
app = Flask(__name__)
@@ -14,6 +16,49 @@ if not os.path.exists(app.config['DOWNLOAD_FOLDER']):
download_status = {}
def check_ffmpeg():
"""Verificar si FFmpeg está disponible en el sistema"""
try:
result = subprocess.run(['ffmpeg', '-version'],
capture_output=True, text=True, timeout=10)
return result.returncode == 0
except (subprocess.TimeoutExpired, FileNotFoundError):
return False
def install_ffmpeg():
"""Intentar instalar FFmpeg automáticamente"""
try:
# Detectar el sistema operativo
import platform
system = platform.system().lower()
if system == 'linux':
# Para sistemas basados en Debian/Ubuntu
commands = [
['sudo', 'apt-get', 'update'],
['sudo', 'apt-get', 'install', '-y', 'ffmpeg']
]
elif system == 'darwin':
# Para macOS usando Homebrew
commands = [
['brew', 'update'],
['brew', 'install', 'ffmpeg']
]
elif system == 'windows':
# Para Windows (simplificado - requeriría manual)
return False
else:
return False
for cmd in commands:
result = subprocess.run(cmd, capture_output=True, text=True)
if result.returncode != 0:
return False
return True
except Exception:
return False
class DownloadProgress:
def __init__(self, download_id):
self.download_id = download_id
@@ -48,6 +93,22 @@ def download_video(url, download_id, format_type='mp4'):
progress = DownloadProgress(download_id)
download_status[download_id] = progress
# Verificar FFmpeg para formatos que lo requieren
if format_type == 'mp3':
if not check_ffmpeg():
progress.status = 'error'
progress.error = "FFmpeg no está disponible. La conversión a MP3 requiere FFmpeg. Por favor, instala FFmpeg o contacta al administrador."
return
# Opcional: intentar instalar FFmpeg automáticamente si no está disponible
# if install_ffmpeg():
# progress.status = 'info'
# progress.error = "FFmpeg ha sido instalado automáticamente. Intenta la descarga nuevamente."
# else:
# progress.status = 'error'
# progress.error = "No se pudo instalar FFmpeg automáticamente. La conversión a MP3 requiere FFmpeg."
# return
try:
ydl_opts = {
'outtmpl': os.path.join(app.config['DOWNLOAD_FOLDER'], f'{download_id}.%(ext)s'),
@@ -180,6 +241,31 @@ def list_downloads():
return jsonify(downloads)
@app.route('/api/ffmpeg/status')
def ffmpeg_status():
"""Verificar el estado de FFmpeg"""
ffmpeg_available = check_ffmpeg()
return jsonify({
'available': ffmpeg_available,
'can_install': True if not ffmpeg_available else False
})
@app.route('/api/ffmpeg/install', methods=['POST'])
def install_ffmpeg_api():
"""Intentar instalar FFmpeg automáticamente"""
try:
if check_ffmpeg():
return jsonify({'success': True, 'message': 'FFmpeg ya está disponible.'})
# Intentar instalar FFmpeg
success = install_ffmpeg()
if success:
return jsonify({'success': True, 'message': 'FFmpeg instalado correctamente.'})
else:
return jsonify({'success': False, 'message': 'No se pudo instalar FFmpeg automáticamente. Debes instalarlo manualmente.'})
except Exception as e:
return jsonify({'success': False, 'message': f'Error durante la instalación: {str(e)}'}), 500
@app.route('/api/cleanup', methods=['POST'])
def cleanup_downloads():
"""Limpia descargas fallidas y muy antiguas"""

View File

@@ -3,6 +3,7 @@ let progressInterval = null;
document.addEventListener('DOMContentLoaded', function() {
loadDownloads();
checkFFmpegStatus();
document.getElementById('downloadForm').addEventListener('submit', function(e) {
e.preventDefault();
@@ -265,5 +266,81 @@ function formatFileSize(bytes) {
return parseFloat((bytes / Math.pow(k, i)).toFixed(2)) + ' ' + sizes[i];
}
function checkFFmpegStatus() {
fetch('/api/ffmpeg/status')
.then(response => response.json())
.then(data => {
const mp3Option = document.querySelector('input[value="mp3"]');
const mp3Label = document.querySelector('label[for="mp3"]');
if (!data.available) {
// MP3 option is not available
mp3Option.disabled = true;
mp3Label.style.opacity = '0.5';
mp3Label.style.cursor = 'not-allowed';
// Add warning indicator
if (!document.getElementById('ffmpegWarning')) {
const warning = document.createElement('div');
warning.id = 'ffmpegWarning';
warning.className = 'alert alert-warning alert-sm mt-2';
warning.innerHTML = `
<i class="fas fa-exclamation-triangle"></i>
FFmpeg no está disponible. Las descargas de MP3 requieren FFmpeg.
<button class="btn btn-sm btn-outline-warning ms-2" onclick="installFFmpeg()">
<i class="fas fa-download"></i> Instalar FFmpeg
</button>
`;
mp3Label.parentNode.insertBefore(warning, mp3Label.parentNode.nextSibling);
// Switch to MP4 by default
document.querySelector('input[value="mp4"]').checked = true;
}
} else {
// FFmpeg is available
if (document.getElementById('ffmpegWarning')) {
document.getElementById('ffmpegWarning').remove();
}
mp3Option.disabled = false;
mp3Label.style.opacity = '1';
mp3Label.style.cursor = 'pointer';
}
})
.catch(error => {
console.error('Error checking FFmpeg status:', error);
});
}
function installFFmpeg() {
const btn = document.querySelector('#ffmpegWarning button');
const originalContent = btn.innerHTML;
btn.disabled = true;
btn.innerHTML = '<i class="fas fa-spinner fa-spin"></i> Instalando...';
fetch('/api/ffmpeg/install', {
method: 'POST',
headers: {
'Content-Type': 'application/json',
}
})
.then(response => response.json())
.then(data => {
if (data.success) {
alert('✅ ' + data.message);
checkFFmpegStatus(); // Recheck status
} else {
alert('❌ ' + data.message);
btn.disabled = false;
btn.innerHTML = originalContent;
}
})
.catch(error => {
console.error('Error installing FFmpeg:', error);
alert('Error al intentar instalar FFmpeg: ' + error.message);
btn.disabled = false;
btn.innerHTML = originalContent;
});
}
// Auto-refresh downloads list every 30 seconds
setInterval(loadDownloads, 30000);