import os import glob import time import subprocess from fastapi import FastAPI, Query, HTTPException, BackgroundTasks from fastapi.responses import FileResponse app = FastAPI( title="⚡ Studio Engine API", description="High-speed media acquisition endpoint returning JSON payload.", version="3.0.0", docs_url="/", redoc_url=None ) DOWNLOAD_DIR = "downloads" if not os.path.exists(DOWNLOAD_DIR): os.makedirs(DOWNLOAD_DIR) def delete_file_after_delay(file_path: str, delay: int = 300): """Menghapus file dari folder penyimpanan setelah 5 menit (300 detik)""" time.sleep(delay) if os.path.exists(file_path): try: os.remove(file_path) print(f"[Auto-Delete] File hangus berhasil dihapus: {file_path}") except Exception as e: print(f"[Auto-Delete] Gagal menghapus file {file_path}: {e}") @app.get('/api/mp3', summary="Get JSON Info for MP3 Audio") def download_mp3( background_tasks: BackgroundTasks, url: str = Query(..., description="Target resource web URL (YouTube, TikTok, Instagram, etc.)") ): timestamp = int(time.time()) outtmpl = f"{DOWNLOAD_DIR}/audio_{timestamp}.%(ext)s" cmd = [ "yt-dlp", url, "-f", "bestaudio/best", "-o", outtmpl, "-x", "--audio-format", "mp3", "--audio-quality", "192K", "--no-playlist", "--no-warnings", "--no-check-certificate" ] try: result = subprocess.run(cmd, stdout=subprocess.PIPE, stderr=subprocess.PIPE, text=True) if result.returncode != 0: raise Exception(result.stderr) downloaded_files = glob.glob(f"{DOWNLOAD_DIR}/audio_{timestamp}.mp3") if not downloaded_files: downloaded_files = glob.glob(f"{DOWNLOAD_DIR}/*_{timestamp}*") if not downloaded_files: raise HTTPException(status_code=500, detail="Gagal menyimpan file audio ke server.") file_path = downloaded_files[0] file_name = os.path.basename(file_path) # Daftarkan background task untuk menghapus file dalam waktu 5 menit background_tasks.add_task(delete_file_after_delay, file_path, 300) return { "status": "success", "message": "File ready. Links are valid for 5 minutes.", "file_name": file_name, "format": "mp3", "auto_download_url": f"https://fareldevelopers-aio.hf.space/api/get-file/{file_name}?action=download", "play_in_browser_url": f"https://fareldevelopers-aio.hf.space/api/get-file/{file_name}?action=stream" } except Exception as e: raise HTTPException(status_code=500, detail=f"Audio Engine Error: {str(e)}") @app.get('/api/mp4', summary="Get JSON Info for MP4 Video") def download_mp4( background_tasks: BackgroundTasks, url: str = Query(..., description="Target resource web URL (YouTube, TikTok, Instagram, etc.)"), resolution: str = Query("720", description="Resolution specification (Optional). Default: 720") ): timestamp = int(time.time()) outtmpl = f"{DOWNLOAD_DIR}/video_{timestamp}_{resolution}p.%(ext)s" yt_dlp_format = f"bestvideo[height<={resolution}]+bestaudio/best[height<={resolution}]/best" cmd = [ "yt-dlp", url, "-f", yt_dlp_format, "-o", outtmpl, "--merge-output-format", "mp4", "--no-playlist", "--no-warnings", "--no-check-certificate" ] try: result = subprocess.run(cmd, stdout=subprocess.PIPE, stderr=subprocess.PIPE, text=True) if result.returncode != 0: raise Exception(result.stderr) downloaded_files = glob.glob(f"{DOWNLOAD_DIR}/video_{timestamp}_{resolution}p.mp4") if not downloaded_files: downloaded_files = glob.glob(f"{DOWNLOAD_DIR}/*_{timestamp}*") if not downloaded_files: raise HTTPException(status_code=500, detail="Gagal menyimpan file video ke server.") file_path = downloaded_files[0] file_name = os.path.basename(file_path) # Daftarkan background task untuk menghapus file dalam waktu 5 minutes background_tasks.add_task(delete_file_after_delay, file_path, 300) return { "status": "success", "message": "File ready. Links are valid for 5 minutes.", "file_name": file_name, "format": "mp4", "resolution": resolution, "auto_download_url": f"https://fareldevelopers-aio.hf.space/api/get-file/{file_name}?action=download", "play_in_browser_url": f"https://fareldevelopers-aio.hf.space/api/get-file/{file_name}?action=stream" } except Exception as e: raise HTTPException(status_code=500, detail=f"Video Engine Error: {str(e)}") @app.get('/api/get-file/{file_name}', summary="Serve Saved File (Download or Stream)") def get_file(file_name: str, action: str = Query("download", description="Options: 'download' or 'stream'")): """Endpoint core yang melayani file berdasarkan query parameter action""" file_path = os.path.join(DOWNLOAD_DIR, file_name) if not os.path.exists(file_path): raise HTTPException(status_code=404, detail="File tidak ditemukan atau sudah kedaluwarsa (terhapus otomatis setelah 5 menit).") # Deteksi tipe media berdasarkan extension media_type = "audio/mpeg" if file_name.endswith(".mp3") else "video/mp4" if action == "stream": # Menggunakan inline content disposition agar browser memutar langsung di web return FileResponse(file_path, media_type=media_type, content_disposition_type="inline") else: # Menggunakan attachment content disposition agar browser otomatis mendownload file return FileResponse(file_path, media_type="application/octet-stream", filename=file_name, content_disposition_type="attachment")