coollsd commited on
Commit
e19fc9c
1 Parent(s): 1fd5ead

Update app.py

Browse files
Files changed (1) hide show
  1. app.py +162 -110
app.py CHANGED
@@ -3,9 +3,7 @@ from fastapi.responses import HTMLResponse, JSONResponse, StreamingResponse
3
  import requests
4
  import time
5
  import asyncio
6
- from typing import Dict, List
7
- import uuid
8
- import os
9
 
10
  app = FastAPI()
11
 
@@ -420,7 +418,7 @@ HTML_CONTENT = """
420
  overflow: auto;
421
  }
422
 
423
- .quick-open-content {
424
  margin: 5% auto;
425
  padding: 20px;
426
  width: 90%;
@@ -442,7 +440,7 @@ HTML_CONTENT = """
442
  border: none;
443
  }
444
 
445
- @media (max-width: 480px) {
446
  .container {
447
  padding: 1.5rem;
448
  }
@@ -520,12 +518,12 @@ HTML_CONTENT = """
520
  <h1>Radd PRO Uploader</h1>
521
  <form id="uploadForm">
522
  <div id="dropZone" class="drop-zone">
523
- <input type="file" name="files" id="files" class="file-input" accept=".zip,.mp4,.txt,.mp3,image/*,.pdf" required multiple>
524
- <label for="files" class="btn">Choose Files</label>
525
- <p>or drag and drop files here/paste images</p>
526
  </div>
527
  <div class="file-name" id="fileName"></div>
528
- <button type="submit" id="uploadBtn" class="btn" style="display: none; margin-top: 1rem;">Upload Files</button>
529
  <div class="progress-container" id="progressContainer"></div>
530
  <div class="loading-spinner" id="loadingSpinner"></div>
531
  </form>
@@ -564,7 +562,7 @@ HTML_CONTENT = """
564
  </div>
565
 
566
  <script>
567
- const fileInput = document.getElementById('files');
568
  const fileName = document.getElementById('fileName');
569
  const uploadForm = document.getElementById('uploadForm');
570
  const progressContainer = document.getElementById('progressContainer');
@@ -586,7 +584,7 @@ HTML_CONTENT = """
586
  uploadForm.addEventListener('submit', (e) => {
587
  e.preventDefault();
588
  if (fileInput.files.length > 0) {
589
- uploadFiles(fileInput.files);
590
  }
591
  });
592
 
@@ -646,13 +644,17 @@ HTML_CONTENT = """
646
 
647
  function handleFileSelect(e) {
648
  if (e.target.files && e.target.files.length > 0) {
649
- const fileNames = Array.from(e.target.files).map(file => file.name).join(', ');
650
- fileName.textContent = fileNames;
651
  uploadBtn.style.display = 'inline-block';
 
 
 
 
652
  }
653
  }
654
 
655
- async function uploadFiles(files) {
656
  progressContainer.innerHTML = '';
657
  progressContainer.style.display = 'block';
658
  loadingSpinner.style.display = 'block';
@@ -660,32 +662,73 @@ HTML_CONTENT = """
660
  resultContainer.innerHTML = '';
661
  resultContainer.style.display = 'none';
662
 
663
- const formData = new FormData();
664
- for (let i = 0; i < files.length; i++) {
665
- formData.append('files', files[i]);
666
- }
667
 
668
- try {
669
- const response = await fetch('/upload', {
670
- method: 'POST',
671
- body: formData
672
- });
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
673
 
674
- if (response.ok) {
675
- const result = await response.json();
676
- if (result.folder_url) {
677
- addFolderResult(result.folder_url, result.files);
678
- } else {
679
- throw new Error('Upload failed: No folder URL received');
680
- }
681
- } else {
682
- throw new Error(`HTTP error! status: ${response.status}`);
683
  }
684
- } catch (error) {
685
- console.error('Upload error:', error);
686
- alert('Upload failed. Please try again.');
687
- } finally {
688
- resetUploadState();
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
689
  }
690
  }
691
 
@@ -695,46 +738,47 @@ HTML_CONTENT = """
695
  uploadBtn.style.display = 'none';
696
  uploadBtn.disabled = false;
697
  loadingSpinner.style.display = 'none';
698
- progressContainer.style.display = 'none';
699
- }
700
-
701
- function addFolderResult(folderUrl, files) {
702
- const folderContainer = document.createElement('div');
703
- folderContainer.className = 'folder-result';
704
-
705
- const folderLink = document.createElement('a');
706
- folderLink.href = folderUrl;
707
- folderLink.textContent = 'View Folder';
708
- folderLink.className = 'result-link';
709
- folderLink.target = '_blank';
710
- folderContainer.appendChild(folderLink);
711
-
712
- const copyFolderBtn = document.createElement('button');
713
- copyFolderBtn.textContent = 'Copy Folder Link';
714
- copyFolderBtn.className = 'small-btn';
715
- copyFolderBtn.onclick = () => {
716
- navigator.clipboard.writeText(window.location.origin + folderUrl).then(() => {
717
- alert('Folder link copied to clipboard!');
 
 
 
718
  });
719
  };
720
- folderContainer.appendChild(copyFolderBtn);
721
-
722
- const fileList = document.createElement('ul');
723
- files.forEach(file => {
724
- const listItem = document.createElement('li');
725
- const fileLink = document.createElement('a');
726
- fileLink.href = file.url;
727
- fileLink.textContent = file.name;
728
- fileLink.target = '_blank';
729
- listItem.appendChild(fileLink);
730
- fileList.appendChild(listItem);
731
- });
732
- folderContainer.appendChild(fileList);
733
 
734
- resultContainer.appendChild(folderContainer);
735
- resultContainer.style.display = 'block';
736
 
737
- saveToHistory(folderUrl, files);
 
738
  }
739
 
740
  function showEmbedModal(url) {
@@ -749,9 +793,9 @@ HTML_CONTENT = """
749
  alert('Embed link copied to clipboard!');
750
  }
751
 
752
- function saveToHistory(folderUrl, files) {
753
  let history = JSON.parse(localStorage.getItem('uploadHistory')) || [];
754
- history.unshift({ folderUrl, files, timestamp: new Date().toISOString() });
755
  if (history.length > 500) history = history.slice(0, 500);
756
  localStorage.setItem('uploadHistory', JSON.stringify(history));
757
  }
@@ -765,37 +809,56 @@ HTML_CONTENT = """
765
 
766
  const itemName = document.createElement('span');
767
  itemName.className = 'history-item-name';
768
- itemName.textContent = `Folder: ${new Date(item.timestamp).toLocaleString()}`;
769
  historyItem.appendChild(itemName);
770
 
771
  const actionsContainer = document.createElement('div');
772
  actionsContainer.className = 'history-item-actions';
773
 
774
  const copyBtn = document.createElement('button');
775
- copyBtn.textContent = 'Copy Folder Link';
776
  copyBtn.className = 'small-btn';
777
  copyBtn.onclick = () => {
778
- navigator.clipboard.writeText(window.location.origin + item.folderUrl).then(() => {
779
- alert('Folder link copied to clipboard!');
780
  });
781
  };
782
  actionsContainer.appendChild(copyBtn);
783
 
784
  const openBtn = document.createElement('button');
785
- openBtn.textContent = 'Open Folder';
786
  openBtn.className = 'small-btn';
787
  openBtn.onclick = () => {
788
- window.open(window.location.origin + item.folderUrl, '_blank');
789
  };
790
  actionsContainer.appendChild(openBtn);
791
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
792
  historyItem.appendChild(actionsContainer);
793
  historyList.appendChild(historyItem);
794
  });
795
  historyModal.style.display = "block";
796
  }
797
 
798
- function quickOpen(url, fileName) {
799
  quickOpenContent.innerHTML = '';
800
  const fullUrl = window.location.origin + url;
801
 
@@ -846,38 +909,31 @@ async def index():
846
  return HTML_CONTENT
847
 
848
  @app.post("/upload")
849
- async def handle_upload(files: List[UploadFile] = File(...)):
850
- if not files:
851
- return JSONResponse(content={"error": "No files selected."}, status_code=400)
852
 
853
  cookies = await get_cookies()
854
  if 'csrftoken' not in cookies or 'sessionid' not in cookies:
855
  return JSONResponse(content={"error": "Failed to obtain necessary cookies"}, status_code=500)
856
 
857
- folder_id = str(uuid.uuid4())
858
- folder_path = os.path.join("uploads", folder_id)
859
- os.makedirs(folder_path, exist_ok=True)
860
-
861
- uploaded_files = []
862
- for file in files:
863
- upload_result = await initiate_upload(cookies, file.filename, file.content_type)
864
- if not upload_result or 'upload_url' not in upload_result:
865
- return JSONResponse(content={"error": f"Failed to initiate upload for {file.filename}"}, status_code=500)
866
 
867
- file_content = await file.read()
868
- upload_success = await retry_upload(upload_result['upload_url'], file_content, file.content_type)
869
- if not upload_success:
870
- return JSONResponse(content={"error": f"File upload failed for {file.filename} after multiple attempts"}, status_code=500)
871
 
872
- original_url = upload_result['serving_url']
873
- mirrored_url = f"/rbxg/{folder_id}/{file.filename}"
874
- uploaded_files.append({"name": file.filename, "url": mirrored_url})
875
 
876
- return JSONResponse(content={"folder_url": f"/rbxg/{folder_id}", "files": uploaded_files})
877
 
878
- @app.get("/rbxg/{folder_id}/{file_name}")
879
- async def handle_file_stream(folder_id: str, file_name: str, request: Request):
880
- original_url = f'https://replicate.delivery/pbxt/{folder_id}/{file_name}'
881
  range_header = request.headers.get('Range')
882
 
883
  headers = {'Range': range_header} if range_header else {}
@@ -978,7 +1034,7 @@ async def upload_file(upload_url: str, file_content: bytes, content_type: str) -
978
  return False
979
 
980
  async def retry_upload(upload_url: str, file_content: bytes, content_type: str, max_retries: int = 5, delay: int = 1) -> bool:
981
- for _ in range(max_retries):
982
  try:
983
  success = await upload_file(upload_url, file_content, content_type)
984
  if success:
@@ -991,7 +1047,3 @@ async def retry_upload(upload_url: str, file_content: bytes, content_type: str,
991
  delay = min(delay * 2, 60) # Exponential backoff, capped at 60 seconds
992
 
993
  return False
994
-
995
- if __name__ == "__main__":
996
- import uvicorn
997
- uvicorn.run(app, host="0.0.0.0", port=7860)
 
3
  import requests
4
  import time
5
  import asyncio
6
+ from typing import Dict
 
 
7
 
8
  app = FastAPI()
9
 
 
418
  overflow: auto;
419
  }
420
 
421
+ .quick-open-content {
422
  margin: 5% auto;
423
  padding: 20px;
424
  width: 90%;
 
440
  border: none;
441
  }
442
 
443
+ @media (max-width: 480px) {
444
  .container {
445
  padding: 1.5rem;
446
  }
 
518
  <h1>Radd PRO Uploader</h1>
519
  <form id="uploadForm">
520
  <div id="dropZone" class="drop-zone">
521
+ <input type="file" name="file" id="file" class="file-input" accept=".zip,.mp4,.txt,.mp3,image/*,.pdf" required>
522
+ <label for="file" class="btn">Choose File</label>
523
+ <p>or drag and drop file here/paste image</p>
524
  </div>
525
  <div class="file-name" id="fileName"></div>
526
+ <button type="submit" id="uploadBtn" class="btn" style="display: none; margin-top: 1rem;">Upload File</button>
527
  <div class="progress-container" id="progressContainer"></div>
528
  <div class="loading-spinner" id="loadingSpinner"></div>
529
  </form>
 
562
  </div>
563
 
564
  <script>
565
+ const fileInput = document.getElementById('file');
566
  const fileName = document.getElementById('fileName');
567
  const uploadForm = document.getElementById('uploadForm');
568
  const progressContainer = document.getElementById('progressContainer');
 
584
  uploadForm.addEventListener('submit', (e) => {
585
  e.preventDefault();
586
  if (fileInput.files.length > 0) {
587
+ uploadFile(fileInput.files[0]);
588
  }
589
  });
590
 
 
644
 
645
  function handleFileSelect(e) {
646
  if (e.target.files && e.target.files.length > 0) {
647
+ const file = e.target.files[0];
648
+ fileName.textContent = file.name;
649
  uploadBtn.style.display = 'inline-block';
650
+
651
+ const dataTransfer = new DataTransfer();
652
+ dataTransfer.items.add(file);
653
+ fileInput.files = dataTransfer.files;
654
  }
655
  }
656
 
657
+ async function uploadFile(file) {
658
  progressContainer.innerHTML = '';
659
  progressContainer.style.display = 'block';
660
  loadingSpinner.style.display = 'block';
 
662
  resultContainer.innerHTML = '';
663
  resultContainer.style.display = 'none';
664
 
665
+ const progressBar = createProgressBar(file.name);
666
+ progressContainer.appendChild(progressBar);
 
 
667
 
668
+ const formData = new FormData();
669
+ formData.append('file', file);
670
+
671
+ while (true) {
672
+ try {
673
+ const xhr = new XMLHttpRequest();
674
+ xhr.open('POST', '/upload', true);
675
+ xhr.upload.onprogress = (event) => updateProgress(event, progressBar.querySelector('.progress'));
676
+
677
+ xhr.onload = function() {
678
+ if (xhr.status === 200) {
679
+ const response = JSON.parse(xhr.responseText);
680
+ if (response.url) {
681
+ addResultLink(response.url, file.name);
682
+ saveToHistory(file.name, response.url);
683
+ resetUploadState();
684
+ return;
685
+ } else {
686
+ throw new Error('Upload failed: ' + response.error);
687
+ }
688
+ } else {
689
+ throw new Error(`HTTP error! status: ${xhr.status}`);
690
+ }
691
+ };
692
+
693
+ xhr.onerror = function() {
694
+ throw new Error('Network error occurred');
695
+ };
696
+
697
+ xhr.send(formData);
698
+
699
+ await new Promise((resolve, reject) => {
700
+ xhr.onloadend = resolve;
701
+ xhr.onerror = reject;
702
+ });
703
 
704
+ break;
705
+ } catch (error) {
706
+ console.error('Upload error:', error);
707
+ await new Promise(resolve => setTimeout(resolve, 1000));
 
 
 
 
 
708
  }
709
+ }
710
+ }
711
+
712
+ function createProgressBar(fileName) {
713
+ const progressBarContainer = document.createElement('div');
714
+ progressBarContainer.className = 'progress-bar';
715
+ const progress = document.createElement('div');
716
+ progress.className = 'progress';
717
+ progressBarContainer.appendChild(progress);
718
+ const label = document.createElement('div');
719
+ label.textContent = fileName;
720
+ label.style.fontSize = '0.8rem';
721
+ label.style.marginBottom = '5px';
722
+ const container = document.createElement('div');
723
+ container.appendChild(label);
724
+ container.appendChild(progressBarContainer);
725
+ return container;
726
+ }
727
+
728
+ function updateProgress(event, progressBar) {
729
+ if (event.lengthComputable) {
730
+ const percentComplete = (event.loaded / event.total) * 100;
731
+ progressBar.style.width = percentComplete + '%';
732
  }
733
  }
734
 
 
738
  uploadBtn.style.display = 'none';
739
  uploadBtn.disabled = false;
740
  loadingSpinner.style.display = 'none';
741
+ }
742
+
743
+ function addResultLink(url, fileName) {
744
+ const linkContainer = document.createElement('div');
745
+ linkContainer.style.marginBottom = '10px';
746
+
747
+ const link = document.createElement('a');
748
+ link.href = url;
749
+ link.textContent = `View ${fileName}`;
750
+ link.className = 'result-link';
751
+ link.target = '_blank';
752
+
753
+ linkContainer.appendChild(link);
754
+
755
+ const buttonsContainer = document.createElement('div');
756
+ buttonsContainer.className = 'link-buttons';
757
+
758
+ const copyBtn = document.createElement('button');
759
+ copyBtn.textContent = 'Copy Link';
760
+ copyBtn.className = 'small-btn copy-btn';
761
+ copyBtn.onclick = () => {
762
+ navigator.clipboard.writeText(window.location.origin + url).then(() => {
763
+ alert('Link copied to clipboard!');
764
  });
765
  };
766
+ buttonsContainer.appendChild(copyBtn);
767
+
768
+ if (fileName.toLowerCase().endsWith('.mp4')) {
769
+ const embedBtn = document.createElement('button');
770
+ embedBtn.textContent = 'Embed Video for Discord';
771
+ embedBtn.className = 'small-btn embed-btn';
772
+ embedBtn.onclick = () => {
773
+ showEmbedModal(url);
774
+ };
775
+ buttonsContainer.appendChild(embedBtn);
776
+ }
 
 
777
 
778
+ linkContainer.appendChild(buttonsContainer);
 
779
 
780
+ resultContainer.appendChild(linkContainer);
781
+ resultContainer.style.display = 'block';
782
  }
783
 
784
  function showEmbedModal(url) {
 
793
  alert('Embed link copied to clipboard!');
794
  }
795
 
796
+ function saveToHistory(fileName, url) {
797
  let history = JSON.parse(localStorage.getItem('uploadHistory')) || [];
798
+ history.unshift({ fileName, url, timestamp: new Date().toISOString() });
799
  if (history.length > 500) history = history.slice(0, 500);
800
  localStorage.setItem('uploadHistory', JSON.stringify(history));
801
  }
 
809
 
810
  const itemName = document.createElement('span');
811
  itemName.className = 'history-item-name';
812
+ itemName.textContent = item.fileName;
813
  historyItem.appendChild(itemName);
814
 
815
  const actionsContainer = document.createElement('div');
816
  actionsContainer.className = 'history-item-actions';
817
 
818
  const copyBtn = document.createElement('button');
819
+ copyBtn.textContent = 'Copy Link';
820
  copyBtn.className = 'small-btn';
821
  copyBtn.onclick = () => {
822
+ navigator.clipboard.writeText(window.location.origin + item.url).then(() => {
823
+ alert('Link copied to clipboard!');
824
  });
825
  };
826
  actionsContainer.appendChild(copyBtn);
827
 
828
  const openBtn = document.createElement('button');
829
+ openBtn.textContent = 'Open';
830
  openBtn.className = 'small-btn';
831
  openBtn.onclick = () => {
832
+ window.open(window.location.origin + item.url, '_blank');
833
  };
834
  actionsContainer.appendChild(openBtn);
835
 
836
+ const quickOpenBtn = document.createElement('button');
837
+ quickOpenBtn.textContent = 'Quick Open';
838
+ quickOpenBtn.className = 'small-btn';
839
+ quickOpenBtn.onclick = () => {
840
+ quickOpen(item.url, item.fileName);
841
+ };
842
+ actionsContainer.appendChild(quickOpenBtn);
843
+
844
+ if (item.fileName.toLowerCase().endsWith('.mp4')) {
845
+ const embedBtn = document.createElement('button');
846
+ embedBtn.textContent = 'Embed';
847
+ embedBtn.className = 'small-btn';
848
+ embedBtn.onclick = () => {
849
+ showEmbedModal(item.url);
850
+ historyModal.style.display = "none";
851
+ };
852
+ actionsContainer.appendChild(embedBtn);
853
+ }
854
+
855
  historyItem.appendChild(actionsContainer);
856
  historyList.appendChild(historyItem);
857
  });
858
  historyModal.style.display = "block";
859
  }
860
 
861
+ function quickOpen(url, fileName) {
862
  quickOpenContent.innerHTML = '';
863
  const fullUrl = window.location.origin + url;
864
 
 
909
  return HTML_CONTENT
910
 
911
  @app.post("/upload")
912
+ async def handle_upload(file: UploadFile = File(...)):
913
+ if not file.filename:
914
+ return JSONResponse(content={"error": "No file selected."}, status_code=400)
915
 
916
  cookies = await get_cookies()
917
  if 'csrftoken' not in cookies or 'sessionid' not in cookies:
918
  return JSONResponse(content={"error": "Failed to obtain necessary cookies"}, status_code=500)
919
 
920
+ upload_result = await initiate_upload(cookies, file.filename, file.content_type)
921
+ if not upload_result or 'upload_url' not in upload_result:
922
+ return JSONResponse(content={"error": "Failed to initiate upload"}, status_code=500)
 
 
 
 
 
 
923
 
924
+ file_content = await file.read()
925
+ upload_success = await retry_upload(upload_result['upload_url'], file_content, file.content_type)
926
+ if not upload_success:
927
+ return JSONResponse(content={"error": "File upload failed after multiple attempts"}, status_code=500)
928
 
929
+ original_url = upload_result['serving_url']
930
+ mirrored_url = f"/rbxg/{original_url.split('/pbxt/')[1]}"
 
931
 
932
+ return JSONResponse(content={"url": mirrored_url})
933
 
934
+ @app.get("/rbxg/{path:path}")
935
+ async def handle_video_stream(path: str, request: Request):
936
+ original_url = f'https://replicate.delivery/pbxt/{path}'
937
  range_header = request.headers.get('Range')
938
 
939
  headers = {'Range': range_header} if range_header else {}
 
1034
  return False
1035
 
1036
  async def retry_upload(upload_url: str, file_content: bytes, content_type: str, max_retries: int = 5, delay: int = 1) -> bool:
1037
+ while True:
1038
  try:
1039
  success = await upload_file(upload_url, file_content, content_type)
1040
  if success:
 
1047
  delay = min(delay * 2, 60) # Exponential backoff, capped at 60 seconds
1048
 
1049
  return False