webzepetoku commited on
Commit
04dea0f
Β·
verified Β·
1 Parent(s): 0f1f33c

Update app.py

Browse files
Files changed (1) hide show
  1. app.py +109 -53
app.py CHANGED
@@ -6,18 +6,29 @@ import zipfile
6
  import glob
7
  import json
8
  import uuid
 
 
9
  from fastapi import FastAPI, BackgroundTasks
10
  from fastapi.middleware.cors import CORSMiddleware
11
  from pydantic import BaseModel
12
  from playwright.sync_api import sync_playwright
13
 
14
- # --- CONFIG ---
15
  os.chdir("/tmp")
16
  os.environ["HOME"] = "/tmp"
17
  os.environ["UNITY_PATH"] = "/opt/unity/Editor/Unity"
18
  BASE_PROJECT_PATH = "/app/UnityProject"
19
  DEST_LICENSE_PATH = "/tmp/Unity_lic.ulf"
20
 
 
 
 
 
 
 
 
 
 
21
  app = FastAPI()
22
  app.add_middleware(
23
  CORSMiddleware,
@@ -33,6 +44,72 @@ class ConversionRequest(BaseModel):
33
  zepeto_id: str
34
  zepeto_password: str
35
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
36
  def process_pipeline(req: ConversionRequest):
37
  session_id = str(uuid.uuid4())[:8]
38
  SESSION_PATH = f"/tmp/Project_{session_id}"
@@ -50,35 +127,32 @@ def process_pipeline(req: ConversionRequest):
50
  print("πŸ“¦ [COPY] Cloning Project...", flush=True)
51
  shutil.copytree(BASE_PROJECT_PATH, SESSION_PATH, ignore=shutil.ignore_patterns("Library", "Temp", "Logs"))
52
 
53
- # --- CLEANER ---
54
  trash_folders = glob.glob(os.path.join(SESSION_PATH, "Assets", "**", "UnityMeshSimplifier"), recursive=True)
55
  trash_folders += glob.glob(os.path.join(SESSION_PATH, "Assets", "**", "Tests"), recursive=True)
56
  for folder in trash_folders:
57
  if os.path.exists(folder): shutil.rmtree(folder)
58
 
59
- # --- FLATTENER ---
60
  target_input = os.path.join(SESSION_PATH, "Assets", "InputRaw")
61
  os.makedirs(target_input, exist_ok=True)
62
-
63
  for root, dirs, files in os.walk(extract_tmp):
64
  for file in files:
65
  if file.endswith((".cs", ".ts", ".js", ".asmdef", ".dll")): os.remove(os.path.join(root, file))
66
-
67
- print("πŸ“‚ [FLATTENER] Memindahkan file ke InputRaw...", flush=True)
68
  for root, dirs, files in os.walk(extract_tmp):
69
  for file in files:
70
  if file.startswith(".") or file.endswith(".meta"): continue
71
  src = os.path.join(root, file)
72
  dst = os.path.join(target_input, file)
73
- if os.path.exists(dst):
74
- dst = os.path.join(target_input, f"{uuid.uuid4().hex[:4]}_{file}")
75
  shutil.copy(src, dst)
76
 
77
- # --- MANIFEST CLEAN ---
78
  manifest_path = os.path.join(SESSION_PATH, "Packages", "manifest.json")
79
  if os.path.exists(os.path.join(SESSION_PATH, "Packages", "packages-lock.json")):
80
  os.remove(os.path.join(SESSION_PATH, "Packages", "packages-lock.json"))
81
-
82
  clean_manifest = {
83
  "dependencies": {
84
  "com.unity.render-pipelines.universal": "14.0.10",
@@ -95,23 +169,17 @@ def process_pipeline(req: ConversionRequest):
95
  }
96
  with open(manifest_path, 'w') as f: json.dump(clean_manifest, f, indent=2)
97
 
98
- # --- INJECT SCRIPT BARU (TARGET LINUX) ---
99
- # Kita inject langsung disini biar pasti keubah
100
  script_path = os.path.join(SESSION_PATH, "Assets", "Editor", "TestBuilder.cs")
101
  os.makedirs(os.path.dirname(script_path), exist_ok=True)
102
-
103
  csharp_code = r"""
104
  using UnityEngine;
105
  using UnityEditor;
106
  using System.IO;
107
-
108
- public class TestBuilder
109
- {
110
  static readonly string RAW_PATH = "Assets/InputRaw";
111
  static readonly string OUTPUT_DIR = "Assets/Output";
112
-
113
- public static void ManualConvert()
114
- {
115
  Debug.Log("πŸš€ [NATIVE] STARTING BUILD (TARGET: LINUX64)...");
116
  try {
117
  AssetDatabase.Refresh();
@@ -124,27 +192,14 @@ public class TestBuilder
124
  string assetPath = AssetDatabase.GUIDToAssetPath(guids[0]);
125
  AssetImporter importer = AssetImporter.GetAtPath(assetPath);
126
  importer.assetBundleName = "repacked_item.zepeto";
127
-
128
  if (!Directory.Exists(OUTPUT_DIR)) Directory.CreateDirectory(OUTPUT_DIR);
129
-
130
- // PERUBAHAN PENTING DISINI: GANTI KE StandaloneLinux64
131
- var manifest = BuildPipeline.BuildAssetBundles(
132
- OUTPUT_DIR,
133
- BuildAssetBundleOptions.ForceRebuildAssetBundle,
134
- BuildTarget.StandaloneLinux64
135
- );
136
-
137
- if (manifest == null) {
138
- Debug.LogError("❌ [FATAL] Build Failed (Manifest Null)");
139
- EditorApplication.Exit(1);
140
- } else {
141
- Debug.Log("πŸŽ‰ [SUCCESS] Build Finished!");
142
- EditorApplication.Exit(0);
143
- }
144
- } catch (System.Exception e) {
145
- Debug.LogError($"πŸ’€ [EXCEPTION] {e.Message}");
146
- EditorApplication.Exit(1);
147
- }
148
  }
149
  }
150
  """
@@ -154,37 +209,38 @@ public class TestBuilder
154
  print(f"πŸš€ [UNITY] Repacking...", flush=True)
155
  cmd_repack = [
156
  os.environ["UNITY_PATH"], "-batchmode", "-nographics", "-quit",
157
- "-projectPath", SESSION_PATH,
158
- "-executeMethod", "TestBuilder.ManualConvert",
159
- "-logFile", unity_log_file,
160
- "-no-sprite-atlas-cache",
161
- "-job-worker-count", "1"
162
  ]
163
  subprocess.run(cmd_repack, check=False)
164
 
165
- # --- SMART LOG READER ---
166
  print("\n" + "="*50, flush=True)
167
- print("πŸ” HASIL DIAGNOSA:", flush=True)
168
- print("="*50, flush=True)
169
-
170
  if os.path.exists(unity_log_file):
171
  with open(unity_log_file, "r", encoding="utf-8", errors="ignore") as f:
172
  for line in f:
173
  if any(k in line for k in ["[NATIVE]", "Error", "Exception", "Fail", "CRITICAL"]):
174
  if "Shader" in line or "Metal" in line: continue
175
  print(line.strip(), flush=True)
176
- else:
177
- print("❌ LOG FILE TIDAK DITEMUKAN!", flush=True)
178
  print("="*50 + "\n", flush=True)
179
 
180
- # UPLOAD
181
  output_dir = os.path.join(SESSION_PATH, "Assets", "Output")
182
  target_file = os.path.join(output_dir, "repacked_item.zepeto")
183
 
184
  if os.path.exists(target_file):
185
- print(f"πŸŽ‰ [DONE] File output ditemukan: {target_file}", flush=True)
 
 
 
 
 
 
 
186
  else:
187
- print("❌ [FAIL] File output TIDAK ADA.", flush=True)
188
 
189
  except Exception as e: print(f"❌ [CRITICAL] {e}", flush=True)
190
  finally:
 
6
  import glob
7
  import json
8
  import uuid
9
+ import boto3
10
+ from botocore.exceptions import NoCredentialsError
11
  from fastapi import FastAPI, BackgroundTasks
12
  from fastapi.middleware.cors import CORSMiddleware
13
  from pydantic import BaseModel
14
  from playwright.sync_api import sync_playwright
15
 
16
+ # --- CONFIG SERVER ---
17
  os.chdir("/tmp")
18
  os.environ["HOME"] = "/tmp"
19
  os.environ["UNITY_PATH"] = "/opt/unity/Editor/Unity"
20
  BASE_PROJECT_PATH = "/app/UnityProject"
21
  DEST_LICENSE_PATH = "/tmp/Unity_lic.ulf"
22
 
23
+ # --- CONFIG CLOUDFLARE R2 (SUDAH DIISI) ---
24
+ R2_CONFIG = {
25
+ "account_id": "31f2970a3442da4e6f17f79064897226",
26
+ "access_key": "44613d17ec50941707a7ddd9b17944bc",
27
+ "secret_key": "50185c21ff5e4f53e412e2013305b6ab24b7eda16cc0d3dc66593eed64aa99a2",
28
+ "bucket_name": "zepeto-builds", # <--- PASTIKAN BUCKET INI ADA DI R2 ABANG!
29
+ "public_domain": "" # Isi jika punya custom domain (contoh: https://cdn.domain.com)
30
+ }
31
+
32
  app = FastAPI()
33
  app.add_middleware(
34
  CORSMiddleware,
 
44
  zepeto_id: str
45
  zepeto_password: str
46
 
47
+ # --- FUNGSI UPLOAD R2 ---
48
+ def upload_to_r2(file_path, original_filename):
49
+ print("☁️ [R2] Memulai upload ke Cloudflare R2...", flush=True)
50
+ try:
51
+ s3 = boto3.client(
52
+ 's3',
53
+ endpoint_url=f"https://{R2_CONFIG['account_id']}.r2.cloudflarestorage.com",
54
+ aws_access_key_id=R2_CONFIG['access_key'],
55
+ aws_secret_access_key=R2_CONFIG['secret_key']
56
+ )
57
+
58
+ # Nama file di R2: builds/timestamp_namafile.zepeto
59
+ object_name = f"builds/{uuid.uuid4().hex[:8]}_{original_filename}.zepeto"
60
+
61
+ s3.upload_file(file_path, R2_CONFIG['bucket_name'], object_name)
62
+
63
+ # Generate URL
64
+ if R2_CONFIG['public_domain']:
65
+ url = f"{R2_CONFIG['public_domain']}/{object_name}"
66
+ else:
67
+ # Default R2 URL structure
68
+ url = f"https://{R2_CONFIG['account_id']}.r2.cloudflarestorage.com/{R2_CONFIG['bucket_name']}/{object_name}"
69
+
70
+ print(f"βœ… [R2] Upload Sukses! URL BUKTI: {url}", flush=True)
71
+ return url
72
+ except Exception as e:
73
+ print(f"❌ [R2] Upload Gagal: {str(e)}", flush=True)
74
+ return None
75
+
76
+ # --- FUNGSI UPLOAD ZEPETO ---
77
+ def upload_to_zepeto(file_path, z_id, z_pw):
78
+ print(f"πŸ” [Zepeto] Login Playwright...", flush=True)
79
+ try:
80
+ with sync_playwright() as p:
81
+ browser = p.chromium.launch(headless=True, args=['--no-sandbox', '--disable-setuid-sandbox'])
82
+ context = browser.new_context(user_agent="Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/91.0.4472.124 Safari/537.36")
83
+ page = context.new_page()
84
+
85
+ page.goto("https://account.zepeto.me/signin?sm=1", timeout=60000)
86
+ page.fill('input[name="userId"]', z_id)
87
+ page.fill('input[type="password"]', z_pw)
88
+ page.click('button[type="submit"]')
89
+ try: page.wait_for_url(lambda u: "signin" not in u, timeout=60000)
90
+ except:
91
+ browser.close()
92
+ return False, "Login Timeout"
93
+
94
+ cookies = {c['name']: c['value'] for c in context.cookies()}
95
+ jwt_token = cookies.get('token') or cookies.get('jwt')
96
+ browser.close()
97
+
98
+ if not jwt_token: return False, "Token Not Found"
99
+
100
+ print(f"πŸš€ [Zepeto] Uploading via API...", flush=True)
101
+ headers = {"Authorization": f"Bearer {jwt_token}"}
102
+ with open(file_path, "rb") as f:
103
+ res = requests.post(
104
+ "https://cf-api-studio.zepeto.me/api/items",
105
+ headers=headers,
106
+ files={"file": (os.path.basename(file_path), f, "application/octet-stream")},
107
+ timeout=120
108
+ )
109
+ return (True, "Success") if res.status_code in [200, 201] else (False, f"HTTP {res.status_code}")
110
+ except Exception as e: return False, f"Error: {str(e)}"
111
+
112
+ # --- PIPELINE UTAMA ---
113
  def process_pipeline(req: ConversionRequest):
114
  session_id = str(uuid.uuid4())[:8]
115
  SESSION_PATH = f"/tmp/Project_{session_id}"
 
127
  print("πŸ“¦ [COPY] Cloning Project...", flush=True)
128
  shutil.copytree(BASE_PROJECT_PATH, SESSION_PATH, ignore=shutil.ignore_patterns("Library", "Temp", "Logs"))
129
 
130
+ # Cleaner
131
  trash_folders = glob.glob(os.path.join(SESSION_PATH, "Assets", "**", "UnityMeshSimplifier"), recursive=True)
132
  trash_folders += glob.glob(os.path.join(SESSION_PATH, "Assets", "**", "Tests"), recursive=True)
133
  for folder in trash_folders:
134
  if os.path.exists(folder): shutil.rmtree(folder)
135
 
136
+ # Flattener
137
  target_input = os.path.join(SESSION_PATH, "Assets", "InputRaw")
138
  os.makedirs(target_input, exist_ok=True)
 
139
  for root, dirs, files in os.walk(extract_tmp):
140
  for file in files:
141
  if file.endswith((".cs", ".ts", ".js", ".asmdef", ".dll")): os.remove(os.path.join(root, file))
142
+
143
+ print("πŸ“‚ [FLATTENER] Moving files...", flush=True)
144
  for root, dirs, files in os.walk(extract_tmp):
145
  for file in files:
146
  if file.startswith(".") or file.endswith(".meta"): continue
147
  src = os.path.join(root, file)
148
  dst = os.path.join(target_input, file)
149
+ if os.path.exists(dst): dst = os.path.join(target_input, f"{uuid.uuid4().hex[:4]}_{file}")
 
150
  shutil.copy(src, dst)
151
 
152
+ # Manifest
153
  manifest_path = os.path.join(SESSION_PATH, "Packages", "manifest.json")
154
  if os.path.exists(os.path.join(SESSION_PATH, "Packages", "packages-lock.json")):
155
  os.remove(os.path.join(SESSION_PATH, "Packages", "packages-lock.json"))
 
156
  clean_manifest = {
157
  "dependencies": {
158
  "com.unity.render-pipelines.universal": "14.0.10",
 
169
  }
170
  with open(manifest_path, 'w') as f: json.dump(clean_manifest, f, indent=2)
171
 
172
+ # Inject Script (Target Linux)
 
173
  script_path = os.path.join(SESSION_PATH, "Assets", "Editor", "TestBuilder.cs")
174
  os.makedirs(os.path.dirname(script_path), exist_ok=True)
 
175
  csharp_code = r"""
176
  using UnityEngine;
177
  using UnityEditor;
178
  using System.IO;
179
+ public class TestBuilder {
 
 
180
  static readonly string RAW_PATH = "Assets/InputRaw";
181
  static readonly string OUTPUT_DIR = "Assets/Output";
182
+ public static void ManualConvert() {
 
 
183
  Debug.Log("πŸš€ [NATIVE] STARTING BUILD (TARGET: LINUX64)...");
184
  try {
185
  AssetDatabase.Refresh();
 
192
  string assetPath = AssetDatabase.GUIDToAssetPath(guids[0]);
193
  AssetImporter importer = AssetImporter.GetAtPath(assetPath);
194
  importer.assetBundleName = "repacked_item.zepeto";
 
195
  if (!Directory.Exists(OUTPUT_DIR)) Directory.CreateDirectory(OUTPUT_DIR);
196
+
197
+ // TARGET LINUX64
198
+ var manifest = BuildPipeline.BuildAssetBundles(OUTPUT_DIR, BuildAssetBundleOptions.ForceRebuildAssetBundle, BuildTarget.StandaloneLinux64);
199
+
200
+ if (manifest == null) { Debug.LogError("❌ Build Failed"); EditorApplication.Exit(1); }
201
+ else { Debug.Log("πŸŽ‰ Build Finished!"); EditorApplication.Exit(0); }
202
+ } catch (System.Exception e) { Debug.LogError(e.Message); EditorApplication.Exit(1); }
 
 
 
 
 
 
 
 
 
 
 
 
203
  }
204
  }
205
  """
 
209
  print(f"πŸš€ [UNITY] Repacking...", flush=True)
210
  cmd_repack = [
211
  os.environ["UNITY_PATH"], "-batchmode", "-nographics", "-quit",
212
+ "-projectPath", SESSION_PATH, "-executeMethod", "TestBuilder.ManualConvert",
213
+ "-logFile", unity_log_file, "-no-sprite-atlas-cache", "-job-worker-count", "1"
 
 
 
214
  ]
215
  subprocess.run(cmd_repack, check=False)
216
 
217
+ # Print Log (Filtered)
218
  print("\n" + "="*50, flush=True)
219
+ print("πŸ” LOG DIAGNOSTICS:", flush=True)
 
 
220
  if os.path.exists(unity_log_file):
221
  with open(unity_log_file, "r", encoding="utf-8", errors="ignore") as f:
222
  for line in f:
223
  if any(k in line for k in ["[NATIVE]", "Error", "Exception", "Fail", "CRITICAL"]):
224
  if "Shader" in line or "Metal" in line: continue
225
  print(line.strip(), flush=True)
226
+ else: print("❌ Log Not Found")
 
227
  print("="*50 + "\n", flush=True)
228
 
229
+ # OUTPUT CHECK & UPLOAD
230
  output_dir = os.path.join(SESSION_PATH, "Assets", "Output")
231
  target_file = os.path.join(output_dir, "repacked_item.zepeto")
232
 
233
  if os.path.exists(target_file):
234
+ print(f"πŸŽ‰ [DONE] File generated: {target_file}", flush=True)
235
+
236
+ # 1. UPLOAD KE R2 (BACKUP/BUKTI)
237
+ upload_to_r2(target_file, req.filename)
238
+
239
+ # 2. UPLOAD KE ZEPETO
240
+ success, msg = upload_to_zepeto(target_file, req.zepeto_id, req.zepeto_password)
241
+ print(f"πŸš€ [ZEPETO] Result: {msg}", flush=True)
242
  else:
243
+ print("❌ [FAIL] No output file.", flush=True)
244
 
245
  except Exception as e: print(f"❌ [CRITICAL] {e}", flush=True)
246
  finally: