openfree commited on
Commit
172eb69
ยท
verified ยท
1 Parent(s): c4a09bc

Update app.py

Browse files
Files changed (1) hide show
  1. app.py +29 -212
app.py CHANGED
@@ -1,218 +1,35 @@
1
  import os
2
- import json
3
- import re
4
- import gradio as gr
5
 
6
- # โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€ 1. ๊ธฐ๋ณธ ์„ค์ • โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€
7
- BEST_FILE, PER_PAGE = "best_games.json", 9 # โถ ํ•œ ํŽ˜์ด์ง€์— 9๊ฐœ์”ฉ
8
-
9
-
10
- # โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€ 2. BEST ๋ฐ์ดํ„ฐ โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€
11
- def _init_best():
12
- if not os.path.exists(BEST_FILE):
13
- json.dump([], open(BEST_FILE, "w"), ensure_ascii=False)
14
-
15
-
16
- def _load_best():
17
  try:
18
- raw = json.load(open(BEST_FILE))
19
- return [u if isinstance(u, str) else u.get("url") for u in raw] if isinstance(raw, list) else []
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
20
  except Exception as e:
21
- print("BEST ๋กœ๋“œ ์˜ค๋ฅ˜:", e)
22
- return []
23
-
24
-
25
- def _save_best(lst):
26
- try:
27
- json.dump(lst, open(BEST_FILE, "w"), ensure_ascii=False, indent=2)
28
- return True
29
- except Exception as e:
30
- print("BEST ์ €์žฅ ์˜ค๋ฅ˜:", e)
31
- return False
32
-
33
-
34
- # *.hf.space โ†’ Hub URL(์ƒˆ ํƒญ์šฉ) ๋ณ€ํ™˜
35
- def to_hub_space_url(url: str) -> str:
36
- m = re.match(r"https?://([^-]+)-([^.]+)\.hf\.space(/.*)?", url)
37
- if m:
38
- owner, space, _ = m.groups()
39
- return f"https://huggingface.co/spaces/{owner}/{space}"
40
- return url
41
-
42
-
43
- def add_url_to_best(url: str):
44
- data = _load_best()
45
- if url in data:
46
- return False
47
- data.insert(0, url)
48
- return _save_best(data)
49
-
50
-
51
- # โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€ 3. ์œ ํ‹ธ โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€
52
- def page(lst, pg):
53
- s, e = (pg - 1) * PER_PAGE, (pg - 1) * PER_PAGE + PER_PAGE
54
- total = (len(lst) + PER_PAGE - 1) // PER_PAGE
55
- return lst[s:e], total
56
-
57
-
58
- def process_url_for_iframe(url):
59
- """iframe์šฉ ์ฃผ์†Œ ๋ณ€ํ™˜"""
60
- if "huggingface.co/spaces" in url:
61
- owner, name = url.rstrip("/").split("/spaces/")[1].split("/")[:2]
62
- return f"https://huggingface.co/spaces/{owner}/{name}/embed", "huggingface", []
63
-
64
- m = re.match(r"https?://([^/]+)\.hf\.space(/.*)?", url)
65
- if m:
66
- sub, rest = m.groups()
67
- static_url = f"https://{sub}.static.hf.space{rest or ''}"
68
- return static_url, "hfspace", [url]
69
-
70
- return url, "", []
71
-
72
-
73
- # โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€ 4. HTML ๊ทธ๋ฆฌ๋“œ โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€
74
- def html(cards, pg, total):
75
- if not cards:
76
- return "<div style='text-align:center;padding:70px;color:#555;'>ํ‘œ์‹œํ•  ๋ฐฐํฌ๊ฐ€ ์—†์Šต๋‹ˆ๋‹ค.</div>"
77
-
78
- css = r"""
79
- <style>
80
- /* ํŒŒ์Šคํ…” ๋ฐฐ๊ฒฝ */
81
- body{
82
- margin:0;padding:0;font-family:Poppins,sans-serif;
83
- background:linear-gradient(135deg,#fdf4ff 0%,#f6fbff 50%,#fffaf4 100%);
84
- background-attachment:fixed;
85
- overflow-x:hidden;overflow-y:auto;
86
- }
87
- .container{width:100%;padding:10px 10px var(--bottom-gap,70px);box-sizing:border-box;}
88
- .grid{display:grid;grid-template-columns:repeat(3,1fr);gap:12px;width:100%;}
89
- .card{
90
- background:#fff;border-radius:10px;overflow:hidden;box-shadow:0 4px 10px rgba(0,0,0,0.08);
91
- height:420px;display:flex;flex-direction:column;position:relative;
92
- }
93
- .frame{flex:1;position:relative;overflow:hidden;}
94
- .frame iframe{
95
- position:absolute;top:0;left:0;
96
- width:166.667%;height:166.667%;
97
- transform:scale(0.6);transform-origin:top left;border:0;
98
- }
99
- .frame.huggingface iframe{width:100%!important;height:100%!important;transform:none!important;border:none!important;}
100
- .frame.hfspace iframe{
101
- width:200%;height:200%;
102
- transform:scale(0.5);transform-origin:top left;border:0;
103
- }
104
- .foot{height:34px;display:flex;align-items:center;justify-content:center;background:#fafafa;border-top:1px solid #eee;}
105
- .foot a{font-size:0.85rem;font-weight:600;color:#4a6dd8;text-decoration:none;}
106
- .foot a:hover{text-decoration:underline;}
107
- @media(min-width:1200px){.card{height:560px;}}
108
- @media(max-width:767px){
109
- .grid{grid-template-columns:1fr;}
110
- .card{height:480px;}
111
- }
112
- </style>"""
113
-
114
- # ๋ฒ„ํŠผ๊ณผ ํ—ค๋” ๋†’์ด๋ฅผ ๊ณ ๋ คํ•ด ์Šคํฌ๋กค ์˜์—ญ ๋™์ ์œผ๋กœ ๊ณ„์‚ฐ
115
- js = r"""
116
- <script>
117
- function adjustGap(){
118
- const header = document.querySelector('.app-header');
119
- const buttons = document.querySelector('.button-row');
120
- const gap = (buttons?.offsetHeight || 60) + 10; // 10px ์—ฌ์œ 
121
- document.documentElement.style.setProperty('--bottom-gap', gap + 'px');
122
- const content = document.getElementById('content-area');
123
- const h = (header?.offsetHeight || 0) + (buttons?.offsetHeight || 60);
124
- content.style.height = `calc(100vh - ${h}px)`;
125
- }
126
- window.addEventListener('load',adjustGap);
127
- window.addEventListener('resize',adjustGap);
128
- </script>
129
- """
130
-
131
- h = css + js + '<div class="container"><div class="grid">'
132
- for idx, url in enumerate(cards):
133
- iframe_url, extra_cls, alt_urls = process_url_for_iframe(url)
134
- frame_class = f"frame {extra_cls}".strip()
135
- iframe_id = f"iframe-{idx}-{hash(url)%10000}"
136
- alt_attr = f'data-alternate-urls="{",".join(alt_urls)}"' if alt_urls else ""
137
- safe_url = to_hub_space_url(url)
138
- h += f"""
139
- <div class="card">
140
- <div class="{frame_class}">
141
- <iframe id="{iframe_id}" src="{iframe_url}" loading="lazy"
142
- sandbox="allow-forms allow-modals allow-popups allow-popups-to-escape-sandbox allow-same-origin allow-scripts allow-downloads"
143
- data-original-url="{url}" {alt_attr}></iframe>
144
- </div>
145
- <div class="foot">
146
- <a href="{safe_url}" target="_blank" rel="noopener noreferrer">โ†— Open in Full Screen (New Tab)</a>
147
- </div>
148
- </div>"""
149
- h += "</div></div>"
150
- h += f'<div class="page-info">Page {pg} / {total}</div>'
151
- return h
152
-
153
-
154
- # โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€ 5. Gradio UI โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€
155
- def build():
156
- _init_best()
157
-
158
- header = """
159
- <style>
160
- .app-header{position:sticky;top:0;text-align:center;background:#fff;padding:16px 0 8px;border-bottom:1px solid #eee;z-index:1100;}
161
- .badge-row{display:inline-flex;gap:8px;margin:8px 0;}
162
- </style>
163
- <div class="app-header">
164
- <h1 style="margin:0;font-size:28px;">๐ŸŽฎ Vibe Game Gallery</h1>
165
- <p style="margin:4px 0;font-size:11px;">
166
- Only high-quality games automatically generated with <b>Vibe Game Craft</b> are showcased here.<br>
167
- Every game includes its full source code, and anyone can freely copy the <code>index.html</code>
168
- file from each URL and modify it as desired. All content is released under the <b>Apache&nbsp;2.0</b> license.
169
- </p>
170
- <div class="badge-row">
171
- <a href="https://huggingface.co/spaces/openfree/Vibe-Game" target="_blank">
172
- <img src="https://img.shields.io/static/v1?label=huggingface&message=Vibe%20Game%20Craft&color=800080&labelColor=ffa500&logo=huggingface&logoColor=ffff00&style=for-the-badge">
173
- </a>
174
- <a href="https://huggingface.co/spaces/openfree/Game-Gallery" target="_blank">
175
- <img src="https://img.shields.io/static/v1?label=huggingface&message=Game%20Gallery&color=800080&labelColor=ffa500&logo=huggingface&logoColor=ffff00&style=for-the-badge">
176
- </a>
177
- <a href="https://discord.gg/openfreeai" target="_blank">
178
- <img src="https://img.shields.io/static/v1?label=Discord&message=Openfree%20AI&color=0000ff&labelColor=800080&logo=discord&logoColor=white&style=for-the-badge">
179
- </a>
180
- </div>
181
- </div>"""
182
-
183
- global_css = """
184
- footer{display:none !important;}
185
- .button-row{
186
- position:fixed!important;bottom:0!important;left:0!important;right:0!important;
187
- height:60px;background:#f0f0f0;padding:10px;text-align:center;
188
- box-shadow:0 -2px 10px rgba(0,0,0,.05);z-index:10000;
189
- }
190
- .button-row button{margin:0 10px;padding:10px 20px;font-size:16px;font-weight:bold;border-radius:50px;}
191
- #content-area{overflow-y:auto;}
192
- """
193
-
194
- with gr.Blocks(title="Vibe Game Gallery", css=global_css) as demo:
195
- gr.HTML(header)
196
- out = gr.HTML(elem_id="content-area")
197
- with gr.Row(elem_classes="button-row"):
198
- b_prev = gr.Button("โ—€ ์ด์ „", size="lg")
199
- b_next = gr.Button("๋‹ค์Œ โ–ถ", size="lg")
200
-
201
- bp = gr.State(1)
202
-
203
- def render(p=1):
204
- data, tot = page(_load_best(), p)
205
- return html(data, p, tot), p
206
-
207
- b_prev.click(lambda p: render(max(1, p-1)), inputs=bp, outputs=[out, bp])
208
- b_next.click(lambda p: render(p+1), inputs=bp, outputs=[out, bp])
209
-
210
- demo.load(render, outputs=[out, bp])
211
-
212
- return demo
213
-
214
-
215
- app = build()
216
 
217
  if __name__ == "__main__":
218
- app.launch()
 
1
  import os
2
+ import sys
3
+ import streamlit as st
4
+ from tempfile import NamedTemporaryFile
5
 
6
+ def main():
 
 
 
 
 
 
 
 
 
 
7
  try:
8
+ # Get the code from secrets
9
+ code = os.environ.get("MAIN_CODE")
10
+
11
+ if not code:
12
+ st.error("โš ๏ธ The application code wasn't found in secrets. Please add the MAIN_CODE secret.")
13
+ return
14
+
15
+ # Create a temporary Python file
16
+ with NamedTemporaryFile(suffix='.py', delete=False, mode='w') as tmp:
17
+ tmp.write(code)
18
+ tmp_path = tmp.name
19
+
20
+ # Execute the code
21
+ exec(compile(code, tmp_path, 'exec'), globals())
22
+
23
+ # Clean up the temporary file
24
+ try:
25
+ os.unlink(tmp_path)
26
+ except:
27
+ pass
28
+
29
  except Exception as e:
30
+ st.error(f"โš ๏ธ Error loading or executing the application: {str(e)}")
31
+ import traceback
32
+ st.code(traceback.format_exc())
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
33
 
34
  if __name__ == "__main__":
35
+ main()