Offex commited on
Commit
5750f08
·
verified ·
1 Parent(s): 385705c

Update app.py

Browse files
Files changed (1) hide show
  1. app.py +87 -81
app.py CHANGED
@@ -5,107 +5,113 @@ import uuid
5
 
6
  app = Flask(__name__)
7
 
8
- # --- UI CODE ---
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>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 { font-family: sans-serif; background-color: #0f172a; color: white; }
20
- .glass { background: rgba(30, 41, 59, 0.8); backdrop-filter: blur(12px); border: 1px solid rgba(255,255,255,0.1); border-radius: 16px; }
21
- .loader { border: 3px solid #f3f3f3; border-top: 3px solid #3498db; border-radius: 50%; width: 20px; height: 20px; animation: spin 1s linear infinite; display: none; }
22
- @keyframes spin { 0% { transform: rotate(0deg); } 100% { transform: rotate(360deg); } }
23
- </style>
 
 
 
24
  </head>
 
25
  <body class="flex items-center justify-center min-h-screen p-4">
26
- <div class="glass w-full max-w-md p-6 shadow-2xl">
27
- <h1 class="text-3xl font-bold text-center mb-6 text-blue-400">UniLoader <span class="text-xs text-gray-400">v2.0</span></h1>
28
-
29
- <form method="POST" action="/fetch" onsubmit="document.getElementById('spinner').style.display='inline-block'" class="space-y-4">
30
- <input type="text" name="url" class="w-full bg-gray-900 border border-gray-700 rounded-lg p-3 focus:outline-none focus:border-blue-500" placeholder="Paste Link (YouTube/TikTok)..." required>
31
- <button type="submit" class="w-full bg-blue-600 hover:bg-blue-700 p-3 rounded-lg font-bold flex justify-center items-center gap-2">
32
- <span>Search</span> <div class="loader" id="spinner"></div>
33
- </button>
34
- </form>
35
-
36
- {% if formats %}
37
- <div class="mt-6 space-y-2">
38
- <p class="text-xs text-gray-400 text-center uppercase">Select Quality</p>
39
- {% for f in formats %}
40
- <form method="POST" action="/download">
41
- <input type="hidden" name="url" value="{{ url }}">
42
- <input type="hidden" name="format_id" value="{{ f.id }}">
43
- <button type="submit" class="w-full bg-gray-800 hover:bg-gray-700 p-3 rounded-lg flex justify-between items-center border border-gray-700">
44
- <span class="font-bold">{{ f.label }}</span>
45
- <span class="text-xs text-gray-400">{{ f.ext }}</span>
46
- </button>
47
- </form>
48
- {% endfor %}
49
- </div>
50
- {% endif %}
51
-
52
- {% if error %}
53
- <div class="mt-4 p-3 bg-red-900/50 text-red-200 text-sm rounded border border-red-500 text-center">{{ error }}</div>
54
- {% endif %}
55
- </div>
56
  </body>
57
  </html>
58
  """
59
 
 
60
  @app.route("/", methods=["GET"])
61
  def index():
62
  return render_template_string(HTML_CODE)
63
 
64
- @app.route("/fetch", methods=["POST"])
65
- def fetch():
66
  url = request.form.get("url")
 
 
67
  try:
68
- # Latest yt-dlp needs minimal config
69
- opts = {
70
- 'quiet': True,
71
- 'no_warnings': True,
72
- 'nocheckcertificate': True,
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
73
  }
74
- with yt_dlp.YoutubeDL(opts) as ydl:
75
- info = ydl.extract_info(url, download=False)
76
- formats = []
77
- seen = set()
78
- for f in info.get('formats', []):
79
- if f.get('vcodec') != 'none':
80
- h = f.get('height', 0)
81
- if h:
82
- label = f"{h}p"
83
- if h >= 1080: label += " HD"
84
- if label not in seen:
85
- formats.append({'id': f['format_id'], 'label': label, 'ext': f['ext']})
86
- seen.add(label)
87
- formats.sort(key=lambda x: int(x['label'].split('p')[0]), reverse=True)
88
- return render_template_string(HTML_CODE, formats=formats, url=url)
89
- except Exception as e:
90
- return render_template_string(HTML_CODE, error=str(e))
91
 
92
- @app.route("/download", methods=["POST"])
93
- def dl():
94
- url = request.form.get("url")
95
- fid = request.form.get("format_id")
96
- name = f"Vid_{uuid.uuid4().hex[:5]}.mp4"
97
- try:
98
- opts = {'format': f'{fid}+bestaudio/best', 'outtmpl': name, 'merge_output_format': 'mp4'}
99
- with yt_dlp.YoutubeDL(opts) as ydl:
100
  ydl.download([url])
 
101
  @after_this_request
102
- def cln(r):
103
- if os.path.exists(name): os.remove(name)
104
- return r
105
- return send_file(name, as_attachment=True)
 
 
 
 
 
 
106
  except Exception as e:
107
- return f"Error: {str(e)}"
 
108
 
 
109
  if __name__ == "__main__":
110
- app.run(host='0.0.0.0', port=7860)
111
-
 
5
 
6
  app = Flask(__name__)
7
 
8
+ # ---------------- HTML 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>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
  """
62
 
63
+ # ---------------- ROUTES ----------------
64
  @app.route("/", methods=["GET"])
65
  def index():
66
  return render_template_string(HTML_CODE)
67
 
68
+ @app.route("/download", methods=["POST"])
69
+ def download():
70
  url = request.form.get("url")
71
+ filename = f"video_{uuid.uuid4().hex[:6]}.mp4"
72
+
73
  try:
74
+ ydl_opts = {
75
+ # 🔥 BEST POSSIBLE FORMAT (HF SAFE)
76
+ "format": (
77
+ "bv*[ext=mp4][height<=720]/"
78
+ "bv*[height<=720]/"
79
+ "best[height<=720]/best"
80
+ ),
81
+
82
+ "outtmpl": filename,
83
+ "merge_output_format": "mp4",
84
+
85
+ # 🔥 Browser-like headers (slight quality improvement)
86
+ "http_headers": {
87
+ "User-Agent":
88
+ "Mozilla/5.0 (Windows NT 10.0; Win64; x64)",
89
+ "Accept-Language": "en-US,en;q=0.9",
90
+ },
91
+
92
+ "quiet": True,
93
+ "no_warnings": True,
94
+ "nocheckcertificate": True,
95
  }
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
96
 
97
+ with yt_dlp.YoutubeDL(ydl_opts) as ydl:
 
 
 
 
 
 
 
98
  ydl.download([url])
99
+
100
  @after_this_request
101
+ def cleanup(resp):
102
+ try:
103
+ if os.path.exists(filename):
104
+ os.remove(filename)
105
+ except:
106
+ pass
107
+ return resp
108
+
109
+ return send_file(filename, as_attachment=True)
110
+
111
  except Exception as e:
112
+ return render_template_string(HTML_CODE, error=str(e))
113
+
114
 
115
+ # ---------------- RUN ----------------
116
  if __name__ == "__main__":
117
+ app.run(host="0.0.0.0", port=7860)