Spaces:
Sleeping
Sleeping
File size: 6,336 Bytes
ebd67c4 e82e859 e6be728 e82e859 ebd67c4 e82e859 ebd67c4 e82e859 6f35883 e82e859 6f35883 e82e859 ebd67c4 574d828 9de639c ebd67c4 9de639c ebd67c4 574d828 e6be728 ebd67c4 e82e859 574d828 efc9b0c ebd67c4 6f35883 e6be728 ebd67c4 6f35883 574d828 ebd67c4 b5d3142 ebd67c4 1b8ac87 b5d3142 ebd67c4 b5d3142 ebd67c4 b5d3142 ebd67c4 574d828 ebd67c4 574d828 ebd67c4 6f35883 9a4ca5c 574d828 ebd67c4 574d828 | 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 | import os
import shutil
import subprocess
import requests
import zipfile
import uuid
import glob
import datetime
from fastapi import FastAPI, BackgroundTasks
from fastapi.responses import FileResponse, JSONResponse
from pydantic import BaseModel
# --- KONFIGURASI PATH ---
os.chdir("/tmp")
os.environ["HOME"] = "/tmp"
os.environ["UNITY_PATH"] = "/opt/unity/Editor/Unity"
BASE_PROJECT_PATH = "/app/UnityProject"
LICENSE_SOURCE = "/app/Unity_lic.ulf"
app = FastAPI()
class ConversionRequest(BaseModel):
transaction_id: str
file_url: str
filename: str
z_id: str
z_pw: str
# --- FUNGSI PEMBANTU ---
def setup_license():
"""Menyiapkan lisensi dan mengecek waktu server untuk debug."""
# 1. Cek Waktu Server (Penting untuk mengatasi 'Time validation failed')
now = datetime.datetime.now()
print(f"⏰ [DEBUG] Waktu Server Sekarang: {now.strftime('%Y-%m-%d %H:%M:%S')}", flush=True)
target_dir = "/tmp/.local/share/unity3d/Unity"
os.makedirs(target_dir, exist_ok=True)
if os.path.exists(LICENSE_SOURCE):
# Bersihkan lisensi lama di folder internal jika ada
internal_license = os.path.join(target_dir, "Unity_lic.ulf")
if os.path.exists(internal_license):
os.remove(internal_license)
shutil.copy2(LICENSE_SOURCE, internal_license)
print("✅ [SYSTEM] Lisensi disalin ke folder internal Unity.", flush=True)
else:
print("⚠️ [WARNING] File Unity_lic.ulf tidak ditemukan di /app/", flush=True)
def run_unity_command(project_path, method, extra_args=None):
"""Menjalankan Unity dengan flag headless dan anti-stuck."""
cmd = [
os.environ["UNITY_PATH"],
"-batchmode",
"-nographics",
"-quit",
"-no-webservices", # Matikan pencarian layanan cloud
"-no-graphics", # Proteksi tambahan mode headless
"-silent-crashes", # Jangan munculkan popup error
"-manualLicenseFile", LICENSE_SOURCE, # Paksa baca file lisensi fisik
"-projectPath", project_path,
"-executeMethod", method,
"-logFile", "-" # Log keluar secara real-time ke console
]
if extra_args:
cmd.extend(extra_args)
# Jalankan perintah dan tunggu sampai selesai
return subprocess.run(cmd, capture_output=False)
# --- ENDPOINTS ---
@app.get("/lisensi")
async def generate_new_alf():
"""Endpoint untuk generate file .alf baru jika lisensi lama Expired."""
# Bersihkan sisa file .alf sebelumnya
for f in glob.glob("/tmp/*.alf"):
try: os.remove(f)
except: pass
print("🛠️ [LICENSE] Meminta file aktivasi (.alf) baru dari Unity...", flush=True)
cmd = [
os.environ["UNITY_PATH"],
"-batchmode", "-nographics",
"-createManualActivationFile",
"-logfile", "/dev/stdout"
]
subprocess.run(cmd, cwd="/tmp", timeout=60)
found_alf = glob.glob("/tmp/*.alf")
if found_alf:
print(f"✅ [LICENSE] File .alf berhasil dibuat: {found_alf[0]}", flush=True)
return FileResponse(path=found_alf[0], filename=os.path.basename(found_alf[0]))
return JSONResponse(status_code=500, content={"error": "Gagal generate .alf. Cek tab Logs."})
@app.post("/convert")
async def api_convert(req: ConversionRequest, background_tasks: BackgroundTasks):
"""Endpoint utama untuk memicu pipeline convert dan upload."""
background_tasks.add_task(process_pipeline, req)
return {"status": "processing", "transaction_id": req.transaction_id}
# --- INTI PROSES (PIPELINE) ---
def process_pipeline(req: ConversionRequest):
setup_license()
# Folder unik untuk setiap transaksi
SESSION_PATH = f"/tmp/Project_{req.transaction_id}"
extract_tmp = f"/tmp/extract_{req.transaction_id}"
zip_tmp = f"/tmp/{req.transaction_id}.zip"
try:
# 1. DOWNLOAD & PREPARE
print(f"📥 [START] Mengambil aset: {req.transaction_id}", flush=True)
r = requests.get(req.file_url, timeout=30)
with open(zip_tmp, 'wb') as f:
f.write(r.content)
os.makedirs(extract_tmp, exist_ok=True)
with zipfile.ZipFile(zip_tmp, 'r') as z:
z.extractall(extract_tmp)
# 2. SETUP PROJECT WORKSPACE
# Salin UnityProject dasar ke folder temporer agar project asli tetap bersih
shutil.copytree(BASE_PROJECT_PATH, SESSION_PATH, ignore=shutil.ignore_patterns("Library", "Temp"))
target_in = os.path.join(SESSION_PATH, "Assets/InputRaw")
os.makedirs(target_in, exist_ok=True)
# Pindahkan file hasil ekstrak ke folder input project
for item in os.listdir(extract_tmp):
shutil.move(os.path.join(extract_tmp, item), os.path.join(target_in, item))
# 3. TAHAP 1: PENYEDERHANAAN MESH
print(f"🛠️ [STEP 1] Menjalankan TestBuilder.SimplifyOnly...", flush=True)
step1 = run_unity_command(SESSION_PATH, "TestBuilder.SimplifyOnly")
if step1.returncode != 0:
print(f"❌ [FAILED] Step 1 Gagal (Exit Code: {step1.returncode}). Cek Logs di atas.", flush=True)
return
# 4. TAHAP 2: UPLOAD KE ZEPETO
print(f"🚀 [STEP 2] Menjalankan Zepeto CLI Upload...", flush=True)
upload_args = [
"-id", req.z_id,
"-password", req.z_pw,
"-upload"
]
step2 = run_unity_command(SESSION_PATH, "ZepetoPackageCliBuilder.BuildWithArgs", upload_args)
if step2.returncode == 0:
print(f"✅ [SUCCESS] Item {req.transaction_id} telah terunggah ke ZEPETO Studio.", flush=True)
else:
print(f"❌ [FAILED] Step 2 Gagal (Exit Code: {step2.returncode}).", flush=True)
except Exception as e:
print(f"🔥 [CRITICAL ERROR] {str(e)}", flush=True)
finally:
# PEMBERSIHAN (Wajib agar disk tidak penuh)
print(f"🧹 [CLEANUP] Menghapus folder sesi {req.transaction_id}...", flush=True)
for p in [SESSION_PATH, extract_tmp, zip_tmp]:
if os.path.exists(p):
if os.path.isdir(p): shutil.rmtree(p)
else: os.remove(p)
if __name__ == "__main__":
import uvicorn
# Jalankan server FastAPI
uvicorn.run(app, host="0.0.0.0", port=7860) |