Spaces:
Sleeping
Sleeping
| from fastapi import FastAPI, HTTPException, UploadFile, File | |
| from fastapi.responses import FileResponse | |
| from fastapi.middleware.cors import CORSMiddleware | |
| from fastapi.background import BackgroundTasks | |
| import os, subprocess, traceback, urllib.parse | |
| app = FastAPI() | |
| TMP_DIR = "/tmp/motor_hf" | |
| os.makedirs(TMP_DIR, exist_ok=True) | |
| app.add_middleware( | |
| CORSMiddleware, allow_origins=["*"], allow_credentials=True, | |
| allow_methods=["*"], allow_headers=["*"], | |
| ) | |
| # ββ Healthcheck leve (usado pelo MyMp3 para o sinal luminoso de status) βββββ | |
| def home(): | |
| return {"status": "online", "servico": "AV Conversion Core"} | |
| # ββ MP3 via upload (usado pela OrangePi e pelo LocalServer/Musicas) βββββββββ | |
| async def processar_conversao(audio_bruto: UploadFile = File(...)): | |
| job_id = os.urandom(4).hex() | |
| caminho_bruto = f"{TMP_DIR}/bruto_{job_id}" | |
| caminho_mp3 = f"{TMP_DIR}/saida_{job_id}.mp3" | |
| try: | |
| conteudo = await audio_bruto.read() | |
| with open(caminho_bruto, "wb") as f: | |
| f.write(conteudo) | |
| cmd = ["ffmpeg", "-y", "-i", caminho_bruto, "-q:a", "0", "-map", "a", caminho_mp3] | |
| res = subprocess.run(cmd, stdout=subprocess.PIPE, stderr=subprocess.PIPE, | |
| text=True, timeout=180) | |
| if res.returncode != 0 or not os.path.exists(caminho_mp3): | |
| raise Exception(f"Erro FFmpeg: {res.stderr}") | |
| bg = BackgroundTasks() | |
| bg.add_task(os.remove, caminho_bruto) | |
| bg.add_task(os.remove, caminho_mp3) | |
| return FileResponse(caminho_mp3, media_type="audio/mpeg", background=bg) | |
| except Exception as e: | |
| traceback.print_exc() | |
| if os.path.exists(caminho_bruto): | |
| try: os.remove(caminho_bruto) | |
| except Exception: pass | |
| raise HTTPException(status_code=500, detail=str(e)) | |
| # ββ MP3 via URL direta (busca na CDN, sem upload) βββββββββββββββββββββββββββ | |
| def converter_stream_direta(url_stream_audio: str, titulo_musica: str): | |
| job_id = os.urandom(4).hex() | |
| titulo_limpo = titulo_musica.replace("/", "").replace("\\", "").replace(" ", "_") | |
| caminho_mp3 = f"{TMP_DIR}/{titulo_limpo}_{job_id}.mp3" | |
| try: | |
| url_real = urllib.parse.unquote(url_stream_audio) | |
| cmd = ["ffmpeg", "-y", "-i", url_real, "-q:a", "0", caminho_mp3] | |
| res = subprocess.run(cmd, stdout=subprocess.PIPE, stderr=subprocess.PIPE, | |
| text=True, timeout=120) | |
| if res.returncode != 0: | |
| raise Exception(f"Erro FFmpeg no co-processamento: {res.stderr}") | |
| if os.path.exists(caminho_mp3): | |
| bg = BackgroundTasks() | |
| bg.add_task(os.remove, caminho_mp3) | |
| headers = {"Content-Disposition": f'attachment; filename="{urllib.parse.quote(titulo_limpo)}.mp3"'} | |
| return FileResponse(caminho_mp3, media_type="audio/mpeg", headers=headers, background=bg) | |
| raise Exception("Falha ao gerar arquivo MP3") | |
| except Exception as e: | |
| traceback.print_exc() | |
| raise HTTPException(status_code=500, detail=str(e)) | |
| # ββ MP4 via URL direta (usado pela OrangePi e LocalServer para Clipes) ββββββ | |
| def converter_video_direto(url_stream_video: str, titulo_video: str): | |
| job_id = os.urandom(4).hex() | |
| titulo_limpo = titulo_video.replace("/", "").replace("\\", "").replace(" ", "_") | |
| caminho_mp4 = f"{TMP_DIR}/{titulo_limpo}_{job_id}.mp4" | |
| try: | |
| url_real = urllib.parse.unquote(url_stream_video) | |
| cmd = [ | |
| "ffmpeg", "-y", "-i", url_real, | |
| "-c:v", "libx264", "-preset", "veryfast", "-crf", "23", | |
| "-c:a", "aac", "-b:a", "160k", | |
| "-movflags", "+faststart", | |
| caminho_mp4, | |
| ] | |
| res = subprocess.run(cmd, stdout=subprocess.PIPE, stderr=subprocess.PIPE, | |
| text=True, timeout=600) | |
| if res.returncode != 0: | |
| raise Exception(f"Erro FFmpeg no co-processamento de video: {res.stderr}") | |
| if os.path.exists(caminho_mp4): | |
| bg = BackgroundTasks() | |
| bg.add_task(os.remove, caminho_mp4) | |
| headers = {"Content-Disposition": f'attachment; filename="{urllib.parse.quote(titulo_limpo)}.mp4"'} | |
| return FileResponse(caminho_mp4, media_type="video/mp4", headers=headers, background=bg) | |
| raise Exception("Falha ao gerar arquivo MP4") | |
| except Exception as e: | |
| traceback.print_exc() | |
| raise HTTPException(status_code=500, detail=str(e)) |