ginipick commited on
Commit
b98dc44
ยท
verified ยท
1 Parent(s): 216bae4

Update app.py

Browse files
Files changed (1) hide show
  1. app.py +116 -0
app.py CHANGED
@@ -1,3 +1,36 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
  def fetch_all(limit=50):
2
  """
3
  Vercel API v10/projects๋ฅผ ์‚ฌ์šฉํ•˜์—ฌ ํ”„๋กœ์ ํŠธ ๋ชฉ๋ก์„ ๊ฐ€์ ธ์˜ต๋‹ˆ๋‹ค.
@@ -83,5 +116,88 @@ def fetch_all(limit=50):
83
  traceback.print_exc()
84
  return []
85
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
86
 
 
 
 
87
 
 
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๋ฅผ ์‚ฌ์šฉํ•˜์—ฌ ํ”„๋กœ์ ํŠธ ๋ชฉ๋ก์„ ๊ฐ€์ ธ์˜ต๋‹ˆ๋‹ค.
 
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
+
203