albumup commited on
Commit
d889136
·
verified ·
1 Parent(s): bdc505c

Update app.py

Browse files
Files changed (1) hide show
  1. app.py +42 -1045
app.py CHANGED
@@ -1,11 +1,8 @@
1
  from fastapi import FastAPI, File, UploadFile, Request
2
- from fastapi.responses import HTMLResponse, JSONResponse, StreamingResponse, FileResponse
3
  import requests
4
- import time
5
  import asyncio
6
- from typing import Dict
7
  import os
8
- import mimetypes
9
 
10
  app = FastAPI()
11
 
@@ -15,923 +12,14 @@ HTML_CONTENT = """
15
  <head>
16
  <meta charset="UTF-8">
17
  <meta name="viewport" content="width=device-width, initial-scale=1.0">
18
- <title>Radd PRO Uploader</title>
19
- <link href="https://fonts.googleapis.com/css2?family=Poppins:wght@300;400;600&display=swap" rel="stylesheet">
20
- <style>
21
- body {
22
- font-family: 'Poppins', sans-serif;
23
- background-color: #121212;
24
- color: #e0e0e0;
25
- margin: 0;
26
- min-height: 100vh;
27
- display: flex;
28
- justify-content: center;
29
- align-items: center;
30
- padding: 20px;
31
- box-sizing: border-box;
32
- }
33
-
34
- body::before {
35
- content: "";
36
- position: fixed;
37
- top: 0;
38
- left: 0;
39
- width: 100%;
40
- height: 100%;
41
- background: url('data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAADwAAAA8CAQAAACM/9unAAAACXBIWXMAAAsTAAALEwEAmpwYAAABF0lEQVR4nO3YMRLCQBRE0clsYgxZwwq7oLGxAgp2AtbsqQZsYgEG0wEWc/LSZnb9HcMjR8fHvEKCgoKCgoKCgoKCgoKCgoKCgoKCgoKCgsK8tJOq9fzs7vlkNlWvf5ELi+20t5k2VSL7p/iHJ5Rz5ynOhU7rQ4pUi+6b4hyeUc+cpzoVO60OkV7rQ4pUi+6b4hxenu+en4rQAOkaks/eJegGaUfOHI+nRvQCND1w2J9yf8C2KZwNjkeUsAKRa7Nz50tQAokVbO/U6AaiWjl5wd6kQAOke8Xpx3JgTQKVq7Heh0ADpFvF6cd0kE0Claux3odAA6RfxenHc+BNCpWrsd6HQAOkX8Xpx3PgTQqVq7Heh0ADpF/F6cdz4E0KlarjdI/cR1FBQUGBgYGBgYGBgYG/AT4AIHph6aQGU7oAAAAASUVORK5CYII=') repeat;
42
- animation: grain 8s steps(10) infinite;
43
- opacity: 0.2;
44
- pointer-events: none;
45
- }
46
-
47
- @keyframes grain {
48
- 0% { transform: translate(0, 0); }
49
- 10% { transform: translate(-5%, -5%); }
50
- 20% { transform: translate(-10%, 5%); }
51
- 30% { transform: translate(5%, -10%); }
52
- 40% { transform: translate(-5%, 15%); }
53
- 50% { transform: translate(-10%, 5%); }
54
- 60% { transform: translate(15%, 0); }
55
- 70% { transform: translate(0, 10%); }
56
- 80% { transform: translate(-15%, 0); }
57
- 90% { transform: translate(10%, 5%); }
58
- 100% { transform: translate(5%, 0); }
59
- }
60
-
61
- .container {
62
- position: relative;
63
- width: 100%;
64
- max-width: 450px;
65
- margin: 0 auto;
66
- padding: 2rem;
67
- background: rgba(18, 18, 18, 0.9);
68
- backdrop-filter: blur(10px);
69
- border-radius: 15px;
70
- z-index: 1;
71
- text-align: center;
72
- box-shadow: 0 0 20px rgba(0, 0, 0, 0.8);
73
- }
74
-
75
- h1 {
76
- margin-bottom: 1.5rem;
77
- font-size: 1.8rem;
78
- color: #ffffff;
79
- text-shadow: 0 0 5px rgba(255, 255, 255, 0.2);
80
- }
81
-
82
- .btn {
83
- display: inline-block;
84
- position: relative;
85
- padding: 12px 24px;
86
- margin: 0.5rem;
87
- font-size: 1rem;
88
- font-weight: 600;
89
- color: #ffffff;
90
- background-color: #2a2a2a;
91
- border: none;
92
- border-radius: 5px;
93
- cursor: pointer;
94
- overflow: hidden;
95
- z-index: 1;
96
- transition: color 0.3s ease, box-shadow 0.3s ease;
97
- }
98
-
99
- .btn:hover {
100
- color: #ffffff;
101
- box-shadow: 0 0 15px rgba(200, 200, 200, 0.5);
102
- }
103
-
104
- .btn:hover::before {
105
- content: '';
106
- position: absolute;
107
- inset: -10px;
108
- background: radial-gradient(circle at center, rgba(200,200,200,0.2), transparent);
109
- filter: blur(20px);
110
- animation: glowAnimation 2s infinite;
111
- z-index: -1;
112
- pointer-events: none;
113
- }
114
-
115
- @keyframes glowAnimation {
116
- 0% { transform: scale(0.8); }
117
- 50% { transform: scale(1.2); }
118
- 100% { transform: scale(0.8); }
119
- }
120
-
121
- .btn:active {
122
- transform: scale(0.98);
123
- }
124
-
125
- .small-btn {
126
- padding: 6px 12px;
127
- font-size: 0.8rem;
128
- font-weight: 500;
129
- background-color: #2a2a2a;
130
- color: #ffffff;
131
- border: none;
132
- border-radius: 5px;
133
- cursor: pointer;
134
- transition: color 0.3s ease, box-shadow 0.3s ease;
135
- position: relative;
136
- overflow: hidden;
137
- z-index: 1;
138
- margin: 0.25rem;
139
- }
140
-
141
- .small-btn:hover {
142
- color: #ffffff;
143
- box-shadow: 0 0 10px rgba(200, 200, 200, 0.5);
144
- }
145
-
146
- .small-btn:hover::before {
147
- content: '';
148
- position: absolute;
149
- inset: -10px;
150
- background: radial-gradient(circle at center, rgba(200,200,200,0.2), transparent);
151
- filter: blur(15px);
152
- animation: glowAnimation 2s infinite;
153
- z-index: -1;
154
- pointer-events: none;
155
- }
156
-
157
- .small-btn:active {
158
- transform: scale(0.98);
159
- }
160
-
161
- .drop-zone {
162
- position: relative;
163
- padding: 20px;
164
- margin-bottom: 1rem;
165
- border: 2px dashed #aaa;
166
- border-radius: 10px;
167
- cursor: pointer;
168
- transition: all 0.3s ease;
169
- background: rgba(255, 255, 255, 0.05);
170
- overflow: hidden;
171
- }
172
-
173
- .drop-zone:hover, .drop-zone.drag-over {
174
- border-color: #ffffff;
175
- background: rgba(255, 255, 255, 0.1);
176
- position: relative;
177
- }
178
-
179
- .drop-zone:hover::before, .drop-zone.drag-over::before {
180
- content: '';
181
- position: absolute;
182
- inset: -10px;
183
- background: radial-gradient(circle at center, rgba(200,200,200,0.2), transparent);
184
- filter: blur(30px);
185
- animation: grainGlow 5s infinite;
186
- z-index: -1;
187
- pointer-events: none;
188
- }
189
-
190
- @keyframes grainGlow {
191
- 0% { opacity: 0.2; }
192
- 50% { opacity: 0.5; }
193
- 100% { opacity: 0.2; }
194
- }
195
-
196
- .file-input {
197
- display: none;
198
- }
199
-
200
- .file-name {
201
- margin-top: 1rem;
202
- font-size: 0.9rem;
203
- color: #aaa;
204
- word-break: break-all;
205
- }
206
-
207
- .progress-container {
208
- display: none;
209
- margin-top: 1.5rem;
210
- }
211
-
212
- .progress-bar {
213
- width: 100%;
214
- height: 10px;
215
- background-color: #333;
216
- border-radius: 5px;
217
- overflow: hidden;
218
- margin-bottom: 10px;
219
- }
220
-
221
- .progress {
222
- width: 0%;
223
- height: 100%;
224
- background-color: #ffffff;
225
- transition: width 0.3s ease;
226
- }
227
-
228
- .loading-spinner {
229
- display: none;
230
- width: 40px;
231
- height: 40px;
232
- border: 4px solid #333;
233
- border-top: 4px solid #ffffff;
234
- border-radius: 50%;
235
- animation: spin 1s linear infinite;
236
- margin: 20px auto;
237
- }
238
-
239
- @keyframes spin {
240
- 0% { transform: rotate(0deg); }
241
- 100% { transform: rotate(360deg); }
242
- }
243
-
244
- .result-container {
245
- display: none;
246
- margin-top: 1.5rem;
247
- }
248
-
249
- .result-link {
250
- color: #ffffff;
251
- text-decoration: none;
252
- font-weight: 600;
253
- transition: all 0.3s ease;
254
- margin-right: 10px;
255
- word-break: break-all;
256
- }
257
-
258
- .result-link:hover {
259
- text-decoration: underline;
260
- }
261
-
262
- .link-buttons {
263
- display: flex;
264
- justify-content: center;
265
- flex-wrap: wrap;
266
- margin-top: 10px;
267
- }
268
-
269
- .file-types {
270
- margin-top: 2rem;
271
- font-size: 0.8rem;
272
- color: #aaa;
273
- }
274
-
275
- .modal {
276
- display: none;
277
- position: fixed;
278
- z-index: 2;
279
- left: 0;
280
- top: 0;
281
- width: 100%;
282
- height: 100%;
283
- overflow: auto;
284
- background-color: rgba(0,0,0,0.8);
285
- }
286
-
287
- .modal-content {
288
- background-color: #1e1e1e;
289
- margin: 15% auto;
290
- padding: 20px;
291
- border: 1px solid #333;
292
- width: 90%;
293
- max-width: 600px;
294
- border-radius: 10px;
295
- color: #e0e0e0;
296
- animation: modalFadeIn 0.3s;
297
- position: relative;
298
- }
299
-
300
- @keyframes modalFadeIn {
301
- from {opacity: 0; transform: scale(0.8);}
302
- to {opacity: 1; transform: scale(1);}
303
- }
304
-
305
- .close {
306
- color: #aaa;
307
- position: absolute;
308
- top: 10px;
309
- right: 15px;
310
- font-size: 28px;
311
- font-weight: bold;
312
- transition: color 0.3s ease;
313
- }
314
-
315
- .close:hover,
316
- .close:focus {
317
- color: #fff;
318
- text-decoration: none;
319
- cursor: pointer;
320
- }
321
-
322
- .embed-container {
323
- display: flex;
324
- flex-direction: column;
325
- align-items: stretch;
326
- margin-top: 15px;
327
- }
328
-
329
- #embedLink {
330
- width: 100%;
331
- padding: 10px;
332
- background-color: #333;
333
- border: 1px solid #555;
334
- color: #e0e0e0;
335
- border-radius: 5px;
336
- margin-bottom: 10px;
337
- font-size: 0.9rem;
338
- }
339
-
340
- .history-btn-container {
341
- display: flex;
342
- justify-content: center;
343
- gap: 10px;
344
- margin-top: 1rem;
345
- }
346
-
347
- .history-btn, .clear-history-btn {
348
- display: inline-block;
349
- padding: 8px 16px;
350
- font-size: 0.9rem;
351
- font-weight: 500;
352
- color: #ffffff;
353
- border: none;
354
- border-radius: 3px;
355
- cursor: pointer;
356
- transition: background-color 0.3s ease, box-shadow 0.3s ease;
357
- }
358
-
359
- .history-btn {
360
- background-color: #2a2a2a;
361
- }
362
-
363
- .history-btn:hover {
364
- background-color: #3a3a3a;
365
- box-shadow: 0 0 10px rgba(200, 200, 200, 0.3);
366
- }
367
-
368
- .clear-history-btn {
369
- background-color: #1a0505;
370
- }
371
-
372
- .clear-history-btn:hover {
373
- background-color: #2a0a0a;
374
- box-shadow: 0 0 10px rgba(255, 0, 0, 0.3);
375
- }
376
-
377
- .history-modal {
378
- display: none;
379
- position: fixed;
380
- z-index: 3;
381
- left: 0;
382
- top: 0;
383
- width: 100%;
384
- height: 100%;
385
- overflow: auto;
386
- background-color: rgba(0,0,0,0.8);
387
- }
388
-
389
- .history-modal-content {
390
- background-color: #1e1e1e;
391
- margin: 10% auto;
392
- padding: 20px;
393
- border: 1px solid #333;
394
- width: 90%;
395
- max-width: 600px;
396
- border-radius: 10px;
397
- color: #e0e0e0;
398
- animation: modalFadeIn 0.3s;
399
- position: relative;
400
- max-height: 80vh;
401
- overflow-y: auto;
402
- }
403
-
404
- .history-item {
405
- display: flex;
406
- justify-content: space-between;
407
- align-items: center;
408
- padding: 10px;
409
- border-bottom: 1px solid #333;
410
- transition: background-color 0.3s ease;
411
- }
412
-
413
- .history-item:hover {
414
- background-color: #2a2a2a;
415
- }
416
-
417
- .history-item-name {
418
- flex-grow: 1;
419
- margin-right: 10px;
420
- word-break: break-all;
421
- }
422
-
423
- .history-item-actions {
424
- display: flex;
425
- gap: 5px;
426
- }
427
-
428
- .quick-open-modal {
429
- display: none;
430
- position: fixed;
431
- z-index: 4;
432
- left: 0;
433
- top: 0;
434
- width: 100%;
435
- height: 100%;
436
- background-color: rgba(0,0,0,0.9);
437
- overflow: auto;
438
- }
439
-
440
- .quick-open-content {
441
- margin: 5% auto;
442
- padding: 20px;
443
- width: 90%;
444
- max-width: 800px;
445
- text-align: center;
446
- }
447
-
448
- .quick-open-content img,
449
- .quick-open-content video,
450
- .quick-open-content audio {
451
- max-width: 100%;
452
- max-height: 70vh;
453
- margin-bottom: 20px;
454
- }
455
-
456
- .quick-open-content iframe {
457
- width: 100%;
458
- height: 70vh;
459
- border: none;
460
- }
461
-
462
- @media (max-width: 480px) {
463
- .container {
464
- padding: 1.5rem;
465
- }
466
-
467
- h1 {
468
- font-size: 1.5rem;
469
- }
470
-
471
- .btn, .small-btn {
472
- font-size: 0.9rem;
473
- padding: 10px 20px;
474
- margin: 0.25rem;
475
- }
476
-
477
- .file-types {
478
- font-size: 0.7rem;
479
- }
480
-
481
- .modal-content, .history-modal-content {
482
- width: 95%;
483
- margin: 5% auto;
484
- padding: 15px;
485
- }
486
-
487
- .history-item {
488
- flex-direction: column;
489
- align-items: flex-start;
490
- }
491
-
492
- .history-item-actions {
493
- margin-top: 10px;
494
- flex-wrap: wrap;
495
- }
496
-
497
- .history-item-name {
498
- font-size: 0.9rem;
499
- }
500
-
501
- .drop-zone {
502
- padding: 15px;
503
- }
504
-
505
- .drop-zone p {
506
- font-size: 0.9rem;
507
- }
508
-
509
- .result-link {
510
- font-size: 0.9rem;
511
- }
512
-
513
- .link-buttons {
514
- flex-direction: column;
515
- align-items: stretch;
516
- }
517
-
518
- .link-buttons .small-btn {
519
- margin: 0.25rem 0;
520
- }
521
-
522
- .close {
523
- top: 5px;
524
- right: 10px;
525
- font-size: 24px;
526
- }
527
-
528
- .quick-open-content {
529
- margin: 10% auto;
530
- padding: 10px;
531
- }
532
- }
533
- </style>
534
  </head>
535
  <body>
536
- <div class="container">
537
- <h1>Radd PRO Uploader</h1>
538
- <form id="uploadForm">
539
- <div id="dropZone" class="drop-zone">
540
- <input type="file" name="file" id="file" class="file-input" accept="*" required>
541
- <label for="file" class="btn">Choose File</label>
542
- <p>or drag and drop file here/paste image</p>
543
- </div>
544
- <div class="file-name" id="fileName"></div>
545
- <button type="submit" id="uploadBtn" class="btn" style="display: none; margin-top: 1rem;">Upload File</button>
546
- <div class="progress-container" id="progressContainer"></div>
547
- <div class="loading-spinner" id="loadingSpinner"></div>
548
- </form>
549
- <div class="result-container" id="resultContainer"></div>
550
- <div class="file-types">
551
- All file types are supported
552
- </div>
553
- <div class="history-btn-container">
554
- <button id="historyBtn" class="history-btn">View Upload History</button>
555
- <button id="clearHistoryBtn" class="clear-history-btn">Clear History</button>
556
- </div>
557
- </div>
558
-
559
- <div id="embedModal" class="modal">
560
- <div class="modal-content">
561
- <span class="close">&times;</span>
562
- <h2>Embed Video Link</h2>
563
- <p>copy the link to embed it on discord:</p>
564
- <div class="embed-container">
565
- <input type="text" id="embedLink" readonly>
566
- <button onclick="copyEmbedLink()" class="small-btn copy-embed-btn">Copy</button>
567
- </div>
568
- </div>
569
- </div>
570
-
571
- <div id="historyModal" class="history-modal">
572
- <div class="history-modal-content">
573
- <span class="close">&times;</span>
574
- <h2>Upload History</h2>
575
- <div id="historyList"></div>
576
- </div>
577
- </div>
578
-
579
- <div id="quickOpenModal" class="quick-open-modal">
580
- <div class="quick-open-content">
581
- <span class="close">&times;</span>
582
- <div id="quickOpenContent"></div>
583
- </div>
584
- </div>
585
-
586
- <script>
587
- const fileInput = document.getElementById('file');
588
- const fileName = document.getElementById('fileName');
589
- const uploadForm = document.getElementById('uploadForm');
590
- const progressContainer = document.getElementById('progressContainer');
591
- const loadingSpinner = document.getElementById('loadingSpinner');
592
- const resultContainer = document.getElementById('resultContainer');
593
- const dropZone = document.getElementById('dropZone');
594
- const modal = document.getElementById('embedModal');
595
- const historyModal = document.getElementById('historyModal');
596
- const quickOpenModal = document.getElementById('quickOpenModal');
597
- const span = document.getElementsByClassName("close");
598
- const embedLinkInput = document.getElementById('embedLink');
599
- const uploadBtn = document.getElementById('uploadBtn');
600
- const historyBtn = document.getElementById('historyBtn');
601
- const clearHistoryBtn = document.getElementById('clearHistoryBtn');
602
- const historyList = document.getElementById('historyList');
603
- const quickOpenContent = document.getElementById('quickOpenContent');
604
-
605
- fileInput.addEventListener('change', handleFileSelect);
606
-
607
- uploadForm.addEventListener('submit', (e) => {
608
- e.preventDefault();
609
- if (fileInput.files.length > 0) {
610
- uploadFile(fileInput.files[0]);
611
- }
612
- });
613
-
614
- dropZone.addEventListener('dragover', (e) => {
615
- e.preventDefault();
616
- dropZone.classList.add('drag-over');
617
- });
618
-
619
- dropZone.addEventListener('dragleave', () => {
620
- dropZone.classList.remove('drag-over');
621
- });
622
-
623
- dropZone.addEventListener('drop', (e) => {
624
- e.preventDefault();
625
- dropZone.classList.remove('drag-over');
626
- handleFileSelect({ target: { files: e.dataTransfer.files } });
627
- });
628
-
629
- document.addEventListener('paste', (e) => {
630
- const items = e.clipboardData.items;
631
- for (let i = 0; i < items.length; i++) {
632
- if (items[i].kind === 'file') {
633
- const file = items[i].getAsFile();
634
- handleFileSelect({ target: { files: [file] } });
635
- break;
636
- }
637
- }
638
- });
639
-
640
- span[0].onclick = function() {
641
- modal.style.display = "none";
642
- }
643
-
644
- span[1].onclick = function() {
645
- historyModal.style.display = "none";
646
- }
647
-
648
- span[2].onclick = function() {
649
- quickOpenModal.style.display = "none";
650
- }
651
-
652
- window.onclick = function(event) {
653
- if (event.target == modal) {
654
- modal.style.display = "none";
655
- }
656
- if (event.target == historyModal) {
657
- historyModal.style.display = "none";
658
- }
659
- if (event.target == quickOpenModal) {
660
- quickOpenModal.style.display = "none";
661
- }
662
- }
663
-
664
- historyBtn.onclick = function() {
665
- showHistory();
666
- }
667
-
668
- clearHistoryBtn.onclick = function() {
669
- if (confirm('Are you sure you want to clear your upload history?')) {
670
- localStorage.removeItem('uploadHistory');
671
- alert('Upload history has been cleared.');
672
- }
673
- }
674
-
675
- function handleFileSelect(e) {
676
- if (e.target.files && e.target.files.length > 0) {
677
- const file = e.target.files[0];
678
- fileName.textContent = file.name;
679
- uploadBtn.style.display = 'inline-block';
680
-
681
- const dataTransfer = new DataTransfer();
682
- dataTransfer.items.add(file);
683
- fileInput.files = dataTransfer.files;
684
- }
685
- }
686
-
687
- async function uploadFile(file) {
688
- progressContainer.innerHTML = '';
689
- progressContainer.style.display = 'block';
690
- loadingSpinner.style.display = 'block';
691
- uploadBtn.disabled = true;
692
- resultContainer.innerHTML = '';
693
- resultContainer.style.display = 'none';
694
-
695
- const progressBar = createProgressBar(file.name);
696
- progressContainer.appendChild(progressBar);
697
-
698
- const formData = new FormData();
699
- formData.append('file', file);
700
-
701
- while (true) {
702
- try {
703
- const xhr = new XMLHttpRequest();
704
- xhr.open('POST', '/upload', true);
705
- xhr.upload.onprogress = (event) => updateProgress(event, progressBar.querySelector('.progress'));
706
-
707
- xhr.onload = function() {
708
- if (xhr.status === 200) {
709
- const response = JSON.parse(xhr.responseText);
710
- if (response.url) {
711
- addResultLink(response.url, file.name, response.originalExtension);
712
- saveToHistory(file.name, response.url, response.originalExtension);
713
- resetUploadState();
714
- return;
715
- } else {
716
- throw new Error('Upload failed: ' + response.error);
717
- }
718
- } else {
719
- throw new Error(`HTTP error! status: ${xhr.status}`);
720
- }
721
- };
722
-
723
- xhr.onerror = function() {
724
- throw new Error('Network error occurred');
725
- };
726
-
727
- xhr.send(formData);
728
-
729
- await new Promise((resolve, reject) => {
730
- xhr.onloadend = resolve;
731
- xhr.onerror = reject;
732
- });
733
-
734
- break;
735
- } catch (error) {
736
- console.error('Upload error:', error);
737
- await new Promise(resolve => setTimeout(resolve, 1000));
738
- }
739
- }
740
- }
741
-
742
- function createProgressBar(fileName) {
743
- const progressBarContainer = document.createElement('div');
744
- progressBarContainer.className = 'progress-bar';
745
- const progress = document.createElement('div');
746
- progress.className = 'progress';
747
- progressBarContainer.appendChild(progress);
748
- const label = document.createElement('div');
749
- label.textContent = fileName;
750
- label.style.fontSize = '0.8rem';
751
- label.style.marginBottom = '5px';
752
- const container = document.createElement('div');
753
- container.appendChild(label);
754
- container.appendChild(progressBarContainer);
755
- return container;
756
- }
757
-
758
- function updateProgress(event, progressBar) {
759
- if (event.lengthComputable) {
760
- const percentComplete = (event.loaded / event.total) * 100;
761
- progressBar.style.width = percentComplete + '%';
762
- }
763
- }
764
-
765
- function resetUploadState() {
766
- fileInput.value = '';
767
- fileName.textContent = '';
768
- uploadBtn.style.display = 'none';
769
- uploadBtn.disabled = false;
770
- loadingSpinner.style.display = 'none';
771
- }
772
-
773
- function addResultLink(url, fileName, originalExtension) {
774
- const linkContainer = document.createElement('div');
775
- linkContainer.style.marginBottom = '10px';
776
-
777
- const link = document.createElement('a');
778
- link.href = url;
779
- link.textContent = `View ${fileName}`;
780
- link.className = 'result-link';
781
- link.target = '_blank';
782
- link.download = fileName;
783
-
784
- linkContainer.appendChild(link);
785
-
786
- const buttonsContainer = document.createElement('div');
787
- buttonsContainer.className = 'link-buttons';
788
-
789
- const copyBtn = document.createElement('button');
790
- copyBtn.textContent = 'Copy Link';
791
- copyBtn.className = 'small-btn copy-btn';
792
- copyBtn.onclick = () => {
793
- navigator.clipboard.writeText(window.location.origin + url).then(() => {
794
- alert('Link copied to clipboard!');
795
- });
796
- };
797
- buttonsContainer.appendChild(copyBtn);
798
-
799
- const openBtn = document.createElement('button');
800
- openBtn.textContent = 'Open';
801
- openBtn.className = 'small-btn';
802
- openBtn.onclick = () => {
803
- quickOpen(url, fileName, originalExtension);
804
- };
805
- buttonsContainer.appendChild(openBtn);
806
-
807
- if (originalExtension.toLowerCase() === 'mp4') {
808
- const embedBtn = document.createElement('button');
809
- embedBtn.textContent = 'Embed Video for Discord';
810
- embedBtn.className = 'small-btn embed-btn';
811
- embedBtn.onclick = () => {
812
- showEmbedModal(url);
813
- };
814
- buttonsContainer.appendChild(embedBtn);
815
- }
816
-
817
- linkContainer.appendChild(buttonsContainer);
818
-
819
- resultContainer.appendChild(linkContainer);
820
- resultContainer.style.display = 'block';
821
- }
822
-
823
- function showEmbedModal(url) {
824
- const embedUrl = `https://x266.mov/e/${encodeURIComponent(window.location.origin + url)}`;
825
- embedLinkInput.value = embedUrl;
826
- modal.style.display = "block";
827
- }
828
-
829
- function copyEmbedLink() {
830
- embedLinkInput.select();
831
- document.execCommand('copy');
832
- alert('Embed link copied to clipboard!');
833
- }
834
-
835
- function saveToHistory(fileName, url, originalExtension) {
836
- let history = JSON.parse(localStorage.getItem('uploadHistory')) || [];
837
- history.unshift({ fileName, url, originalExtension, timestamp: new Date().toISOString() });
838
- if (history.length > 500) history = history.slice(0, 500);
839
- localStorage.setItem('uploadHistory', JSON.stringify(history));
840
- }
841
-
842
- function showHistory() {
843
- const history = JSON.parse(localStorage.getItem('uploadHistory')) || [];
844
- historyList.innerHTML = '';
845
- history.forEach(item => {
846
- const historyItem = document.createElement('div');
847
- historyItem.className = 'history-item';
848
-
849
- const itemName = document.createElement('span');
850
- itemName.className = 'history-item-name';
851
- itemName.textContent = item.fileName;
852
- historyItem.appendChild(itemName);
853
-
854
- const actionsContainer = document.createElement('div');
855
- actionsContainer.className = 'history-item-actions';
856
-
857
- const copyBtn = document.createElement('button');
858
- copyBtn.textContent = 'Copy Link';
859
- copyBtn.className = 'small-btn';
860
- copyBtn.onclick = () => {
861
- navigator.clipboard.writeText(window.location.origin + item.url).then(() => {
862
- alert('Link copied to clipboard!');
863
- });
864
- };
865
- actionsContainer.appendChild(copyBtn);
866
-
867
- const openBtn = document.createElement('button');
868
- openBtn.textContent = 'Open';
869
- openBtn.className = 'small-btn';
870
- openBtn.onclick = () => {
871
- quickOpen(item.url, item.fileName, item.originalExtension);
872
- };
873
- actionsContainer.appendChild(openBtn);
874
-
875
- if (item.originalExtension.toLowerCase() === 'mp4') {
876
- const embedBtn = document.createElement('button');
877
- embedBtn.textContent = 'Embed';
878
- embedBtn.className = 'small-btn';
879
- embedBtn.onclick = () => {
880
- showEmbedModal(item.url);
881
- historyModal.style.display = "none";
882
- };
883
- actionsContainer.appendChild(embedBtn);
884
- }
885
-
886
- historyItem.appendChild(actionsContainer);
887
- historyList.appendChild(historyItem);
888
- });
889
- historyModal.style.display = "block";
890
- }
891
-
892
- function quickOpen(url, fileName, originalExtension) {
893
- quickOpenContent.innerHTML = '';
894
- const fullUrl = window.location.origin + url;
895
-
896
- if (['jpeg', 'jpg', 'gif', 'png'].includes(originalExtension.toLowerCase())) {
897
- const img = document.createElement('img');
898
- img.src = fullUrl;
899
- img.alt = fileName;
900
- quickOpenContent.appendChild(img);
901
- } else if (originalExtension.toLowerCase() === 'mp4') {
902
- const video = document.createElement('video');
903
- video.src = fullUrl;
904
- video.controls = true;
905
- quickOpenContent.appendChild(video);
906
- } else if (originalExtension.toLowerCase() === 'mp3') {
907
- const audio = document.createElement('audio');
908
- audio.src = fullUrl;
909
- audio.controls = true;
910
- quickOpenContent.appendChild(audio);
911
- } else if (originalExtension.toLowerCase() === 'pdf') {
912
- const iframe = document.createElement('iframe');
913
- iframe.src = fullUrl;
914
- quickOpenContent.appendChild(iframe);
915
- } else if (originalExtension.toLowerCase() === 'txt') {
916
- fetch(fullUrl)
917
- .then(response => response.text())
918
- .then(text => {
919
- const pre = document.createElement('pre');
920
- pre.textContent = text;
921
- quickOpenContent.appendChild(pre);
922
- });
923
- } else {
924
- const link = document.createElement('a');
925
- link.href = fullUrl;
926
- link.textContent = 'Download ' + fileName;
927
- link.target = '_blank';
928
- link.download = fileName;
929
- quickOpenContent.appendChild(link);
930
- }
931
-
932
- quickOpenModal.style.display = "block";
933
- }
934
- </script>
935
  </body>
936
  </html>
937
  """
@@ -942,161 +30,70 @@ async def index():
942
 
943
  @app.post("/upload")
944
  async def handle_upload(file: UploadFile = File(...)):
945
- if not file.filename:
946
- return JSONResponse(content={"error": "No file selected."}, status_code=400)
947
 
948
  cookies = await get_cookies()
949
  if 'csrftoken' not in cookies or 'sessionid' not in cookies:
950
- return JSONResponse(content={"error": "Failed"}, status_code=500)
951
 
952
- original_extension = os.path.splitext(file.filename)[1][1:]
953
- supported_types = ['mp4', 'png', 'jpg', 'jpeg', 'gif', 'mp3', 'pdf', 'txt']
954
-
955
- if original_extension.lower() in supported_types:
956
- temp_filename = file.filename
957
- content_type = file.content_type
958
- else:
959
- temp_filename = f"{file.filename}.png"
960
- content_type = "image/png"
961
-
962
- upload_result = await initiate_upload(cookies, temp_filename, content_type)
963
  if not upload_result or 'upload_url' not in upload_result:
964
- return JSONResponse(content={"error": "Failed to upload"}, status_code=500)
965
 
966
  file_content = await file.read()
967
- upload_success = await retry_upload(upload_result['upload_url'], file_content, content_type)
968
  if not upload_success:
969
- return JSONResponse(content={"error": "FAILED GOD MAN AFTER alot of attempts"}, status_code=500)
970
-
971
- original_url = upload_result['serving_url']
972
- mirrored_url = f"/rbxg/{original_url.split('/pbxt/')[1]}"
973
-
974
- if original_extension.lower() not in supported_types:
975
- mirrored_url = mirrored_url.replace('.png', '')
976
 
977
- return JSONResponse(content={"url": mirrored_url, "originalExtension": original_extension})
 
978
 
979
  @app.get("/rbxg/{path:path}")
980
- async def handle_file_stream(path: str, request: Request):
981
  original_url = f'https://replicate.delivery/pbxt/{path}'
982
-
983
- if not path.lower().endswith(('.png', '.jpg', '.jpeg', '.gif', '.mp4', '.mp3', '.pdf', '.txt')):
984
- original_url += '.png'
985
-
986
  range_header = request.headers.get('Range')
987
  headers = {'Range': range_header} if range_header else {}
 
988
  response = requests.get(original_url, headers=headers, stream=True)
989
-
990
  def generate():
991
  for chunk in response.iter_content(chunk_size=8192):
992
  yield chunk
993
 
994
  headers = dict(response.headers)
995
  headers['Access-Control-Allow-Origin'] = '*'
996
- headers['Content-Disposition'] = 'inline'
997
-
998
- if response.status_code == 206:
999
- headers['Content-Range'] = response.headers.get('Content-Range')
1000
-
1001
- original_extension = os.path.splitext(path)[1][1:]
1002
- content_type, _ = mimetypes.guess_type(f"file.{original_extension}")
1003
- if content_type:
1004
- headers['Content-Type'] = content_type
1005
-
1006
- return StreamingResponse(generate(), status_code=response.status_code, headers=headers)
1007
-
1008
- @app.get("/embed")
1009
- async def embed_video(url: str, thumbnail: str):
1010
- html = f'''
1011
- <html>
1012
- <head>
1013
- <meta property="og:type" content="video.other">
1014
- <meta property="og:video" content="{url}">
1015
- <meta property="og:video:url" content="{url}">
1016
- <meta property="og:video:secure_url" content="{url}">
1017
- <meta property="og:video:type" content="video/mp4">
1018
- <meta property="og:video:width" content="1280">
1019
- <meta property="og:video:height" content="720">
1020
- <meta property="og:image" content="{thumbnail}">
1021
- <meta property="og:image:secure_url" content="{thumbnail}">
1022
- <meta property="og:image:width" content="1280">
1023
- <meta property="og:image:height" content="720">
1024
- <meta property="og:image:type" content="image/png">
1025
- <style>
1026
- body, html {{ margin: 0; padding: 0; height: 100%; background: #000; }}
1027
- #thumbnail {{ width: 100%; height: 100%; object-fit: contain; cursor: pointer; }}
1028
- #video {{ display: none; width: 100%; height: 100%; object-fit: contain; }}
1029
- </style>
1030
- </head>
1031
- <body>
1032
- <img id="thumbnail" src="{thumbnail}" onclick="playVideo()">
1033
- <video id="video" controls autoplay>
1034
- <source src="{url}" type="video/mp4">
1035
- Your browser does not support the video tag.
1036
- </video>
1037
- <script>
1038
- function playVideo() {{
1039
- document.getElementById('thumbnail').style.display = 'none';
1040
- document.getElementById('video').style.display = 'block';
1041
- document.getElementById('video').play();
1042
- }}
1043
- </script>
1044
- </body>
1045
- </html>
1046
- '''
1047
- return HTMLResponse(content=html)
1048
 
1049
- async def get_cookies() -> Dict[str, str]:
1050
  try:
1051
  response = requests.get('https://replicate.com/levelsio/neon-tokyo', headers={
1052
- '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'
1053
  })
1054
  return dict(response.cookies)
1055
- except Exception as e:
1056
- print(f'Error fetching the page: {e}')
1057
  return {}
1058
 
1059
- async def initiate_upload(cookies: Dict[str, str], filename: str, content_type: str) -> Dict:
1060
- url = f'https://replicate.com/api/upload/{filename}?content_type={content_type}'
1061
- try:
1062
- response = requests.post(url, cookies=cookies, headers={
1063
- 'X-CSRFToken': cookies.get('csrftoken'),
1064
- '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',
1065
- 'Referer': 'https://replicate.com/levelsio/neon-tokyo',
1066
- 'Origin': 'https://replicate.com',
1067
- 'Accept': '*/*',
1068
- 'Accept-Language': 'en-US,en;q=0.5',
1069
- 'Accept-Encoding': 'identity',
1070
- 'Sec-Fetch-Dest': 'empty',
1071
- 'Sec-Fetch-Mode': 'cors',
1072
- 'Sec-Fetch-Site': 'same-origin',
1073
- 'Sec-GPC': '1',
1074
- 'Priority': 'u=1, i'
1075
- })
1076
- return response.json()
1077
- except Exception as e:
1078
- print(f'Error initiating upload: {e}')
1079
- raise
1080
-
1081
- async def upload_file(upload_url: str, file_content: bytes, content_type: str) -> bool:
1082
- try:
1083
- response = requests.put(upload_url, data=file_content, headers={'Content-Type': content_type})
1084
- return response.status_code == 200
1085
- except Exception as e:
1086
- print(f'Error uploading file: {e}')
1087
- return False
1088
-
1089
- async def retry_upload(upload_url: str, file_content: bytes, content_type: str, max_retries: int = 5, delay: int = 1) -> bool:
1090
- while True:
1091
  try:
1092
- success = await upload_file(upload_url, file_content, content_type)
1093
- if success:
1094
  return True
1095
- print("Upload failed. Retrying...")
1096
- except Exception as e:
1097
- print(f"Error during upload: {e}")
1098
-
1099
  await asyncio.sleep(delay)
1100
- delay = min(delay * 2, 60)
1101
-
1102
  return False
 
1
  from fastapi import FastAPI, File, UploadFile, Request
2
+ from fastapi.responses import HTMLResponse, JSONResponse, StreamingResponse
3
  import requests
 
4
  import asyncio
 
5
  import os
 
6
 
7
  app = FastAPI()
8
 
 
12
  <head>
13
  <meta charset="UTF-8">
14
  <meta name="viewport" content="width=device-width, initial-scale=1.0">
15
+ <title>File Upload</title>
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
16
  </head>
17
  <body>
18
+ <h1>Upload File</h1>
19
+ <form action="/upload" method="post" enctype="multipart/form-data">
20
+ <input type="file" name="file" accept="*/*" required>
21
+ <button type="submit">Upload</button>
22
+ </form>
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
23
  </body>
24
  </html>
25
  """
 
30
 
31
  @app.post("/upload")
32
  async def handle_upload(file: UploadFile = File(...)):
33
+ if not file:
34
+ return JSONResponse({"error": "No file uploaded"}, status_code=400)
35
 
36
  cookies = await get_cookies()
37
  if 'csrftoken' not in cookies or 'sessionid' not in cookies:
38
+ return JSONResponse({"error": "Failed to get cookies"}, status_code=500)
39
 
40
+ upload_result = await initiate_upload(cookies, file.filename, file.content_type)
 
 
 
 
 
 
 
 
 
 
41
  if not upload_result or 'upload_url' not in upload_result:
42
+ return JSONResponse({"error": "Failed to initiate upload"}, status_code=500)
43
 
44
  file_content = await file.read()
45
+ upload_success = await retry_upload(upload_result['upload_url'], file_content, file.content_type)
46
  if not upload_success:
47
+ return JSONResponse({"error": "Upload failed"}, status_code=500)
 
 
 
 
 
 
48
 
49
+ mirrored_url = f"/rbxg/{upload_result['serving_url'].split('/pbxt/')[1]}"
50
+ return JSONResponse({"url": mirrored_url})
51
 
52
  @app.get("/rbxg/{path:path}")
53
+ async def handle_stream(path: str, request: Request):
54
  original_url = f'https://replicate.delivery/pbxt/{path}'
 
 
 
 
55
  range_header = request.headers.get('Range')
56
  headers = {'Range': range_header} if range_header else {}
57
+
58
  response = requests.get(original_url, headers=headers, stream=True)
59
+
60
  def generate():
61
  for chunk in response.iter_content(chunk_size=8192):
62
  yield chunk
63
 
64
  headers = dict(response.headers)
65
  headers['Access-Control-Allow-Origin'] = '*'
66
+
67
+ return StreamingResponse(generate(), headers=headers, status_code=response.status_code)
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
68
 
69
+ async def get_cookies():
70
  try:
71
  response = requests.get('https://replicate.com/levelsio/neon-tokyo', headers={
72
+ 'User-Agent': 'Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36'
73
  })
74
  return dict(response.cookies)
75
+ except Exception:
 
76
  return {}
77
 
78
+ async def initiate_upload(cookies, filename, content_type):
79
+ url = f"https://replicate.com/api/upload/{filename}?content_type={content_type}"
80
+ headers = {
81
+ 'X-CSRFToken': cookies['csrftoken'],
82
+ 'Referer': 'https://replicate.com/levelsio/neon-tokyo',
83
+ 'Origin': 'https://replicate.com'
84
+ }
85
+ response = requests.post(url, cookies=cookies, headers=headers)
86
+ return response.json()
87
+
88
+ async def retry_upload(upload_url, file_content, content_type, max_retries=5):
89
+ delay = 1
90
+ for _ in range(max_retries):
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
91
  try:
92
+ response = requests.put(upload_url, data=file_content, headers={'Content-Type': content_type})
93
+ if response.status_code == 200:
94
  return True
95
+ except Exception:
96
+ pass
 
 
97
  await asyncio.sleep(delay)
98
+ delay *= 2
 
99
  return False