openfree commited on
Commit
c61b01c
·
verified ·
1 Parent(s): a9918b4

Delete app-backup.py

Browse files
Files changed (1) hide show
  1. app-backup.py +0 -202
app-backup.py DELETED
@@ -1,202 +0,0 @@
1
- import os, re, time, json, datetime, requests, gradio as gr
2
-
3
- # ───────────────────── 1. Vercel API ─────────────────────
4
- TOKEN = os.getenv("SVR_TOKEN")
5
- TEAM = os.getenv("VERCEL_TEAM_ID")
6
- if not TOKEN:
7
- raise EnvironmentError("SVR_TOKEN 환경변수를 설정하세요.")
8
- API = "https://api.vercel.com"
9
- HEAD = {"Authorization": f"Bearer {TOKEN}"}
10
-
11
- print(f"API 토큰: {TOKEN[:4]}... (마스킹됨)")
12
- print(f"팀 ID: {TEAM if TEAM else '없음'}")
13
-
14
- # ───────────────────── 2. BEST 데이터 ────────────────────
15
- BEST_FILE, PER_PAGE = "best_games.json", 48
16
- def _init_best():
17
- if not os.path.exists(BEST_FILE):
18
- json.dump([], open(BEST_FILE, "w"))
19
- def _load_best():
20
- try:
21
- data = json.load(open(BEST_FILE))
22
- for it in data:
23
- if "ts" not in it:
24
- it["ts"] = int(it.get("timestamp", time.time()))
25
- return data
26
- except Exception as e:
27
- print(f"BEST 데이터 로드 오류: {e}")
28
- return []
29
-
30
-
31
-
32
-
33
-
34
- def fetch_all(limit=50):
35
- """
36
- Vercel API v10/projects를 사용하여 프로젝트 목록을 가져옵니다.
37
- """
38
- try:
39
- # API 파라미터 설정
40
- params = {"limit": limit}
41
- if TEAM:
42
- params["teamId"] = TEAM
43
-
44
- print(f"Vercel API 호출 (프로젝트): {API}/v10/projects (params={params})")
45
-
46
- resp = requests.get(f"{API}/v10/projects",
47
- headers=HEAD, params=params, timeout=30)
48
-
49
- print(f"API 응답 상태 코드: {resp.status_code}")
50
- if resp.status_code != 200:
51
- print(f"API 응답 오류: {resp.status_code}, {resp.text[:200] if hasattr(resp, 'text') else ''}")
52
- return []
53
-
54
- data = resp.json()
55
-
56
- if "projects" not in data:
57
- print(f"API 응답에 projects 필드가 없습니다: {str(data)[:200]}...")
58
- return []
59
-
60
- projects = data.get("projects", [])
61
- print(f"{len(projects)}개의 프로젝트를 찾았습니다")
62
-
63
- # 각 프로젝트의 최신 배포 정보 가져오기
64
- games = []
65
- for project in projects:
66
- project_id = project.get("id")
67
- project_name = project.get("name", "(제목 없음)")
68
-
69
- # 프로젝트별 최신 배포 가져오기 (projectId 필터 추가)
70
- try:
71
- deploy_params = {
72
- "limit": 1,
73
- "projectId": project_id, # 중요: 해당 프로젝트의 배포만 필터링
74
- "state": "READY"
75
- }
76
-
77
- if TEAM:
78
- deploy_params["teamId"] = TEAM
79
-
80
- print(f"프로젝트 {project_id} ({project_name}) 배포 조회 중...")
81
-
82
- deploy_resp = requests.get(
83
- f"{API}/v6/deployments",
84
- headers=HEAD,
85
- params=deploy_params,
86
- timeout=30
87
- )
88
-
89
- if deploy_resp.status_code == 200:
90
- deploy_data = deploy_resp.json()
91
- deployments = deploy_data.get("deployments", [])
92
-
93
- if deployments:
94
- deployment = deployments[0]
95
- url = deployment.get("url", "")
96
- if url:
97
- games.append({
98
- "title": project_name,
99
- "url": f"https://{url}",
100
- "ts": int(deployment.get("created", time.time() * 1000) / 1000),
101
- "projectId": project_id
102
- })
103
- print(f"프로젝트 {project_name}의 배포 URL: https://{url}")
104
- else:
105
- print(f"프로젝트 {project_name}에 배포된 버전이 없습니다.")
106
- except Exception as e:
107
- print(f"프로젝트 {project_id}의 배포 정보 가져오기 실패: {e}")
108
- continue
109
-
110
- print(f"총 {len(games)}개의 유효한 배포를 찾았습니다")
111
- return sorted(games, key=lambda x: x["ts"], reverse=True)
112
-
113
- except Exception as e:
114
- print(f"Vercel API 오류: {str(e)}")
115
- import traceback
116
- traceback.print_exc()
117
- return []
118
-
119
- # ───────────────────── 4. 페이지네이션 ───────────────────
120
- def page(lst, pg):
121
- s=(pg-1)*PER_PAGE; e=s+PER_PAGE
122
- total=(len(lst)+PER_PAGE-1)//PER_PAGE
123
- return lst[s:e], total
124
-
125
- # ───────────────────── 5. HTML 3-열 그리드 ───────────────
126
- def html(cards, pg, total):
127
- if not cards:
128
- return "<div style='text-align:center;padding:70px;color:#555;'>표시할 배포가 없습니다.</div>"
129
- css=r"""
130
- <style>
131
- body{margin:0;font-family:Poppins,sans-serif;background:linear-gradient(135deg,#C5E8FF 0%,#FFD6E0 100%);}
132
- .grid{display:grid;grid-template-columns:repeat(3,1fr);gap:28px 24px;margin:0 20px 60px;}
133
- @media(max-width:1024px){.grid{grid-template-columns:repeat(2,1fr);} }
134
- @media(max-width:640px){ .grid{grid-template-columns:1fr;} }
135
- .card{background:#fff;border-radius:18px;overflow:hidden;box-shadow:0 10px 25px rgba(0,0,0,.08);transition:.3s}
136
- .card:hover{transform:translateY(-6px);box-shadow:0 16px 40px rgba(0,0,0,.12)}
137
- .hdr{padding:20px 24px;background:rgba(255,255,255,.75);backdrop-filter:blur(8px);border-bottom:1px solid #eee;}
138
- .ttl{margin:0;font-size:1.15rem;font-weight:700;color:#333;white-space:nowrap;overflow:hidden;text-overflow:ellipsis;}
139
- .date{margin-top:4px;font-size:.85rem;color:#777;}
140
- .frame{position:relative;width:100%;padding-top:60%;overflow:hidden;}
141
- .frame iframe{position:absolute;top:0;left:0;width:142.857%;height:142.857%;
142
- transform:scale(.7);transform-origin:top left;border:0;}
143
- .foot{padding:14px 24px;background:rgba(255,255,255,.85);backdrop-filter:blur(8px);text-align:right;}
144
- .link{font-size:.85rem;font-weight:600;color:#4a6dd8;text-decoration:none;}
145
- .cnt{text-align:center;font-size:.85rem;color:#555;margin:10px 0 40px;}
146
- </style>"""
147
-
148
- h=css+"<div class='grid'>"
149
- for c in cards:
150
- date=datetime.datetime.fromtimestamp(int(c["ts"])).strftime("%Y-%m-%d")
151
- h+=f"""
152
- <div class='card'>
153
- <div class='hdr'><p class='ttl'>{c['title']}</p><p class='date'>{date}</p></div>
154
- <div class='frame'><iframe src="{c['url']}" loading="lazy"
155
- allow="accelerometer; camera; encrypted-media; gyroscope;"></iframe></div>
156
- <div class='foot'><a class='link' href="{c['url']}" target="_blank">원본↗</a></div>
157
- </div>"""
158
- h+="</div><p class='cnt'>Page "+str(pg)+" / "+str(total)+"</p>"
159
- return h
160
-
161
- # ───────────────────── 6. Gradio Blocks UI ───────────────
162
- def build():
163
- _init_best()
164
- with gr.Blocks(title="Vibe Game Craft", css="body{overflow-x:hidden;}") as demo:
165
- gr.Markdown("<h1 style='text-align:center;padding:32px 0 0;color:#333;'>🎮 Vibe Game Craft</h1>")
166
- with gr.Row():
167
- b_new = gr.Button("NEW", size="sm")
168
- b_best = gr.Button("BEST", size="sm")
169
- b_prev = gr.Button("⬅️ Prev", size="sm")
170
- b_next = gr.Button("Next ➡️", size="sm")
171
- b_ref = gr.Button("🔄 Reload", size="sm")
172
-
173
- tab = gr.State("new"); np = gr.State(1); bp = gr.State(1); out = gr.HTML()
174
-
175
- def show_new(p=1): d,t=page(fetch_all(),p); return html(d,p,t),"new",p
176
- def show_best(p=1): d,t=page(_load_best(),p); return html(d,p,t),"best",p
177
-
178
- def prev(t,n,b):
179
- if t=="new": n=max(1,n-1); h,_,_=show_new(n); return h,n,b
180
- b=max(1,b-1); h,_,_=show_best(b); return h,n,b
181
- def nxt(t,n,b):
182
- if t=="new":
183
- maxp=(len(fetch_all())+PER_PAGE-1)//PER_PAGE
184
- n=min(maxp,n+1); h,_,_=show_new(n); return h,n,b
185
- maxp=(len(_load_best())+PER_PAGE-1)//PER_PAGE
186
- b=min(maxp,b+1); h,_,_=show_best(b); return h,n,b
187
-
188
- b_new.click(show_new, outputs=[out,tab,np])
189
- b_best.click(show_best,outputs=[out,tab,bp])
190
- b_prev.click(prev, inputs=[tab,np,bp], outputs=[out,np,bp])
191
- b_next.click(nxt, inputs=[tab,np,bp], outputs=[out,np,bp])
192
- b_ref.click(lambda t,n,b: show_new(n)[0] if t=="new" else show_best(b)[0],
193
- inputs=[tab,np,bp], outputs=[out])
194
-
195
- demo.load(show_new, outputs=[out,tab,np])
196
- return demo
197
-
198
- app = build()
199
-
200
- if __name__ == "__main__":
201
- app.launch()
202
-