coollsd commited on
Commit
21b7ff5
1 Parent(s): ebde77a

Update app.py

Browse files
Files changed (1) hide show
  1. app.py +483 -277
app.py CHANGED
@@ -1,6 +1,7 @@
1
  from fastapi import FastAPI, File, UploadFile, Request
2
  from fastapi.responses import HTMLResponse, JSONResponse, StreamingResponse
3
  import requests
 
4
  import asyncio
5
  from typing import Dict
6
 
@@ -11,245 +12,328 @@ HTML_CONTENT = """
11
  <html lang="en">
12
  <head>
13
  <meta charset="UTF-8">
14
- <title>Radd PRO Uploader</title>
15
  <meta name="viewport" content="width=device-width, initial-scale=1.0">
16
- <!-- Google Fonts and Icons -->
17
- <link href="https://fonts.googleapis.com/css2?family=Roboto:wght@400;500;700&display=swap" rel="stylesheet">
18
- <!-- Material Icons -->
19
- <link href="https://fonts.googleapis.com/icon?family=Material+Icons" rel="stylesheet">
20
  <style>
21
- /* Reset and base styles */
22
- * {
23
- margin: 0;
24
- padding: 0;
25
- box-sizing: border-box;
26
- }
27
-
28
  body {
29
- font-family: 'Roboto', sans-serif;
30
- background: linear-gradient(135deg, #667eea, #764ba2);
31
- color: #fff;
 
32
  min-height: 100vh;
33
  display: flex;
34
- align-items: center;
35
  justify-content: center;
36
- overflow: hidden;
 
 
37
  }
38
 
39
- h1 {
40
- font-size: 2rem;
41
- margin-bottom: 1rem;
42
- text-align: center;
43
- animation: fadeInDown 1s ease forwards;
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
44
  }
45
 
46
  .container {
47
- background: rgba(255, 255, 255, 0.1);
 
 
 
48
  padding: 2rem;
49
- border-radius: 16px;
50
  backdrop-filter: blur(10px);
51
- max-width: 500px;
52
- width: 90%;
53
  text-align: center;
54
- animation: fadeInUp 1s ease forwards;
55
  }
56
 
57
- .drop-zone {
58
- border: 2px dashed rgba(255, 255, 255, 0.5);
59
- border-radius: 12px;
60
- padding: 2rem;
61
- cursor: pointer;
62
- transition: background 0.3s, border-color 0.3s;
 
 
 
63
  position: relative;
 
 
 
 
 
 
 
 
 
64
  overflow: hidden;
 
 
65
  }
66
 
67
- .drop-zone.hover {
68
- background: rgba(255, 255, 255, 0.1);
69
- border-color: #fff;
70
  }
71
 
72
- .drop-zone::before {
73
- content: "";
74
  position: absolute;
75
- top: -50%;
76
- left: -50%;
77
- width: 200%;
78
- height: 200%;
79
- background: radial-gradient(circle at center, rgba(255, 255, 255, 0.2), transparent 70%);
80
- opacity: 0;
81
  pointer-events: none;
82
- transition: opacity 0.5s;
83
  }
84
 
85
- .drop-zone.hover::before {
86
- opacity: 1;
87
- animation: pulsate 1.5s infinite;
 
88
  }
89
 
90
- .drop-zone i {
91
- font-size: 4rem;
92
- color: rgba(255, 255, 255, 0.7);
93
  }
94
 
95
- .drop-zone p {
96
- margin-top: 1rem;
97
- font-size: 1rem;
98
- color: rgba(255, 255, 255, 0.8);
 
 
 
 
 
 
 
 
 
 
99
  }
100
 
101
- .file-input {
102
- display: none;
 
103
  }
104
 
105
- .btn {
106
- margin-top: 1.5rem;
107
- padding: 1rem 2rem;
108
- background: #6a11cb;
109
- background: linear-gradient(to right, #2575fc, #6a11cb);
110
- border: none;
111
- border-radius: 50px;
112
- color: #fff;
113
- font-size: 1rem;
114
- font-weight: 500;
115
- cursor: pointer;
116
- box-shadow: 0 4px 15px rgba(0, 0, 0, 0.2);
117
- transition: transform 0.2s ease, box-shadow 0.2s ease;
 
 
 
118
  position: relative;
 
 
 
 
 
 
 
119
  overflow: hidden;
120
  }
121
 
122
- .btn::before {
123
- content: "";
 
 
 
 
 
 
124
  position: absolute;
125
- top: 0;
126
- left: -100%;
127
- width: 100%;
128
- height: 100%;
129
- background: linear-gradient(to right, rgba(255,255,255,0.2), rgba(255,255,255,0.1), rgba(255,255,255,0));
130
- transform: skewX(-45deg);
131
- transition: left 0.5s;
132
  }
133
 
134
- .btn:hover::before {
135
- left: 100%;
 
 
136
  }
137
 
138
- .btn:hover {
139
- transform: scale(1.02);
140
- box-shadow: 0 6px 20px rgba(0, 0, 0, 0.3);
 
 
 
 
 
 
141
  }
142
 
143
  .progress-container {
144
- margin-top: 1.5rem;
145
  display: none;
 
146
  }
147
 
148
  .progress-bar {
149
  width: 100%;
150
  height: 10px;
151
- background: rgba(255, 255, 255, 0.2);
152
- border-radius: 50px;
153
  overflow: hidden;
 
154
  }
155
 
156
  .progress {
157
  width: 0%;
158
  height: 100%;
159
- background: linear-gradient(to right, #36d1dc, #5b86e5);
160
- border-radius: 50px;
161
  transition: width 0.3s ease;
162
  }
163
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
164
  .result-container {
165
- margin-top: 1.5rem;
166
  display: none;
167
- animation: fadeIn 1s ease forwards;
168
  }
169
 
170
  .result-link {
171
- color: #fff;
172
  text-decoration: none;
173
- word-wrap: break-word;
174
- font-weight: 500;
175
- transition: color 0.3s;
 
176
  }
177
 
178
  .result-link:hover {
179
- color: #c7c7c7;
180
- }
181
-
182
- .loading-spinner {
183
- margin-top: 1.5rem;
184
- display: none;
185
  }
186
 
187
- .loading-spinner::after {
188
- content: '';
189
- width: 40px;
190
- height: 40px;
191
- border: 6px solid rgba(255, 255, 255, 0.2);
192
- border-top-color: #fff;
193
- border-radius: 50%;
194
- animation: spin 1s linear infinite;
195
- display: inline-block;
196
  }
197
 
 
198
  .file-types {
199
  margin-top: 2rem;
200
- font-size: 0.9rem;
201
- color: rgba(255, 255, 255, 0.7);
202
- animation: fadeIn 1s ease forwards;
203
- animation-delay: 0.5s;
204
  }
205
 
206
- @keyframes fadeInDown {
207
- from {
208
- opacity: 0;
209
- transform: translateY(-20px);
210
- }
211
- to {
212
- opacity: 1;
213
- transform: translateY(0);
214
- }
 
215
  }
216
 
217
- @keyframes fadeInUp {
218
- from {
219
- opacity: 0;
220
- transform: translateY(20px);
221
- }
222
- to {
223
- opacity: 1;
224
- transform: translateY(0);
225
- }
 
 
226
  }
227
 
228
- @keyframes fadeIn {
229
- from {
230
- opacity: 0;
231
- }
232
- to {
233
- opacity: 1;
234
- }
235
  }
236
 
237
- @keyframes spin {
238
- to {
239
- transform: rotate(360deg);
240
- }
 
 
 
 
241
  }
242
 
243
- @keyframes pulsate {
244
- 0% {
245
- opacity: 0.2;
246
- }
247
- 50% {
248
- opacity: 0.4;
249
- }
250
- 100% {
251
- opacity: 0.2;
252
- }
 
 
 
 
 
 
 
 
 
 
 
 
 
253
  }
254
 
255
  @media (max-width: 480px) {
@@ -260,6 +344,20 @@ HTML_CONTENT = """
260
  h1 {
261
  font-size: 1.5rem;
262
  }
 
 
 
 
 
 
 
 
 
 
 
 
 
 
263
  }
264
  </style>
265
  </head>
@@ -268,16 +366,13 @@ HTML_CONTENT = """
268
  <h1>Radd PRO Uploader</h1>
269
  <form id="uploadForm">
270
  <div id="dropZone" class="drop-zone">
271
- <i class="material-icons">cloud_upload</i>
272
- <p>Drag & Drop or Click to Upload</p>
273
  <input type="file" name="file" id="file" class="file-input" accept=".zip,.mp4,.txt,.mp3,image/*,.pdf" required>
 
 
274
  </div>
275
- <button type="submit" id="uploadBtn" class="btn" style="display: none;">Upload File</button>
276
- <div class="progress-container" id="progressContainer">
277
- <div class="progress-bar">
278
- <div class="progress" id="progress"></div>
279
- </div>
280
- </div>
281
  <div class="loading-spinner" id="loadingSpinner"></div>
282
  </form>
283
  <div class="result-container" id="resultContainer"></div>
@@ -286,116 +381,228 @@ HTML_CONTENT = """
286
  </div>
287
  </div>
288
 
 
 
 
 
 
 
 
 
 
 
 
 
289
  <script>
290
  const fileInput = document.getElementById('file');
 
291
  const uploadForm = document.getElementById('uploadForm');
292
  const progressContainer = document.getElementById('progressContainer');
293
- const progressBar = document.getElementById('progress');
294
  const loadingSpinner = document.getElementById('loadingSpinner');
295
  const resultContainer = document.getElementById('resultContainer');
296
  const dropZone = document.getElementById('dropZone');
 
 
 
297
  const uploadBtn = document.getElementById('uploadBtn');
298
 
299
- dropZone.addEventListener('click', () => {
300
- fileInput.click();
 
 
 
 
 
301
  });
302
 
303
- ['dragenter', 'dragover'].forEach(eventName => {
304
- dropZone.addEventListener(eventName, (e) => {
305
- e.preventDefault();
306
- e.stopPropagation();
307
- dropZone.classList.add('hover');
308
- });
309
  });
310
 
311
- ['dragleave', 'drop'].forEach(eventName => {
312
- dropZone.addEventListener(eventName, (e) => {
313
- e.preventDefault();
314
- e.stopPropagation();
315
- dropZone.classList.remove('hover');
316
- });
317
  });
318
 
319
  dropZone.addEventListener('drop', (e) => {
320
  e.preventDefault();
321
- fileInput.files = e.dataTransfer.files;
322
- handleFileSelect();
323
  });
324
 
325
- fileInput.addEventListener('change', handleFileSelect);
 
 
 
 
 
 
 
 
 
326
 
327
- function handleFileSelect() {
328
- if (fileInput.files && fileInput.files.length > 0) {
329
- uploadBtn.style.display = 'block';
330
- const dataTransfer = new DataTransfer();
331
- dataTransfer.items.add(fileInput.files[0]);
332
- fileInput.files = dataTransfer.files;
333
- } else {
334
- uploadBtn.style.display = 'none';
335
  }
336
  }
337
 
338
- uploadForm.addEventListener('submit', (e) => {
339
- e.preventDefault();
340
- if (fileInput.files.length > 0) {
341
- uploadFile(fileInput.files[0]);
 
 
 
 
 
342
  }
343
- });
344
 
345
  async function uploadFile(file) {
 
346
  progressContainer.style.display = 'block';
347
- loadingSpinner.style.display = 'inline-block';
348
  uploadBtn.disabled = true;
 
349
  resultContainer.style.display = 'none';
350
- progressBar.style.width = '0%';
 
 
351
 
352
  const formData = new FormData();
353
  formData.append('file', file);
354
 
355
- const xhr = new XMLHttpRequest();
356
- xhr.open('POST', '/upload', true);
357
-
358
- xhr.upload.onprogress = (event) => {
359
- if (event.lengthComputable) {
360
- const percentComplete = ((event.loaded / event.total) * 100).toFixed(2);
361
- progressBar.style.width = percentComplete + '%';
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
362
  }
363
- };
364
-
365
- xhr.onload = function () {
366
- if (xhr.status === 200) {
367
- const response = JSON.parse(xhr.responseText);
368
- displayResult(response.url, file.name);
369
- resetForm();
370
- } else {
371
- alert('An error occurred during the upload. Please try again.');
372
- resetForm();
373
- }
374
- };
375
-
376
- xhr.onerror = function () {
377
- alert('An error occurred during the upload. Please try again.');
378
- resetForm();
379
- };
380
 
381
- xhr.send(formData);
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
382
  }
383
 
384
- function resetForm() {
385
  fileInput.value = '';
 
386
  uploadBtn.style.display = 'none';
387
  uploadBtn.disabled = false;
388
  loadingSpinner.style.display = 'none';
389
- progressContainer.style.display = 'none';
390
  }
391
 
392
- function displayResult(url, fileName) {
393
- resultContainer.innerHTML = `
394
- <p>File uploaded successfully:</p>
395
- <a href="${url}" target="_blank" class="result-link">${fileName}</a>
396
- `;
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
397
  resultContainer.style.display = 'block';
398
  }
 
 
 
 
 
 
 
 
 
 
 
 
399
  </script>
400
  </body>
401
  </html>
@@ -436,21 +643,23 @@ async def handle_video_stream(path: str, request: Request):
436
  headers = {'Range': range_header} if range_header else {}
437
  response = requests.get(original_url, headers=headers, stream=True)
438
 
439
- async def generate():
440
  for chunk in response.iter_content(chunk_size=8192):
441
  yield chunk
442
 
443
- response_headers = {key: value for key, value in response.headers.items()}
444
- response_headers['Access-Control-Allow-Origin'] = '*'
445
- response_headers['Content-Disposition'] = 'inline'
446
 
447
- return StreamingResponse(generate(), status_code=response.status_code, headers=response_headers)
 
 
 
448
 
449
  @app.get("/embed")
450
  async def embed_video(url: str, thumbnail: str):
451
  html = f'''
452
- <!DOCTYPE html>
453
- <html lang="en">
454
  <head>
455
  <meta property="og:type" content="video.other">
456
  <meta property="og:video" content="{url}">
@@ -465,42 +674,24 @@ async def embed_video(url: str, thumbnail: str):
465
  <meta property="og:image:height" content="720">
466
  <meta property="og:image:type" content="image/png">
467
  <style>
468
- body, html {{
469
- margin: 0;
470
- padding: 0;
471
- width: 100%;
472
- height: 100%;
473
- background: #000;
474
- display: flex;
475
- align-items: center;
476
- justify-content: center;
477
- }}
478
-
479
- #video {{
480
- width: 100%;
481
- height: 100%;
482
- }}
483
-
484
- .video-container {{
485
- position: relative;
486
- width: 100%;
487
- max-width: 1280px;
488
- height: auto;
489
- }}
490
-
491
- .video-container video {{
492
- width: 100%;
493
- height: auto;
494
- }}
495
  </style>
496
  </head>
497
  <body>
498
- <div class="video-container">
499
- <video id="video" controls autoplay>
500
- <source src="{url}" type="video/mp4">
501
- Your browser does not support the video tag.
502
- </video>
503
- </div>
 
 
 
 
 
 
504
  </body>
505
  </html>
506
  '''
@@ -509,9 +700,9 @@ async def embed_video(url: str, thumbnail: str):
509
  async def get_cookies() -> Dict[str, str]:
510
  try:
511
  response = requests.get('https://replicate.com/levelsio/neon-tokyo', headers={
512
- 'User-Agent': 'Mozilla/5.0'
513
  })
514
- return response.cookies.get_dict()
515
  except Exception as e:
516
  print(f'Error fetching the page: {e}')
517
  return {}
@@ -521,12 +712,22 @@ async def initiate_upload(cookies: Dict[str, str], filename: str, content_type:
521
  try:
522
  response = requests.post(url, cookies=cookies, headers={
523
  'X-CSRFToken': cookies.get('csrftoken'),
524
- 'User-Agent': 'Mozilla/5.0'
 
 
 
 
 
 
 
 
 
 
525
  })
526
  return response.json()
527
  except Exception as e:
528
  print(f'Error initiating upload: {e}')
529
- return {}
530
 
531
  async def upload_file(upload_url: str, file_content: bytes, content_type: str) -> bool:
532
  try:
@@ -537,11 +738,16 @@ async def upload_file(upload_url: str, file_content: bytes, content_type: str) -
537
  return False
538
 
539
  async def retry_upload(upload_url: str, file_content: bytes, content_type: str, max_retries: int = 5, delay: int = 1) -> bool:
540
- for attempt in range(1, max_retries + 1):
541
- success = await upload_file(upload_url, file_content, content_type)
542
- if success:
543
- return True
544
- else:
545
- print(f"Upload failed on attempt {attempt}, retrying in {delay} seconds...")
546
- await asyncio.sleep(delay)
 
 
 
 
 
547
  return False
 
1
  from fastapi import FastAPI, File, UploadFile, Request
2
  from fastapi.responses import HTMLResponse, JSONResponse, StreamingResponse
3
  import requests
4
+ import time
5
  import asyncio
6
  from typing import Dict
7
 
 
12
  <html lang="en">
13
  <head>
14
  <meta charset="UTF-8">
 
15
  <meta name="viewport" content="width=device-width, initial-scale=1.0">
16
+ <title>Radd PRO Uploader</title>
17
+ <link href="https://fonts.googleapis.com/css2?family=Poppins:wght@300;400;600&display=swap" rel="stylesheet">
 
 
18
  <style>
 
 
 
 
 
 
 
19
  body {
20
+ font-family: 'Poppins', sans-serif;
21
+ background-color: #121212;
22
+ color: #e0e0e0;
23
+ margin: 0;
24
  min-height: 100vh;
25
  display: flex;
 
26
  justify-content: center;
27
+ align-items: center;
28
+ padding: 20px;
29
+ box-sizing: border-box;
30
  }
31
 
32
+ body::before {
33
+ content: "";
34
+ position: fixed;
35
+ top: 0;
36
+ left: 0;
37
+ width: 100%;
38
+ height: 100%;
39
+ background: url('data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAADwAAAA8CAQAAACM/9unAAAACXBIWXMAAAsTAAALEwEAmpwYAAABF0lEQVR4nO3YMRLCQBRE0clsYgxZwwq7oLGxAgp2AtbsqQZsYgEG0wEWc/LSZnb9HcMjR8fHvEKCgoKCgoKCgoKCgoKCgoKCgoKCgoKCgsK8tJOq9fzs7vlkNlWvf5ELi+20t5k2VSL7p/iHJ5Rz5ynOhU7rQ4pUi+6b4hyeUc+cpzoVO60OkV7rQ4pUi+6b4hxenu+en4rQAOkaks/eJegGaUfOHI+nRvQCND1w2J9yf8C2KZwNjkeUsAKRa7Nz50tQAokVbO/U6AaiWjl5wd6kQAOke8Xpx3JgTQKVq7Heh0ADpFvF6cd0kE0Claux3odAA6RfxenHc+BNCpWrsd6HQAOkX8Xpx3PgTQqVq7Heh0ADpF/F6cdz4E0KlarjdI/cR1FBQUGBgYGBgYGBgYG/AT4AIHph6aQGU7oAAAAASUVORK5CYII=') repeat;
40
+ animation: grain 8s steps(10) infinite;
41
+ opacity: 0.2;
42
+ pointer-events: none;
43
+ }
44
+
45
+ @keyframes grain {
46
+ 0% { transform: translate(0, 0); }
47
+ 10% { transform: translate(-5%, -5%); }
48
+ 20% { transform: translate(-10%, 5%); }
49
+ 30% { transform: translate(5%, -10%); }
50
+ 40% { transform: translate(-5%, 15%); }
51
+ 50% { transform: translate(-10%, 5%); }
52
+ 60% { transform: translate(15%, 0); }
53
+ 70% { transform: translate(0, 10%); }
54
+ 80% { transform: translate(-15%, 0); }
55
+ 90% { transform: translate(10%, 5%); }
56
+ 100% { transform: translate(5%, 0); }
57
  }
58
 
59
  .container {
60
+ position: relative;
61
+ width: 100%;
62
+ max-width: 450px;
63
+ margin: 0 auto;
64
  padding: 2rem;
65
+ background: rgba(18, 18, 18, 0.9);
66
  backdrop-filter: blur(10px);
67
+ border-radius: 15px;
68
+ z-index: 1;
69
  text-align: center;
70
+ box-shadow: 0 0 20px rgba(0, 0, 0, 0.8);
71
  }
72
 
73
+ h1 {
74
+ margin-bottom: 1.5rem;
75
+ font-size: 1.8rem;
76
+ color: #ffffff;
77
+ text-shadow: 0 0 5px rgba(255, 255, 255, 0.2);
78
+ }
79
+
80
+ .btn {
81
+ display: inline-block;
82
  position: relative;
83
+ padding: 12px 24px;
84
+ margin: 0.5rem;
85
+ font-size: 1rem;
86
+ font-weight: 600;
87
+ color: #ffffff;
88
+ background-color: #2a2a2a;
89
+ border: none;
90
+ border-radius: 5px;
91
+ cursor: pointer;
92
  overflow: hidden;
93
+ z-index: 1;
94
+ transition: color 0.3s ease, box-shadow 0.3s ease;
95
  }
96
 
97
+ .btn:hover {
98
+ color: #ffffff;
99
+ box-shadow: 0 0 15px rgba(200, 200, 200, 0.5);
100
  }
101
 
102
+ .btn:hover::before {
103
+ content: '';
104
  position: absolute;
105
+ inset: -10px;
106
+ background: radial-gradient(circle at center, rgba(200,200,200,0.2), transparent);
107
+ filter: blur(20px);
108
+ animation: glowAnimation 2s infinite;
109
+ z-index: -1;
 
110
  pointer-events: none;
 
111
  }
112
 
113
+ @keyframes glowAnimation {
114
+ 0% { transform: scale(0.8); }
115
+ 50% { transform: scale(1.2); }
116
+ 100% { transform: scale(0.8); }
117
  }
118
 
119
+ .btn:active {
120
+ transform: scale(0.98);
 
121
  }
122
 
123
+ .small-btn {
124
+ padding: 6px 12px;
125
+ font-size: 0.8rem;
126
+ font-weight: 500;
127
+ background-color: #2a2a2a;
128
+ color: #ffffff;
129
+ border: none;
130
+ border-radius: 5px;
131
+ cursor: pointer;
132
+ transition: color 0.3s ease, box-shadow 0.3s ease;
133
+ position: relative;
134
+ overflow: hidden;
135
+ z-index: 1;
136
+ margin: 0.25rem;
137
  }
138
 
139
+ .small-btn:hover {
140
+ color: #ffffff;
141
+ box-shadow: 0 0 10px rgba(200, 200, 200, 0.5);
142
  }
143
 
144
+ .small-btn:hover::before {
145
+ content: '';
146
+ position: absolute;
147
+ inset: -10px;
148
+ background: radial-gradient(circle at center, rgba(200,200,200,0.2), transparent);
149
+ filter: blur(15px);
150
+ animation: glowAnimation 2s infinite;
151
+ z-index: -1;
152
+ pointer-events: none;
153
+ }
154
+
155
+ .small-btn:active {
156
+ transform: scale(0.98);
157
+ }
158
+
159
+ .drop-zone {
160
  position: relative;
161
+ padding: 20px;
162
+ margin-bottom: 1rem;
163
+ border: 2px dashed #aaa;
164
+ border-radius: 10px;
165
+ cursor: pointer;
166
+ transition: all 0.3s ease;
167
+ background: rgba(255, 255, 255, 0.05);
168
  overflow: hidden;
169
  }
170
 
171
+ .drop-zone:hover, .drop-zone.drag-over {
172
+ border-color: #ffffff;
173
+ background: rgba(255, 255, 255, 0.1);
174
+ position: relative;
175
+ }
176
+
177
+ .drop-zone:hover::before, .drop-zone.drag-over::before {
178
+ content: '';
179
  position: absolute;
180
+ inset: -10px;
181
+ background: radial-gradient(circle at center, rgba(200,200,200,0.2), transparent);
182
+ filter: blur(30px);
183
+ animation: grainGlow 5s infinite;
184
+ z-index: -1;
185
+ pointer-events: none;
 
186
  }
187
 
188
+ @keyframes grainGlow {
189
+ 0% { opacity: 0.2; }
190
+ 50% { opacity: 0.5; }
191
+ 100% { opacity: 0.2; }
192
  }
193
 
194
+ .file-input {
195
+ display: none;
196
+ }
197
+
198
+ .file-name {
199
+ margin-top: 1rem;
200
+ font-size: 0.9rem;
201
+ color: #aaa;
202
+ word-break: break-all;
203
  }
204
 
205
  .progress-container {
 
206
  display: none;
207
+ margin-top: 1.5rem;
208
  }
209
 
210
  .progress-bar {
211
  width: 100%;
212
  height: 10px;
213
+ background-color: #333;
214
+ border-radius: 5px;
215
  overflow: hidden;
216
+ margin-bottom: 10px;
217
  }
218
 
219
  .progress {
220
  width: 0%;
221
  height: 100%;
222
+ background-color: #ffffff;
 
223
  transition: width 0.3s ease;
224
  }
225
 
226
+ .loading-spinner {
227
+ display: none;
228
+ width: 40px;
229
+ height: 40px;
230
+ border: 4px solid #333;
231
+ border-top: 4px solid #ffffff;
232
+ border-radius: 50%;
233
+ animation: spin 1s linear infinite;
234
+ margin: 20px auto;
235
+ }
236
+
237
+ @keyframes spin {
238
+ 0% { transform: rotate(0deg); }
239
+ 100% { transform: rotate(360deg); }
240
+ }
241
+
242
  .result-container {
 
243
  display: none;
244
+ margin-top: 1.5rem;
245
  }
246
 
247
  .result-link {
248
+ color: #ffffff;
249
  text-decoration: none;
250
+ font-weight: 600;
251
+ transition: all 0.3s ease;
252
+ margin-right: 10px;
253
+ word-break: break-all;
254
  }
255
 
256
  .result-link:hover {
257
+ text-decoration: underline;
 
 
 
 
 
258
  }
259
 
260
+ .link-buttons {
261
+ display: flex;
262
+ justify-content: center;
263
+ flex-wrap: wrap;
264
+ margin-top: 10px;
 
 
 
 
265
  }
266
 
267
+ /* File Types */
268
  .file-types {
269
  margin-top: 2rem;
270
+ font-size: 0.8rem;
271
+ color: #aaa;
 
 
272
  }
273
 
274
+ .modal {
275
+ display: none;
276
+ position: fixed;
277
+ z-index: 2;
278
+ left: 0;
279
+ top: 0;
280
+ width: 100%;
281
+ height: 100%;
282
+ overflow: auto;
283
+ background-color: rgba(0,0,0,0.8);
284
  }
285
 
286
+ .modal-content {
287
+ background-color: #1e1e1e;
288
+ margin: 15% auto;
289
+ padding: 20px;
290
+ border: 1px solid #333;
291
+ width: 90%;
292
+ max-width: 600px;
293
+ border-radius: 10px;
294
+ color: #e0e0e0;
295
+ animation: modalFadeIn 0.3s;
296
+ position: relative;
297
  }
298
 
299
+ @keyframes modalFadeIn {
300
+ from {opacity: 0; transform: scale(0.8);}
301
+ to {opacity: 1; transform: scale(1);}
 
 
 
 
302
  }
303
 
304
+ .close {
305
+ color: #aaa;
306
+ position: absolute;
307
+ top: 10px;
308
+ right: 15px;
309
+ font-size: 28px;
310
+ font-weight: bold;
311
+ transition: color 0.3s ease;
312
  }
313
 
314
+ .close:hover,
315
+ .close:focus {
316
+ color: #fff;
317
+ text-decoration: none;
318
+ cursor: pointer;
319
+ }
320
+
321
+ .embed-container {
322
+ display: flex;
323
+ flex-direction: column;
324
+ align-items: stretch;
325
+ margin-top: 15px;
326
+ }
327
+
328
+ #embedLink {
329
+ width: 100%;
330
+ padding: 10px;
331
+ background-color: #333;
332
+ border: 1px solid #555;
333
+ color: #e0e0e0;
334
+ border-radius: 5px;
335
+ margin-bottom: 10px;
336
+ font-size: 0.9rem;
337
  }
338
 
339
  @media (max-width: 480px) {
 
344
  h1 {
345
  font-size: 1.5rem;
346
  }
347
+
348
+ .btn, .small-btn {
349
+ font-size: 0.9rem;
350
+ padding: 10px 20px;
351
+ }
352
+
353
+ .file-types {
354
+ font-size: 0.7rem;
355
+ }
356
+
357
+ .modal-content {
358
+ width: 95%;
359
+ margin: 10% auto;
360
+ }
361
  }
362
  </style>
363
  </head>
 
366
  <h1>Radd PRO Uploader</h1>
367
  <form id="uploadForm">
368
  <div id="dropZone" class="drop-zone">
 
 
369
  <input type="file" name="file" id="file" class="file-input" accept=".zip,.mp4,.txt,.mp3,image/*,.pdf" required>
370
+ <label for="file" class="btn">Choose File</label>
371
+ <p>or drag and drop file here/paste image</p>
372
  </div>
373
+ <div class="file-name" id="fileName"></div>
374
+ <button type="submit" id="uploadBtn" class="btn" style="display: none; margin-top: 1rem;">Upload File</button>
375
+ <div class="progress-container" id="progressContainer"></div>
 
 
 
376
  <div class="loading-spinner" id="loadingSpinner"></div>
377
  </form>
378
  <div class="result-container" id="resultContainer"></div>
 
381
  </div>
382
  </div>
383
 
384
+ <div id="embedModal" class="modal">
385
+ <div class="modal-content">
386
+ <span class="close">&times;</span>
387
+ <h2>Embed Video Link</h2>
388
+ <p>copy the link to embed it on discord:</p>
389
+ <div class="embed-container">
390
+ <input type="text" id="embedLink" readonly>
391
+ <button onclick="copyEmbedLink()" class="small-btn copy-embed-btn">Copy</button>
392
+ </div>
393
+ </div>
394
+ </div>
395
+
396
  <script>
397
  const fileInput = document.getElementById('file');
398
+ const fileName = document.getElementById('fileName');
399
  const uploadForm = document.getElementById('uploadForm');
400
  const progressContainer = document.getElementById('progressContainer');
 
401
  const loadingSpinner = document.getElementById('loadingSpinner');
402
  const resultContainer = document.getElementById('resultContainer');
403
  const dropZone = document.getElementById('dropZone');
404
+ const modal = document.getElementById('embedModal');
405
+ const span = document.getElementsByClassName("close")[0];
406
+ const embedLinkInput = document.getElementById('embedLink');
407
  const uploadBtn = document.getElementById('uploadBtn');
408
 
409
+ fileInput.addEventListener('change', handleFileSelect);
410
+
411
+ uploadForm.addEventListener('submit', (e) => {
412
+ e.preventDefault();
413
+ if (fileInput.files.length > 0) {
414
+ uploadFile(fileInput.files[0]);
415
+ }
416
  });
417
 
418
+ dropZone.addEventListener('dragover', (e) => {
419
+ e.preventDefault();
420
+ dropZone.classList.add('drag-over');
 
 
 
421
  });
422
 
423
+ dropZone.addEventListener('dragleave', () => {
424
+ dropZone.classList.remove('drag-over');
 
 
 
 
425
  });
426
 
427
  dropZone.addEventListener('drop', (e) => {
428
  e.preventDefault();
429
+ dropZone.classList.remove('drag-over');
430
+ handleFileSelect({ target: { files: e.dataTransfer.files } });
431
  });
432
 
433
+ document.addEventListener('paste', (e) => {
434
+ const items = e.clipboardData.items;
435
+ for (let i = 0; i < items.length; i++) {
436
+ if (items[i].kind === 'file') {
437
+ const file = items[i].getAsFile();
438
+ handleFileSelect({ target: { files: [file] } });
439
+ break;
440
+ }
441
+ }
442
+ });
443
 
444
+ span.onclick = function() {
445
+ modal.style.display = "none";
446
+ }
447
+
448
+ window.onclick = function(event) {
449
+ if (event.target == modal) {
450
+ modal.style.display = "none";
 
451
  }
452
  }
453
 
454
+ function handleFileSelect(e) {
455
+ if (e.target.files && e.target.files.length > 0) {
456
+ const file = e.target.files[0];
457
+ fileName.textContent = file.name;
458
+ uploadBtn.style.display = 'inline-block';
459
+
460
+ const dataTransfer = new DataTransfer();
461
+ dataTransfer.items.add(file);
462
+ fileInput.files = dataTransfer.files;
463
  }
464
+ }
465
 
466
  async function uploadFile(file) {
467
+ progressContainer.innerHTML = '';
468
  progressContainer.style.display = 'block';
469
+ loadingSpinner.style.display = 'block';
470
  uploadBtn.disabled = true;
471
+ resultContainer.innerHTML = '';
472
  resultContainer.style.display = 'none';
473
+
474
+ const progressBar = createProgressBar(file.name);
475
+ progressContainer.appendChild(progressBar);
476
 
477
  const formData = new FormData();
478
  formData.append('file', file);
479
 
480
+ while (true) {
481
+ try {
482
+ const xhr = new XMLHttpRequest();
483
+ xhr.open('POST', '/upload', true);
484
+ xhr.upload.onprogress = (event) => updateProgress(event, progressBar.querySelector('.progress'));
485
+
486
+ xhr.onload = function() {
487
+ if (xhr.status === 200) {
488
+ const response = JSON.parse(xhr.responseText);
489
+ if (response.url) {
490
+ addResultLink(response.url, file.name);
491
+ resetUploadState();
492
+ return;
493
+ } else {
494
+ throw new Error('Upload failed: ' + response.error);
495
+ }
496
+ } else {
497
+ throw new Error(`HTTP error! status: ${xhr.status}`);
498
+ }
499
+ };
500
+
501
+ xhr.onerror = function() {
502
+ throw new Error('Network error occurred');
503
+ };
504
+
505
+ xhr.send(formData);
506
+
507
+ // Wait for the request to complete
508
+ await new Promise((resolve, reject) => {
509
+ xhr.onloadend = resolve;
510
+ xhr.onerror = reject;
511
+ });
512
+
513
+ break; // Success, exit the loop
514
+ } catch (error) {
515
+ console.error('Upload error:', error);
516
+ // Wait for a short time before retrying
517
+ await new Promise(resolve => setTimeout(resolve, 1000));
518
+ // The loop will continue, retrying the upload
519
  }
520
+ }
521
+ }
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
522
 
523
+ function createProgressBar(fileName) {
524
+ const progressBarContainer = document.createElement('div');
525
+ progressBarContainer.className = 'progress-bar';
526
+ const progress = document.createElement('div');
527
+ progress.className = 'progress';
528
+ progressBarContainer.appendChild(progress);
529
+ const label = document.createElement('div');
530
+ label.textContent = fileName;
531
+ label.style.fontSize = '0.8rem';
532
+ label.style.marginBottom = '5px';
533
+ const container = document.createElement('div');
534
+ container.appendChild(label);
535
+ container.appendChild(progressBarContainer);
536
+ return container;
537
+ }
538
+
539
+ function updateProgress(event, progressBar) {
540
+ if (event.lengthComputable) {
541
+ const percentComplete = (event.loaded / event.total) * 100;
542
+ progressBar.style.width = percentComplete + '%';
543
+ }
544
  }
545
 
546
+ function resetUploadState() {
547
  fileInput.value = '';
548
+ fileName.textContent = '';
549
  uploadBtn.style.display = 'none';
550
  uploadBtn.disabled = false;
551
  loadingSpinner.style.display = 'none';
 
552
  }
553
 
554
+ function addResultLink(url, fileName) {
555
+ const linkContainer = document.createElement('div');
556
+ linkContainer.style.marginBottom = '10px';
557
+
558
+ const link = document.createElement('a');
559
+ link.href = url;
560
+ link.textContent = `View ${fileName}`;
561
+ link.className = 'result-link';
562
+ link.target = '_blank';
563
+
564
+ linkContainer.appendChild(link);
565
+
566
+ const buttonsContainer = document.createElement('div');
567
+ buttonsContainer.className = 'link-buttons';
568
+
569
+ const copyBtn = document.createElement('button');
570
+ copyBtn.textContent = 'Copy Link';
571
+ copyBtn.className = 'small-btn copy-btn';
572
+ copyBtn.onclick = () => {
573
+ navigator.clipboard.writeText(window.location.origin + url).then(() => {
574
+ alert('Link copied to clipboard!');
575
+ });
576
+ };
577
+ buttonsContainer.appendChild(copyBtn);
578
+
579
+ if (fileName.toLowerCase().endsWith('.mp4')) {
580
+ const embedBtn = document.createElement('button');
581
+ embedBtn.textContent = 'Embed Video for Discord';
582
+ embedBtn.className = 'small-btn embed-btn';
583
+ embedBtn.onclick = () => {
584
+ showEmbedModal(url);
585
+ };
586
+ buttonsContainer.appendChild(embedBtn);
587
+ }
588
+
589
+ linkContainer.appendChild(buttonsContainer);
590
+
591
+ resultContainer.appendChild(linkContainer);
592
  resultContainer.style.display = 'block';
593
  }
594
+
595
+ function showEmbedModal(url) {
596
+ const embedUrl = `${window.location.origin}/embed?url=${encodeURIComponent(window.location.origin + url)}&thumbnail=${encodeURIComponent('https://coollsd-fileuploader.hf.space/rbxg/LdnShkhZFgMlMmCwkeX78RqHbiol6r554v5BryQS9upEC1wu/Untitled.png')}`;
597
+ embedLinkInput.value = embedUrl;
598
+ modal.style.display = "block";
599
+ }
600
+
601
+ function copyEmbedLink() {
602
+ embedLinkInput.select();
603
+ document.execCommand('copy');
604
+ alert('Embed link copied to clipboard!');
605
+ }
606
  </script>
607
  </body>
608
  </html>
 
643
  headers = {'Range': range_header} if range_header else {}
644
  response = requests.get(original_url, headers=headers, stream=True)
645
 
646
+ def generate():
647
  for chunk in response.iter_content(chunk_size=8192):
648
  yield chunk
649
 
650
+ headers = dict(response.headers)
651
+ headers['Access-Control-Allow-Origin'] = '*'
652
+ headers['Content-Disposition'] = 'inline'
653
 
654
+ if response.status_code == 206:
655
+ headers['Content-Range'] = response.headers.get('Content-Range')
656
+
657
+ return StreamingResponse(generate(), status_code=response.status_code, headers=headers)
658
 
659
  @app.get("/embed")
660
  async def embed_video(url: str, thumbnail: str):
661
  html = f'''
662
+ <html>
 
663
  <head>
664
  <meta property="og:type" content="video.other">
665
  <meta property="og:video" content="{url}">
 
674
  <meta property="og:image:height" content="720">
675
  <meta property="og:image:type" content="image/png">
676
  <style>
677
+ body, html {{ margin: 0; padding: 0; height: 100%; background: #000; }}
678
+ #thumbnail {{ width: 100%; height: 100%; object-fit: contain; cursor: pointer; }}
679
+ #video {{ display: none; width: 100%; height: 100%; object-fit: contain; }}
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
680
  </style>
681
  </head>
682
  <body>
683
+ <img id="thumbnail" src="{thumbnail}" onclick="playVideo()">
684
+ <video id="video" controls autoplay>
685
+ <source src="{url}" type="video/mp4">
686
+ Your browser does not support the video tag.
687
+ </video>
688
+ <script>
689
+ function playVideo() {{
690
+ document.getElementById('thumbnail').style.display = 'none';
691
+ document.getElementById('video').style.display = 'block';
692
+ document.getElementById('video').play();
693
+ }}
694
+ </script>
695
  </body>
696
  </html>
697
  '''
 
700
  async def get_cookies() -> Dict[str, str]:
701
  try:
702
  response = requests.get('https://replicate.com/levelsio/neon-tokyo', headers={
703
+ 'User-Agent': 'Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/128.0.0.0 Safari/537.36'
704
  })
705
+ return dict(response.cookies)
706
  except Exception as e:
707
  print(f'Error fetching the page: {e}')
708
  return {}
 
712
  try:
713
  response = requests.post(url, cookies=cookies, headers={
714
  'X-CSRFToken': cookies.get('csrftoken'),
715
+ 'User-Agent': 'Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/128.0.0.0 Safari/537.36',
716
+ 'Referer': 'https://replicate.com/levelsio/neon-tokyo',
717
+ 'Origin': 'https://replicate.com',
718
+ 'Accept': '*/*',
719
+ 'Accept-Language': 'en-US,en;q=0.5',
720
+ 'Accept-Encoding': 'identity',
721
+ 'Sec-Fetch-Dest': 'empty',
722
+ 'Sec-Fetch-Mode': 'cors',
723
+ 'Sec-Fetch-Site': 'same-origin',
724
+ 'Sec-GPC': '1',
725
+ 'Priority': 'u=1, i'
726
  })
727
  return response.json()
728
  except Exception as e:
729
  print(f'Error initiating upload: {e}')
730
+ raise
731
 
732
  async def upload_file(upload_url: str, file_content: bytes, content_type: str) -> bool:
733
  try:
 
738
  return False
739
 
740
  async def retry_upload(upload_url: str, file_content: bytes, content_type: str, max_retries: int = 5, delay: int = 1) -> bool:
741
+ while True:
742
+ try:
743
+ success = await upload_file(upload_url, file_content, content_type)
744
+ if success:
745
+ return True
746
+ print("Upload failed. Retrying...")
747
+ except Exception as e:
748
+ print(f"Error during upload: {e}")
749
+
750
+ await asyncio.sleep(delay)
751
+ delay = min(delay * 2, 60) # Exponential backoff, capped at 60 seconds
752
+
753
  return False