Offex commited on
Commit
5bd89e6
·
verified ·
1 Parent(s): f348d61

Update app.py

Browse files
Files changed (1) hide show
  1. app.py +135 -26
app.py CHANGED
@@ -5,50 +5,159 @@ import uuid
5
 
6
  app = Flask(__name__)
7
 
 
8
  HTML_CODE = """
9
  <!DOCTYPE html>
10
  <html lang="en">
11
  <head>
12
  <meta charset="UTF-8">
13
  <meta name="viewport" content="width=device-width, initial-scale=1.0">
14
- <title>TikTok Downloader Cloud</title>
15
  <script src="https://cdn.tailwindcss.com"></script>
 
16
  <style>
17
- body { background: #0b0f19; color: white; min-height: 100vh; display: flex; align-items: center; justify-content: center; font-family: sans-serif; }
18
- .glass-card { background: rgba(17, 24, 39, 0.9); border: 1px solid rgba(255,255,255,0.1); border-radius: 20px; padding: 30px; }
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
19
  </style>
20
  </head>
21
- <body class="p-4">
22
- <div class="glass-card w-full max-w-md shadow-2xl">
23
- <h1 class="text-3xl font-bold text-center mb-2 text-blue-500">CLOUD DOWNLOADER</h1>
24
- <p class="text-gray-400 text-center text-sm mb-6">No VPN Needed • High Speed</p>
25
-
26
- <form method="POST" action="/fetch" class="space-y-4">
27
- <input type="text" name="url" class="w-full bg-gray-900 border border-gray-700 rounded-lg p-3 text-white focus:outline-none focus:border-blue-500" placeholder="Paste TikTok Link..." required>
28
- <button type="submit" class="w-full bg-blue-600 hover:bg-blue-700 p-3 rounded-lg font-bold transition">Check Quality</button>
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
29
  </form>
30
 
31
  {% if formats %}
32
- <div class="mt-6 space-y-3">
33
- <h3 class="text-sm font-semibold text-gray-400">Available Qualities:</h3>
 
 
 
 
 
34
  {% for f in formats %}
35
- <form method="POST" action="/download" class="flex items-center justify-between bg-gray-800 p-3 rounded-lg border border-gray-700">
36
- <input type="hidden" name="url" value="{{ url }}">
37
- <input type="hidden" name="format_id" value="{{ f.id }}">
38
- <div>
39
- <div class="font-bold text-white">{{ f.label }}</div>
40
- <div class="text-xs text-gray-400">{{ f.size }}</div>
41
- </div>
42
- <button type="submit" class="bg-emerald-600 text-xs px-3 py-2 rounded font-bold">GET</button>
43
- </form>
 
 
 
 
 
 
 
 
 
 
 
 
44
  {% endfor %}
45
  </div>
46
  {% endif %}
47
-
48
  {% if error %}
49
- <div class="mt-4 p-3 bg-red-900/50 text-red-200 text-xs rounded text-center">{{ error }}</div>
 
 
 
50
  {% endif %}
 
51
  </div>
 
 
 
 
 
 
 
 
 
 
 
 
52
  </body>
53
  </html>
54
  """
@@ -61,6 +170,7 @@ def index():
61
  def fetch():
62
  url = request.form.get("url")
63
  try:
 
64
  opts = {'quiet': True, 'nocheckcertificate': True, 'user_agent': 'Mozilla/5.0'}
65
  with yt_dlp.YoutubeDL(opts) as ydl:
66
  info = ydl.extract_info(url, download=False)
@@ -88,7 +198,7 @@ def fetch():
88
  def dl():
89
  url = request.form.get("url")
90
  fid = request.form.get("format_id")
91
- name = f"vid_{uuid.uuid4().hex[:5]}.mp4"
92
  try:
93
  opts = {'format': f'{fid}+bestaudio/best', 'outtmpl': name, 'merge_output_format': 'mp4'}
94
  with yt_dlp.YoutubeDL(opts) as ydl:
@@ -104,4 +214,3 @@ def dl():
104
 
105
  if __name__ == "__main__":
106
  app.run(host='0.0.0.0', port=7860)
107
-
 
5
 
6
  app = Flask(__name__)
7
 
8
+ # --- PROFESSIONAL ANIMATED UI ---
9
  HTML_CODE = """
10
  <!DOCTYPE html>
11
  <html lang="en">
12
  <head>
13
  <meta charset="UTF-8">
14
  <meta name="viewport" content="width=device-width, initial-scale=1.0">
15
+ <title>Neon Downloader Pro</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
+ @import url('https://fonts.googleapis.com/css2?family=Outfit:wght@300;500;700&display=swap');
20
+
21
+ body { font-family: 'Outfit', sans-serif; background-color: #000; overflow-x: hidden; }
22
+
23
+ /* Animated Background */
24
+ .bg-animate {
25
+ position: fixed; top: 0; left: 0; width: 100%; height: 100%; z-index: -1;
26
+ background: linear-gradient(-45deg, #ee7752, #e73c7e, #23a6d5, #23d5ab);
27
+ background-size: 400% 400%;
28
+ animation: gradientBG 15s ease infinite;
29
+ opacity: 0.2;
30
+ }
31
+ @keyframes gradientBG {
32
+ 0% { background-position: 0% 50%; }
33
+ 50% { background-position: 100% 50%; }
34
+ 100% { background-position: 0% 50%; }
35
+ }
36
+
37
+ /* Glass Card */
38
+ .glass {
39
+ background: rgba(20, 20, 20, 0.7);
40
+ backdrop-filter: blur(16px);
41
+ -webkit-backdrop-filter: blur(16px);
42
+ border: 1px solid rgba(255, 255, 255, 0.1);
43
+ box-shadow: 0 8px 32px 0 rgba(0, 0, 0, 0.37);
44
+ }
45
+
46
+ /* Input Glow */
47
+ .input-glow:focus {
48
+ box-shadow: 0 0 20px rgba(0, 242, 234, 0.3);
49
+ border-color: #00f2ea;
50
+ }
51
+
52
+ /* Button Animation */
53
+ .btn-grad {
54
+ background-image: linear-gradient(to right, #FF512F 0%, #DD2476 51%, #FF512F 100%);
55
+ transition: 0.5s;
56
+ background-size: 200% auto;
57
+ }
58
+ .btn-grad:hover { background-position: right center; transform: scale(1.02); }
59
+
60
+ /* Loading Spinner */
61
+ .loader {
62
+ border: 3px solid rgba(255,255,255,0.3);
63
+ border-radius: 50%;
64
+ border-top: 3px solid #fff;
65
+ width: 20px; height: 20px;
66
+ animation: spin 1s linear infinite;
67
+ display: none;
68
+ }
69
+ @keyframes spin { 0% { transform: rotate(0deg); } 100% { transform: rotate(360deg); } }
70
+
71
+ /* List Item Animation */
72
+ .fade-in-up { animation: fadeInUp 0.5s ease-out forwards; opacity: 0; transform: translateY(20px); }
73
+ @keyframes fadeInUp { to { opacity: 1; transform: translateY(0); } }
74
  </style>
75
  </head>
76
+ <body class="text-white flex flex-col items-center justify-center min-h-screen p-4">
77
+
78
+ <div class="bg-animate"></div>
79
+
80
+ <div class="glass w-full max-w-lg rounded-3xl p-8 relative overflow-hidden">
81
+
82
+ <div class="absolute -top-10 -right-10 w-32 h-32 bg-blue-500 rounded-full blur-[80px] opacity-40"></div>
83
+ <div class="absolute -bottom-10 -left-10 w-32 h-32 bg-pink-500 rounded-full blur-[80px] opacity-40"></div>
84
+
85
+ <div class="text-center mb-8 relative z-10">
86
+ <h1 class="text-4xl font-bold mb-1 tracking-tight">
87
+ <span class="text-transparent bg-clip-text bg-gradient-to-r from-cyan-400 to-blue-500">Video</span>
88
+ <span class="text-white">Hunter</span>
89
+ </h1>
90
+ <p class="text-gray-400 text-sm">Ultra HD • No Watermark • Fast</p>
91
+ </div>
92
+
93
+ <form method="POST" action="/fetch" onsubmit="showLoader()" class="space-y-5 relative z-10">
94
+ <div class="relative">
95
+ <i class="fa-solid fa-link absolute left-4 top-4 text-gray-400"></i>
96
+ <input type="text" name="url"
97
+ class="input-glow w-full bg-black/40 border border-gray-700 rounded-xl py-3.5 pl-12 pr-4 text-white placeholder-gray-500 focus:outline-none transition-all duration-300"
98
+ placeholder="Paste TikTok/Reel Link here..." required>
99
+ </div>
100
+
101
+ <button type="submit" id="searchBtn" class="btn-grad w-full py-4 rounded-xl font-bold text-lg shadow-lg flex justify-center items-center gap-2">
102
+ <span>ANALYZE VIDEO</span>
103
+ <div class="loader" id="spinner"></div>
104
+ </button>
105
  </form>
106
 
107
  {% if formats %}
108
+ <div class="mt-8 space-y-3 relative z-10">
109
+ <div class="flex items-center gap-2 mb-4">
110
+ <div class="h-px bg-gray-700 flex-1"></div>
111
+ <span class="text-xs text-gray-400 uppercase tracking-widest">Select Quality</span>
112
+ <div class="h-px bg-gray-700 flex-1"></div>
113
+ </div>
114
+
115
  {% for f in formats %}
116
+ <div class="fade-in-up" style="animation-delay: {{ loop.index0 * 100 }}ms">
117
+ <form method="POST" action="/download" onsubmit="showDownloadLoader(this)">
118
+ <input type="hidden" name="url" value="{{ url }}">
119
+ <input type="hidden" name="format_id" value="{{ f.id }}">
120
+
121
+ <button type="submit" class="group w-full bg-gray-800/50 hover:bg-gray-800 border border-gray-700/50 hover:border-blue-500/50 p-4 rounded-xl transition-all duration-300 flex justify-between items-center">
122
+ <div class="text-left">
123
+ <div class="flex items-center gap-2">
124
+ <span class="font-bold text-white group-hover:text-blue-400 transition-colors">{{ f.label }}</span>
125
+ {% if 'HD' in f.label or '1080' in f.label %}
126
+ <span class="bg-blue-500/20 text-blue-300 text-[10px] px-2 py-0.5 rounded font-bold">HQ</span>
127
+ {% endif %}
128
+ </div>
129
+ <div class="text-xs text-gray-500 mt-1">{{ f.size }} • MP4</div>
130
+ </div>
131
+ <div class="w-10 h-10 rounded-full bg-gray-700 group-hover:bg-blue-600 flex items-center justify-center transition-all">
132
+ <i class="fa-solid fa-download text-sm text-gray-300 group-hover:text-white"></i>
133
+ </div>
134
+ </button>
135
+ </form>
136
+ </div>
137
  {% endfor %}
138
  </div>
139
  {% endif %}
140
+
141
  {% if error %}
142
+ <div class="mt-6 p-4 bg-red-500/10 border border-red-500/50 rounded-xl flex items-start gap-3 fade-in-up">
143
+ <i class="fa-solid fa-circle-exclamation text-red-500 mt-1"></i>
144
+ <div class="text-red-200 text-sm">{{ error }}</div>
145
+ </div>
146
  {% endif %}
147
+
148
  </div>
149
+
150
+ <script>
151
+ function showLoader() {
152
+ document.getElementById('searchBtn').style.opacity = '0.8';
153
+ document.getElementById('searchBtn').innerHTML = 'Processing... <div class="loader" style="display:inline-block"></div>';
154
+ }
155
+ function showDownloadLoader(form) {
156
+ const btn = form.querySelector('button');
157
+ const icon = btn.querySelector('i');
158
+ icon.className = 'fa-solid fa-circle-notch fa-spin';
159
+ }
160
+ </script>
161
  </body>
162
  </html>
163
  """
 
170
  def fetch():
171
  url = request.form.get("url")
172
  try:
173
+ # Optimized for Cloud
174
  opts = {'quiet': True, 'nocheckcertificate': True, 'user_agent': 'Mozilla/5.0'}
175
  with yt_dlp.YoutubeDL(opts) as ydl:
176
  info = ydl.extract_info(url, download=False)
 
198
  def dl():
199
  url = request.form.get("url")
200
  fid = request.form.get("format_id")
201
+ name = f"VidHunter_{uuid.uuid4().hex[:5]}.mp4"
202
  try:
203
  opts = {'format': f'{fid}+bestaudio/best', 'outtmpl': name, 'merge_output_format': 'mp4'}
204
  with yt_dlp.YoutubeDL(opts) as ydl:
 
214
 
215
  if __name__ == "__main__":
216
  app.run(host='0.0.0.0', port=7860)