openfree commited on
Commit
c0d421c
ยท
verified ยท
1 Parent(s): 9da8287

Delete app.py

Browse files
Files changed (1) hide show
  1. app.py +0 -368
app.py DELETED
@@ -1,368 +0,0 @@
1
- import os, re, json, sqlite3
2
- from flask import Flask, render_template, request, jsonify
3
-
4
- app = Flask(__name__)
5
-
6
- # โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€ ๊ฒฝ๋กœ๋ฅผ ์ ˆ๋Œ€ ๊ฒฝ๋กœ๋กœ ์ง€์ • โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€
7
- BASE_DIR = os.path.dirname(os.path.abspath(__file__))
8
- DB_FILE = os.path.join(BASE_DIR, "favorite_sites.json")
9
- SQLITE_DB = os.path.join(BASE_DIR, "favorite_sites.db")
10
-
11
- # ์ดํ•˜ ๊ธฐ์กด ์ฝ”๋“œ ๋™์ผ
12
- BLOCKED_DOMAINS = [
13
- "naver.com", "daum.net", "google.com",
14
- "facebook.com", "instagram.com", "kakao.com",
15
- "ycombinator.com"
16
- ]
17
-
18
- CATEGORIES = {
19
- "Productivity": [
20
- "https://huggingface.co/spaces/ginigen/perflexity-clone",
21
- "https://huggingface.co/spaces/ginipick/IDEA-DESIGN",
22
- "https://huggingface.co/spaces/VIDraft/mouse-webgen",
23
- "https://huggingface.co/spaces/openfree/Vibe-Game",
24
- "https://huggingface.co/spaces/openfree/Game-Gallery",
25
- "https://huggingface.co/spaces/aiqtech/Contributors-Leaderboard",
26
- "https://huggingface.co/spaces/fantaxy/Model-Leaderboard",
27
- "https://huggingface.co/spaces/fantaxy/Space-Leaderboard",
28
- "https://huggingface.co/spaces/openfree/Korean-Leaderboard",
29
- ],
30
- "Multimodal": [
31
- "https://huggingface.co/spaces/openfree/DreamO-video",
32
- "https://huggingface.co/spaces/Heartsync/NSFW-Uncensored-photo",
33
- "https://huggingface.co/spaces/Heartsync/NSFW-Uncensored",
34
- "https://huggingface.co/spaces/fantaxy/Sound-AI-SFX",
35
- "https://huggingface.co/spaces/ginigen/SFX-Sound-magic",
36
- "https://huggingface.co/spaces/ginigen/VoiceClone-TTS",
37
- "https://huggingface.co/spaces/aiqcamp/MCP-kokoro",
38
- "https://huggingface.co/spaces/aiqcamp/ENGLISH-Speaking-Scoring",
39
- ],
40
- "Professional": [
41
- "https://huggingface.co/spaces/ginigen/blogger",
42
- "https://huggingface.co/spaces/VIDraft/money-radar",
43
- "https://huggingface.co/spaces/immunobiotech/drug-discovery",
44
- "https://huggingface.co/spaces/immunobiotech/Gemini-MICHELIN",
45
- "https://huggingface.co/spaces/Heartsync/Papers-Leaderboard",
46
- "https://huggingface.co/spaces/VIDraft/PapersImpact",
47
- "https://huggingface.co/spaces/ginipick/AgentX-Papers",
48
- "https://huggingface.co/spaces/openfree/Cycle-Navigator",
49
- ],
50
- "Image": [
51
- "https://huggingface.co/spaces/ginigen/interior-design",
52
- "https://huggingface.co/spaces/ginigen/Workflow-Canvas",
53
- "https://huggingface.co/spaces/ginigen/Multi-LoRAgen",
54
- "https://huggingface.co/spaces/ginigen/Every-Text",
55
- "https://huggingface.co/spaces/ginigen/text3d-r1",
56
- "https://huggingface.co/spaces/ginipick/FLUXllama",
57
- "https://huggingface.co/spaces/Heartsync/FLUX-Vision",
58
- "https://huggingface.co/spaces/ginigen/VisualCloze",
59
- "https://huggingface.co/spaces/seawolf2357/Ghibli-Multilingual-Text-rendering",
60
- "https://huggingface.co/spaces/ginigen/Ghibli-Meme-Studio",
61
- "https://huggingface.co/spaces/VIDraft/Open-Meme-Studio",
62
- "https://huggingface.co/spaces/ginigen/3D-LLAMA",
63
- ],
64
- "LLM / VLM": [
65
- "https://huggingface.co/spaces/VIDraft/Gemma-3-R1984-4B",
66
- "https://huggingface.co/spaces/VIDraft/Gemma-3-R1984-12B",
67
- "https://huggingface.co/spaces/ginigen/Mistral-Perflexity",
68
- "https://huggingface.co/spaces/aiqcamp/gemini-2.5-flash-preview",
69
- "https://huggingface.co/spaces/openfree/qwen3-30b-a3b-research",
70
- "https://huggingface.co/spaces/openfree/qwen3-235b-a22b-research",
71
- "https://huggingface.co/spaces/openfree/Llama-4-Maverick-17B-Research",
72
- ],
73
- }
74
-
75
- def init_db():
76
- if not os.path.exists(DB_FILE):
77
- with open(DB_FILE, "w", encoding="utf-8") as f:
78
- json.dump([], f, ensure_ascii=False)
79
-
80
- conn = sqlite3.connect(SQLITE_DB)
81
- cursor = conn.cursor()
82
- cursor.execute('''
83
- CREATE TABLE IF NOT EXISTS urls (
84
- id INTEGER PRIMARY KEY AUTOINCREMENT,
85
- url TEXT UNIQUE NOT NULL,
86
- date_added TIMESTAMP DEFAULT CURRENT_TIMESTAMP
87
- )
88
- ''')
89
- conn.commit()
90
-
91
- # JSON์— ์žˆ๋Š” URL์„ (์ดˆ๊ธฐํ™” ์‹œ) SQLite๋กœ๋„ ๋ณต์‚ฌ
92
- json_urls = load_json()
93
- if json_urls:
94
- db_urls = load_db_sqlite()
95
- for url in json_urls:
96
- if url not in db_urls:
97
- add_url_to_sqlite(url)
98
-
99
- conn.close()
100
-
101
- def load_json():
102
- """Load URLs from JSON file"""
103
- try:
104
- with open(DB_FILE, "r", encoding="utf-8") as f:
105
- raw = json.load(f)
106
- return raw if isinstance(raw, list) else []
107
- except Exception:
108
- return []
109
-
110
- def save_json(lst):
111
- """Save URLs to JSON file"""
112
- try:
113
- with open(DB_FILE, "w", encoding="utf-8") as f:
114
- json.dump(lst, f, ensure_ascii=False, indent=2)
115
- return True
116
- except Exception:
117
- return False
118
-
119
- def load_db_sqlite():
120
- """Load URLs from SQLite"""
121
- conn = sqlite3.connect(SQLITE_DB)
122
- cursor = conn.cursor()
123
- cursor.execute("SELECT url FROM urls ORDER BY date_added DESC")
124
- urls = [row[0] for row in cursor.fetchall()]
125
- conn.close()
126
- return urls
127
-
128
- def add_url_to_sqlite(url):
129
- """Add a URL to SQLite database"""
130
- conn = sqlite3.connect(SQLITE_DB)
131
- cursor = conn.cursor()
132
- try:
133
- cursor.execute("INSERT INTO urls (url) VALUES (?)", (url,))
134
- conn.commit()
135
- success = True
136
- except sqlite3.IntegrityError:
137
- success = False
138
- conn.close()
139
- return success
140
-
141
- def update_url_in_sqlite(old_url, new_url):
142
- """Update a URL in SQLite database"""
143
- conn = sqlite3.connect(SQLITE_DB)
144
- cursor = conn.cursor()
145
- try:
146
- cursor.execute("UPDATE urls SET url = ? WHERE url = ?", (new_url, old_url))
147
- if cursor.rowcount > 0:
148
- conn.commit()
149
- success = True
150
- else:
151
- success = False
152
- except sqlite3.IntegrityError:
153
- success = False
154
- conn.close()
155
- return success
156
-
157
- def delete_url_from_sqlite(url):
158
- """Delete a URL from SQLite database"""
159
- conn = sqlite3.connect(SQLITE_DB)
160
- cursor = conn.cursor()
161
- cursor.execute("DELETE FROM urls WHERE url = ?", (url,))
162
- if cursor.rowcount > 0:
163
- conn.commit()
164
- success = True
165
- else:
166
- success = False
167
- conn.close()
168
- return success
169
-
170
- def load_db():
171
- """Load URLs: ์šฐ์„  SQLite์—์„œ ๋ถˆ๋Ÿฌ์˜จ ๋’ค, ์—†์œผ๋ฉด JSON ๋ถˆ๋Ÿฌ์˜ค๊ธฐ"""
172
- urls = load_db_sqlite()
173
- if not urls:
174
- urls = load_json()
175
- for url in urls:
176
- add_url_to_sqlite(url)
177
- return urls
178
-
179
- def save_db(lst):
180
- """Save URLs to both SQLite and JSON"""
181
- conn = sqlite3.connect(SQLITE_DB)
182
- cursor = conn.cursor()
183
- cursor.execute("DELETE FROM urls")
184
- for url in lst:
185
- cursor.execute("INSERT INTO urls (url) VALUES (?)", (url,))
186
- conn.commit()
187
- conn.close()
188
- return save_json(lst)
189
-
190
- def direct_url(hf_url):
191
- m = re.match(r"https?://huggingface\.co/spaces/([^/]+)/([^/?#]+)", hf_url)
192
- if not m:
193
- return hf_url
194
- owner, name = m.groups()
195
- owner = owner.lower()
196
- name = name.replace('.', '-').replace('_', '-').lower()
197
- return f"https://{owner}-{name}.hf.space"
198
-
199
- def screenshot_url(url):
200
- return f"https://image.thum.io/get/fullpage/{url}"
201
-
202
- def process_url_for_preview(url):
203
- if any(d for d in BLOCKED_DOMAINS if d in url):
204
- return screenshot_url(url), "snapshot"
205
- if "vibe-coding-tetris" in url or "World-of-Tank-GAME" in url or "Minesweeper-Game" in url:
206
- return screenshot_url(url), "snapshot"
207
- try:
208
- if "huggingface.co/spaces" in url:
209
- parts = url.rstrip("/").split("/")
210
- if len(parts) >= 5:
211
- owner = parts[-2]
212
- name = parts[-1]
213
- embed_url = f"https://huggingface.co/spaces/{owner}/{name}/embed"
214
- return embed_url, "iframe"
215
- except Exception:
216
- return screenshot_url(url), "snapshot"
217
- return url, "iframe"
218
-
219
- @app.route('/api/category')
220
- def api_category():
221
- cat = request.args.get('name', '')
222
- urls = CATEGORIES.get(cat, [])
223
- return jsonify([
224
- {
225
- "title": url.split('/')[-1],
226
- "owner": url.split('/')[-2] if '/spaces/' in url else '',
227
- "iframe": direct_url(url),
228
- "shot": screenshot_url(url),
229
- "hf": url
230
- } for url in urls
231
- ])
232
-
233
- @app.route('/api/favorites')
234
- def api_favorites():
235
- urls = load_db()
236
- page = int(request.args.get('page', 1))
237
- per_page = int(request.args.get('per_page', 9))
238
-
239
- total_pages = max(1, (len(urls) + per_page - 1) // per_page)
240
- start = (page - 1) * per_page
241
- end = min(start + per_page, len(urls))
242
-
243
- urls_page = urls[start:end]
244
- result = []
245
- for url in urls_page:
246
- try:
247
- preview_url, mode = process_url_for_preview(url)
248
- result.append({
249
- "title": url.split('/')[-1],
250
- "url": url,
251
- "preview_url": preview_url,
252
- "mode": mode
253
- })
254
- except Exception:
255
- result.append({
256
- "title": url.split('/')[-1],
257
- "url": url,
258
- "preview_url": screenshot_url(url),
259
- "mode": "snapshot"
260
- })
261
- return jsonify({
262
- "items": result,
263
- "page": page,
264
- "total_pages": total_pages
265
- })
266
-
267
- @app.route('/api/url/add', methods=['POST'])
268
- def add_url():
269
- url = request.form.get('url', '').strip()
270
- if not url:
271
- return jsonify({"success": False, "message": "URL is required"})
272
-
273
- conn = sqlite3.connect(SQLITE_DB)
274
- cursor = conn.cursor()
275
- try:
276
- cursor.execute("INSERT INTO urls (url) VALUES (?)", (url,))
277
- conn.commit()
278
- success = True
279
- except sqlite3.IntegrityError:
280
- success = False
281
- except Exception as e:
282
- print(f"SQLite error: {str(e)}")
283
- success = False
284
- finally:
285
- conn.close()
286
-
287
- if not success:
288
- return jsonify({"success": False, "message": "URL already exists or could not be added"})
289
-
290
- # JSON ํŒŒ์ผ์—๋„ ์ถ”๊ฐ€ (๋ฐฑ์—…์šฉ)
291
- data = load_json()
292
- if url not in data:
293
- data.insert(0, url)
294
- save_json(data)
295
-
296
- return jsonify({"success": True, "message": "URL added successfully"})
297
-
298
- @app.route('/api/url/update', methods=['POST'])
299
- def update_url():
300
- old = request.form.get('old', '')
301
- new = request.form.get('new', '').strip()
302
-
303
- if not new:
304
- return jsonify({"success": False, "message": "New URL is required"})
305
-
306
- if not update_url_in_sqlite(old, new):
307
- return jsonify({"success": False, "message": "URL not found or new URL already exists"})
308
-
309
- data = load_json()
310
- try:
311
- idx = data.index(old)
312
- data[idx] = new
313
- save_json(data)
314
- except ValueError:
315
- data.append(new)
316
- save_json(data)
317
-
318
- return jsonify({"success": True, "message": "URL updated successfully"})
319
-
320
- @app.route('/api/url/delete', methods=['POST'])
321
- def delete_url():
322
- url = request.form.get('url', '')
323
-
324
- if not delete_url_from_sqlite(url):
325
- return jsonify({"success": False, "message": "URL not found"})
326
-
327
- data = load_json()
328
- try:
329
- data.remove(url)
330
- save_json(data)
331
- except ValueError:
332
- pass
333
-
334
- return jsonify({"success": True, "message": "URL deleted successfully"})
335
-
336
- @app.route('/')
337
- def home():
338
- os.makedirs('templates', exist_ok=True)
339
- with open('templates/index.html', 'w', encoding='utf-8') as fp:
340
- fp.write(r'''<!DOCTYPE html>
341
- <!-- ์ดํ•˜ HTML ํ…œํ”Œ๋ฆฟ์€ ๊ธฐ์กด ์ฝ”๋“œ ๊ทธ๋Œ€๋กœ ์œ ์ง€ -->
342
- <!-- ... -->
343
- ''')
344
- return render_template('index.html', cats=list(CATEGORIES.keys()))
345
-
346
- init_db()
347
-
348
- def ensure_db_consistency():
349
- urls = load_db_sqlite()
350
- save_json(urls)
351
-
352
- @app.before_request
353
- def before_request_func():
354
- if not hasattr(app, '_got_first_request'):
355
- ensure_db_consistency()
356
- app._got_first_request = True
357
-
358
- if __name__ == '__main__':
359
- print("Initializing database...")
360
- init_db()
361
- db_path = os.path.abspath(SQLITE_DB)
362
- print(f"SQLite DB path: {db_path}")
363
- if os.path.exists(db_path):
364
- print(f"Database file exists, size: {os.path.getsize(db_path)} bytes")
365
- else:
366
- print("Warning: Database file does not exist after initialization!")
367
-
368
- app.run(host='0.0.0.0', port=7860)