Offex commited on
Commit
3e8ea08
Β·
verified Β·
1 Parent(s): 5750f08

Update app.py

Browse files
Files changed (1) hide show
  1. app.py +458 -40
app.py CHANGED
@@ -12,50 +12,468 @@ HTML_CODE = """
12
  <head>
13
  <meta charset="UTF-8">
14
  <meta name="viewport" content="width=device-width, initial-scale=1.0">
15
- <title>Universal Video Downloader</title>
16
- <script src="https://cdn.tailwindcss.com"></script>
17
- <link href="https://cdnjs.cloudflare.com/ajax/libs/font-awesome/6.0.0/css/all.min.css" rel="stylesheet">
 
18
  <style>
19
- body { background:#0f172a; color:white; font-family:sans-serif; }
20
- .glass { background:rgba(30,41,59,.85); backdrop-filter:blur(12px);
21
- border-radius:16px; border:1px solid rgba(255,255,255,.1); }
22
- .loader { border:3px solid #f3f3f3; border-top:3px solid #3498db;
23
- border-radius:50%; width:18px; height:18px;
24
- animation:spin 1s linear infinite; display:none; }
25
- @keyframes spin {100%{transform:rotate(360deg)}}
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
26
  </style>
27
  </head>
28
 
29
- <body class="flex items-center justify-center min-h-screen p-4">
30
- <div class="glass w-full max-w-md p-6">
31
- <h1 class="text-3xl text-center font-bold text-blue-400 mb-6">
32
- UniLoader <span class="text-xs text-gray-400">HF Edition</span>
33
- </h1>
34
-
35
- <form method="POST" action="/download"
36
- onsubmit="document.getElementById('sp').style.display='inline-block'"
37
- class="space-y-4">
38
- <input name="url" required
39
- class="w-full bg-gray-900 border border-gray-700 p-3 rounded-lg"
40
- placeholder="Paste YouTube / TikTok link">
41
-
42
- <button class="w-full bg-blue-600 hover:bg-blue-700 p-3 rounded-lg
43
- font-bold flex items-center justify-center gap-2">
44
- Download Best Quality
45
- <div id="sp" class="loader"></div>
46
- </button>
47
- </form>
48
-
49
- {% if error %}
50
- <div class="mt-4 bg-red-900/50 p-3 rounded text-center text-sm">
51
- {{ error }}
52
- </div>
53
- {% endif %}
54
-
55
- <p class="text-xs text-gray-400 mt-4 text-center">
56
- Note: TikTok HD on Hugging Face is limited by platform.
57
- </p>
58
- </div>
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
59
  </body>
60
  </html>
61
  """
 
12
  <head>
13
  <meta charset="UTF-8">
14
  <meta name="viewport" content="width=device-width, initial-scale=1.0">
15
+ <title>UniLoader β€” Premium Video Downloader</title>
16
+ <link rel="preconnect" href="https://fonts.googleapis.com">
17
+ <link href="https://fonts.googleapis.com/css2?family=Playfair+Display:wght@700;900&family=DM+Sans:wght@300;400;500&display=swap" rel="stylesheet">
18
+ <link href="https://cdnjs.cloudflare.com/ajax/libs/font-awesome/6.5.0/css/all.min.css" rel="stylesheet">
19
  <style>
20
+ *, *::before, *::after { box-sizing: border-box; margin: 0; padding: 0; }
21
+
22
+ :root {
23
+ --gold: #c9a84c;
24
+ --gold-light: #f0d080;
25
+ --gold-dim: rgba(201,168,76,0.15);
26
+ --bg-deep: #080b12;
27
+ --bg-card: rgba(12, 17, 30, 0.92);
28
+ --border: rgba(201,168,76,0.25);
29
+ --text: #e8e0d0;
30
+ --muted: #7a7060;
31
+ }
32
+
33
+ html, body {
34
+ min-height: 100vh;
35
+ background: var(--bg-deep);
36
+ font-family: 'DM Sans', sans-serif;
37
+ color: var(--text);
38
+ overflow-x: hidden;
39
+ }
40
+
41
+ /* ── Animated Background ── */
42
+ .bg-scene {
43
+ position: fixed; inset: 0; z-index: 0;
44
+ overflow: hidden;
45
+ pointer-events: none;
46
+ }
47
+
48
+ .orb {
49
+ position: absolute;
50
+ border-radius: 50%;
51
+ filter: blur(80px);
52
+ opacity: 0.35;
53
+ animation: drift 18s ease-in-out infinite alternate;
54
+ }
55
+ .orb1 {
56
+ width: 520px; height: 520px;
57
+ background: radial-gradient(circle, #1a3a6e, transparent 70%);
58
+ top: -180px; left: -120px;
59
+ animation-duration: 22s;
60
+ }
61
+ .orb2 {
62
+ width: 380px; height: 380px;
63
+ background: radial-gradient(circle, #6e3a1a, transparent 70%);
64
+ bottom: -100px; right: -80px;
65
+ animation-duration: 17s;
66
+ animation-delay: -8s;
67
+ }
68
+ .orb3 {
69
+ width: 240px; height: 240px;
70
+ background: radial-gradient(circle, var(--gold), transparent 70%);
71
+ top: 45%; left: 55%;
72
+ opacity: 0.12;
73
+ animation-duration: 25s;
74
+ animation-delay: -13s;
75
+ }
76
+
77
+ @keyframes drift {
78
+ 0% { transform: translate(0, 0) scale(1); }
79
+ 50% { transform: translate(30px, -40px) scale(1.08); }
80
+ 100% { transform: translate(-20px, 30px) scale(0.95); }
81
+ }
82
+
83
+ /* Fine grid overlay */
84
+ .bg-grid {
85
+ position: fixed; inset: 0; z-index: 0;
86
+ background-image:
87
+ linear-gradient(rgba(201,168,76,0.04) 1px, transparent 1px),
88
+ linear-gradient(90deg, rgba(201,168,76,0.04) 1px, transparent 1px);
89
+ background-size: 52px 52px;
90
+ }
91
+
92
+ /* ── Layout ── */
93
+ .page-wrap {
94
+ position: relative; z-index: 1;
95
+ min-height: 100vh;
96
+ display: flex; flex-direction: column;
97
+ align-items: center; justify-content: center;
98
+ padding: 2rem 1rem;
99
+ }
100
+
101
+ /* ── Brand Header ── */
102
+ .brand {
103
+ text-align: center;
104
+ margin-bottom: 2.8rem;
105
+ animation: fadeDown 0.7s ease both;
106
+ }
107
+
108
+ .brand-badge {
109
+ display: inline-block;
110
+ font-family: 'DM Sans', sans-serif;
111
+ font-size: 0.65rem;
112
+ font-weight: 500;
113
+ letter-spacing: 0.22em;
114
+ text-transform: uppercase;
115
+ color: var(--gold);
116
+ background: var(--gold-dim);
117
+ border: 1px solid var(--border);
118
+ border-radius: 100px;
119
+ padding: 4px 14px;
120
+ margin-bottom: 1.1rem;
121
+ }
122
+
123
+ .brand-title {
124
+ font-family: 'Playfair Display', serif;
125
+ font-size: clamp(2.6rem, 7vw, 4.2rem);
126
+ font-weight: 900;
127
+ line-height: 1;
128
+ letter-spacing: -0.01em;
129
+ background: linear-gradient(135deg, #f0d080 0%, #c9a84c 45%, #f0d080 100%);
130
+ -webkit-background-clip: text;
131
+ -webkit-text-fill-color: transparent;
132
+ background-clip: text;
133
+ background-size: 200% auto;
134
+ animation: shimmer 4s linear infinite;
135
+ }
136
+
137
+ .brand-sub {
138
+ margin-top: 0.6rem;
139
+ font-size: 0.82rem;
140
+ font-weight: 300;
141
+ letter-spacing: 0.06em;
142
+ color: var(--muted);
143
+ }
144
+
145
+ @keyframes shimmer {
146
+ 0% { background-position: 0% center; }
147
+ 100% { background-position: 200% center; }
148
+ }
149
+
150
+ /* ── Card ── */
151
+ .card {
152
+ width: 100%; max-width: 480px;
153
+ background: var(--bg-card);
154
+ border: 1px solid var(--border);
155
+ border-radius: 20px;
156
+ padding: 2.2rem 2rem;
157
+ position: relative;
158
+ backdrop-filter: blur(24px);
159
+ box-shadow:
160
+ 0 0 0 1px rgba(255,255,255,0.04) inset,
161
+ 0 40px 80px rgba(0,0,0,0.6),
162
+ 0 0 60px rgba(201,168,76,0.06);
163
+ animation: fadeUp 0.7s ease 0.15s both;
164
+ }
165
+
166
+ /* Top gold accent line */
167
+ .card::before {
168
+ content: '';
169
+ position: absolute;
170
+ top: 0; left: 12%; right: 12%;
171
+ height: 1px;
172
+ background: linear-gradient(90deg, transparent, var(--gold), transparent);
173
+ border-radius: 100px;
174
+ }
175
+
176
+ /* ── Input Field ── */
177
+ .input-wrap {
178
+ position: relative;
179
+ margin-bottom: 1.2rem;
180
+ }
181
+
182
+ .input-icon {
183
+ position: absolute;
184
+ left: 16px; top: 50%;
185
+ transform: translateY(-50%);
186
+ color: var(--gold);
187
+ font-size: 0.85rem;
188
+ opacity: 0.7;
189
+ pointer-events: none;
190
+ transition: opacity 0.2s;
191
+ }
192
+
193
+ .url-input {
194
+ width: 100%;
195
+ background: rgba(255,255,255,0.04);
196
+ border: 1px solid rgba(201,168,76,0.2);
197
+ border-radius: 12px;
198
+ padding: 14px 16px 14px 42px;
199
+ font-family: 'DM Sans', sans-serif;
200
+ font-size: 0.9rem;
201
+ font-weight: 400;
202
+ color: var(--text);
203
+ outline: none;
204
+ transition: border-color 0.25s, box-shadow 0.25s, background 0.25s;
205
+ letter-spacing: 0.01em;
206
+ }
207
+
208
+ .url-input::placeholder { color: var(--muted); }
209
+
210
+ .url-input:focus {
211
+ border-color: var(--gold);
212
+ background: rgba(201,168,76,0.06);
213
+ box-shadow: 0 0 0 3px rgba(201,168,76,0.12);
214
+ }
215
+
216
+ .url-input:focus + .input-icon { opacity: 1; }
217
+
218
+ /* ── Button ── */
219
+ .dl-btn {
220
+ width: 100%;
221
+ padding: 15px;
222
+ font-family: 'DM Sans', sans-serif;
223
+ font-size: 0.92rem;
224
+ font-weight: 500;
225
+ letter-spacing: 0.04em;
226
+ color: #0a0e1a;
227
+ background: linear-gradient(135deg, #f0d080 0%, #c9a84c 50%, #e8c060 100%);
228
+ background-size: 200% auto;
229
+ border: none;
230
+ border-radius: 12px;
231
+ cursor: pointer;
232
+ display: flex;
233
+ align-items: center;
234
+ justify-content: center;
235
+ gap: 10px;
236
+ transition: background-position 0.4s ease, transform 0.15s, box-shadow 0.2s;
237
+ box-shadow: 0 4px 24px rgba(201,168,76,0.3);
238
+ position: relative;
239
+ overflow: hidden;
240
+ }
241
+
242
+ .dl-btn::after {
243
+ content: '';
244
+ position: absolute; inset: 0;
245
+ background: rgba(255,255,255,0);
246
+ transition: background 0.2s;
247
+ }
248
+
249
+ .dl-btn:hover {
250
+ background-position: right center;
251
+ box-shadow: 0 6px 32px rgba(201,168,76,0.45);
252
+ transform: translateY(-1px);
253
+ }
254
+
255
+ .dl-btn:hover::after { background: rgba(255,255,255,0.08); }
256
+ .dl-btn:active { transform: translateY(1px); box-shadow: 0 2px 12px rgba(201,168,76,0.3); }
257
+
258
+ /* ── Spinner ── */
259
+ .spinner {
260
+ width: 16px; height: 16px;
261
+ border: 2px solid rgba(0,0,0,0.2);
262
+ border-top-color: #0a0e1a;
263
+ border-radius: 50%;
264
+ display: none;
265
+ animation: spin 0.7s linear infinite;
266
+ }
267
+
268
+ @keyframes spin { to { transform: rotate(360deg); } }
269
+
270
+ /* ── Platform Pills ── */
271
+ .platforms {
272
+ display: flex;
273
+ gap: 8px;
274
+ justify-content: center;
275
+ margin-bottom: 1.6rem;
276
+ flex-wrap: wrap;
277
+ }
278
+
279
+ .pill {
280
+ display: inline-flex;
281
+ align-items: center;
282
+ gap: 5px;
283
+ font-size: 0.7rem;
284
+ font-weight: 500;
285
+ letter-spacing: 0.05em;
286
+ padding: 4px 11px;
287
+ border-radius: 100px;
288
+ background: rgba(255,255,255,0.04);
289
+ border: 1px solid rgba(255,255,255,0.08);
290
+ color: var(--muted);
291
+ transition: color 0.2s, border-color 0.2s;
292
+ }
293
+
294
+ .pill i { font-size: 0.65rem; }
295
+
296
+ .pill:hover {
297
+ color: var(--gold-light);
298
+ border-color: var(--border);
299
+ }
300
+
301
+ /* ── Error ── */
302
+ .error-box {
303
+ margin-top: 1.2rem;
304
+ background: rgba(180, 50, 50, 0.12);
305
+ border: 1px solid rgba(220, 60, 60, 0.25);
306
+ border-radius: 10px;
307
+ padding: 12px 16px;
308
+ font-size: 0.82rem;
309
+ color: #f87171;
310
+ display: flex;
311
+ align-items: flex-start;
312
+ gap: 10px;
313
+ animation: fadeUp 0.3s ease both;
314
+ }
315
+
316
+ .error-box i { margin-top: 2px; flex-shrink: 0; }
317
+
318
+ /* ── Footer note ── */
319
+ .footer-note {
320
+ margin-top: 1.6rem;
321
+ text-align: center;
322
+ font-size: 0.72rem;
323
+ color: var(--muted);
324
+ letter-spacing: 0.02em;
325
+ opacity: 0.7;
326
+ }
327
+
328
+ .footer-note span { color: var(--gold); opacity: 0.7; }
329
+
330
+ /* ── Section divider ── */
331
+ .divider {
332
+ display: flex;
333
+ align-items: center;
334
+ gap: 10px;
335
+ margin-bottom: 1.4rem;
336
+ opacity: 0.35;
337
+ }
338
+ .divider-line { flex: 1; height: 1px; background: var(--border); }
339
+ .divider-dot { width: 4px; height: 4px; background: var(--gold); border-radius: 50%; }
340
+
341
+ /* ── Animations ── */
342
+ @keyframes fadeDown {
343
+ from { opacity: 0; transform: translateY(-18px); }
344
+ to { opacity: 1; transform: translateY(0); }
345
+ }
346
+ @keyframes fadeUp {
347
+ from { opacity: 0; transform: translateY(16px); }
348
+ to { opacity: 1; transform: translateY(0); }
349
+ }
350
+
351
+ /* ── Quality badge ── */
352
+ .quality-row {
353
+ display: flex;
354
+ gap: 8px;
355
+ margin-bottom: 1.3rem;
356
+ }
357
+
358
+ .q-tag {
359
+ flex: 1;
360
+ text-align: center;
361
+ padding: 7px 6px;
362
+ background: rgba(255,255,255,0.03);
363
+ border: 1px solid rgba(255,255,255,0.07);
364
+ border-radius: 8px;
365
+ font-size: 0.68rem;
366
+ font-weight: 500;
367
+ letter-spacing: 0.06em;
368
+ color: var(--muted);
369
+ text-transform: uppercase;
370
+ }
371
+ .q-tag strong {
372
+ display: block;
373
+ font-size: 0.78rem;
374
+ color: var(--gold-light);
375
+ margin-bottom: 2px;
376
+ font-weight: 700;
377
+ }
378
  </style>
379
  </head>
380
 
381
+ <body>
382
+ <!-- Animated background -->
383
+ <div class="bg-scene">
384
+ <div class="orb orb1"></div>
385
+ <div class="orb orb2"></div>
386
+ <div class="orb orb3"></div>
387
+ </div>
388
+ <div class="bg-grid"></div>
389
+
390
+ <div class="page-wrap">
391
+
392
+ <!-- Brand -->
393
+ <div class="brand">
394
+ <div class="brand-badge">&#x2605; Premium Downloader</div>
395
+ <div class="brand-title">UniLoader</div>
396
+ <div class="brand-sub">Crafted for quality &nbsp;&bull;&nbsp; HF Edition</div>
397
+ </div>
398
+
399
+ <!-- Card -->
400
+ <div class="card">
401
+
402
+ <!-- Platform pills -->
403
+ <div class="platforms">
404
+ <span class="pill"><i class="fab fa-youtube"></i> YouTube</span>
405
+ <span class="pill"><i class="fab fa-tiktok"></i> TikTok</span>
406
+ <span class="pill"><i class="fab fa-instagram"></i> Instagram</span>
407
+ <span class="pill"><i class="fas fa-video"></i> 1000+ Sites</span>
408
+ </div>
409
+
410
+ <!-- Quality tags -->
411
+ <div class="quality-row">
412
+ <div class="q-tag"><strong>720p</strong>Max Quality</div>
413
+ <div class="q-tag"><strong>MP4</strong>Format</div>
414
+ <div class="q-tag"><strong>Fast</strong>Download</div>
415
+ </div>
416
+
417
+ <div class="divider">
418
+ <div class="divider-line"></div>
419
+ <div class="divider-dot"></div>
420
+ <div class="divider-line"></div>
421
+ </div>
422
+
423
+ <!-- Form -->
424
+ <form method="POST" action="/download"
425
+ onsubmit="handleSubmit()">
426
+
427
+ <div class="input-wrap">
428
+ <input
429
+ type="url"
430
+ name="url"
431
+ required
432
+ class="url-input"
433
+ placeholder="Paste your video link here…"
434
+ autocomplete="off"
435
+ >
436
+ <i class="fas fa-link input-icon"></i>
437
+ </div>
438
+
439
+ <button type="submit" class="dl-btn" id="dlBtn">
440
+ <i class="fas fa-download" id="btnIcon"></i>
441
+ <span id="btnText">Download Best Quality</span>
442
+ <div class="spinner" id="spinner"></div>
443
+ </button>
444
+ </form>
445
+
446
+ {% if error %}
447
+ <div class="error-box">
448
+ <i class="fas fa-circle-exclamation"></i>
449
+ <span>{{ error }}</span>
450
+ </div>
451
+ {% endif %}
452
+
453
+ </div>
454
+
455
+ <p class="footer-note">
456
+ TikTok HD on Hugging Face may be limited by platform.
457
+ &nbsp;|&nbsp; <span>Use responsibly.</span>
458
+ </p>
459
+
460
+ </div>
461
+
462
+ <script>
463
+ function handleSubmit() {
464
+ const btn = document.getElementById('dlBtn');
465
+ const icon = document.getElementById('btnIcon');
466
+ const text = document.getElementById('btnText');
467
+ const spin = document.getElementById('spinner');
468
+
469
+ btn.disabled = true;
470
+ btn.style.opacity = '0.75';
471
+ btn.style.cursor = 'wait';
472
+ icon.style.display = 'none';
473
+ text.textContent = 'Preparing download…';
474
+ spin.style.display = 'block';
475
+ }
476
+ </script>
477
  </body>
478
  </html>
479
  """