Spaces:
Paused
Paused
Update app.py
Browse files
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
|
| 7 |
-
import uuid
|
| 8 |
-
import os
|
| 9 |
|
| 10 |
app = FastAPI()
|
| 11 |
|
|
@@ -420,7 +418,7 @@ HTML_CONTENT = """
|
|
| 420 |
overflow: auto;
|
| 421 |
}
|
| 422 |
|
| 423 |
-
|
| 424 |
margin: 5% auto;
|
| 425 |
padding: 20px;
|
| 426 |
width: 90%;
|
|
@@ -442,7 +440,7 @@ HTML_CONTENT = """
|
|
| 442 |
border: none;
|
| 443 |
}
|
| 444 |
|
| 445 |
-
|
| 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="
|
| 524 |
-
<label for="
|
| 525 |
-
<p>or drag and drop
|
| 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
|
| 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('
|
| 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 |
-
|
| 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
|
| 650 |
-
fileName.textContent =
|
| 651 |
uploadBtn.style.display = 'inline-block';
|
|
|
|
|
|
|
|
|
|
|
|
|
| 652 |
}
|
| 653 |
}
|
| 654 |
|
| 655 |
-
async function
|
| 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
|
| 664 |
-
|
| 665 |
-
formData.append('files', files[i]);
|
| 666 |
-
}
|
| 667 |
|
| 668 |
-
|
| 669 |
-
|
| 670 |
-
|
| 671 |
-
|
| 672 |
-
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 673 |
|
| 674 |
-
|
| 675 |
-
|
| 676 |
-
|
| 677 |
-
|
| 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 |
-
}
|
| 685 |
-
|
| 686 |
-
|
| 687 |
-
|
| 688 |
-
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 689 |
}
|
| 690 |
}
|
| 691 |
|
|
@@ -695,46 +738,47 @@ HTML_CONTENT = """
|
|
| 695 |
uploadBtn.style.display = 'none';
|
| 696 |
uploadBtn.disabled = false;
|
| 697 |
loadingSpinner.style.display = 'none';
|
| 698 |
-
|
| 699 |
-
|
| 700 |
-
|
| 701 |
-
|
| 702 |
-
|
| 703 |
-
|
| 704 |
-
|
| 705 |
-
|
| 706 |
-
|
| 707 |
-
|
| 708 |
-
|
| 709 |
-
|
| 710 |
-
|
| 711 |
-
|
| 712 |
-
const
|
| 713 |
-
|
| 714 |
-
|
| 715 |
-
|
| 716 |
-
|
| 717 |
-
|
|
|
|
|
|
|
|
|
|
| 718 |
});
|
| 719 |
};
|
| 720 |
-
|
| 721 |
-
|
| 722 |
-
|
| 723 |
-
|
| 724 |
-
|
| 725 |
-
|
| 726 |
-
|
| 727 |
-
|
| 728 |
-
|
| 729 |
-
|
| 730 |
-
|
| 731 |
-
});
|
| 732 |
-
folderContainer.appendChild(fileList);
|
| 733 |
|
| 734 |
-
|
| 735 |
-
resultContainer.style.display = 'block';
|
| 736 |
|
| 737 |
-
|
|
|
|
| 738 |
}
|
| 739 |
|
| 740 |
function showEmbedModal(url) {
|
|
@@ -749,9 +793,9 @@ HTML_CONTENT = """
|
|
| 749 |
alert('Embed link copied to clipboard!');
|
| 750 |
}
|
| 751 |
|
| 752 |
-
function saveToHistory(
|
| 753 |
let history = JSON.parse(localStorage.getItem('uploadHistory')) || [];
|
| 754 |
-
history.unshift({
|
| 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 =
|
| 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
|
| 776 |
copyBtn.className = 'small-btn';
|
| 777 |
copyBtn.onclick = () => {
|
| 778 |
-
navigator.clipboard.writeText(window.location.origin + item.
|
| 779 |
-
alert('
|
| 780 |
});
|
| 781 |
};
|
| 782 |
actionsContainer.appendChild(copyBtn);
|
| 783 |
|
| 784 |
const openBtn = document.createElement('button');
|
| 785 |
-
openBtn.textContent = 'Open
|
| 786 |
openBtn.className = 'small-btn';
|
| 787 |
openBtn.onclick = () => {
|
| 788 |
-
window.open(window.location.origin + item.
|
| 789 |
};
|
| 790 |
actionsContainer.appendChild(openBtn);
|
| 791 |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 792 |
historyItem.appendChild(actionsContainer);
|
| 793 |
historyList.appendChild(historyItem);
|
| 794 |
});
|
| 795 |
historyModal.style.display = "block";
|
| 796 |
}
|
| 797 |
|
| 798 |
-
|
| 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(
|
| 850 |
-
if not
|
| 851 |
-
return JSONResponse(content={"error": "No
|
| 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 |
-
|
| 858 |
-
|
| 859 |
-
|
| 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 |
-
|
| 868 |
-
|
| 869 |
-
|
| 870 |
-
|
| 871 |
|
| 872 |
-
|
| 873 |
-
|
| 874 |
-
uploaded_files.append({"name": file.filename, "url": mirrored_url})
|
| 875 |
|
| 876 |
-
return JSONResponse(content={"
|
| 877 |
|
| 878 |
-
@app.get("/rbxg/{
|
| 879 |
-
async def
|
| 880 |
-
original_url = f'https://replicate.delivery/pbxt/{
|
| 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 |
-
|
| 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
|
|
|
|
|
|
|
|
|
|
|
|