fileuploader / app.py
coollsd's picture
Update app.py
a7d7c12 verified
raw
history blame
32.7 kB
from fastapi import FastAPI, Request, HTTPException
from fastapi.responses import JSONResponse, StreamingResponse
import requests
import time
import asyncio
from typing import Dict
import base64
import secrets
from cryptography.fernet import Fernet
from starlette.middleware.sessions import SessionMiddleware
app = FastAPI()
# Add SessionMiddleware to the application
app.add_middleware(SessionMiddleware, secret_key=secrets.token_urlsafe(32))
# Generate a secret key for Fernet encryption
FERNET_KEY = Fernet.generate_key()
fernet = Fernet(FERNET_KEY)
HTML_CONTENT = """
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>Radd PRO Uploader</title>
<link href="https://fonts.googleapis.com/css2?family=Poppins:wght@300;400;600&display=swap" rel="stylesheet">
<style>
body {
font-family: 'Poppins', sans-serif;
background-color: #121212;
color: #e0e0e0;
margin: 0;
min-height: 100vh;
display: flex;
justify-content: center;
align-items: center;
padding: 20px;
box-sizing: border-box;
}
body::before {
content: "";
position: fixed;
top: 0;
left: 0;
width: 100%;
height: 100%;
background: url('data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAADwAAAA8CAQAAACM/9unAAAACXBIWXMAAAsTAAALEwEAmpwYAAABF0lEQVR4nO3YMRLCQBRE0clsYgxZwwq7oLGxAgp2AtbsqQZsYgEG0wEWc/LSZnb9HcMjR8fHvEKCgoKCgoKCgoKCgoKCgoKCgoKCgoKCgsK8tJOq9fzs7vlkNlWvf5ELi+20t5k2VSL7p/iHJ5Rz5ynOhU7rQ4pUi+6b4hyeUc+cpzoVO60OkV7rQ4pUi+6b4hxenu+en4rQAOkaks/eJegGaUfOHI+nRvQCND1w2J9yf8C2KZwNjkeUsAKRa7Nz50tQAokVbO/U6AaiWjl5wd6kQAOke8Xpx3JgTQKVq7Heh0ADpFvF6cd0kE0Claux3odAA6RfxenHc+BNCpWrsd6HQAOkX8Xpx3PgTQqVq7Heh0ADpF/F6cdz4E0KlarjdI/cR1FBQUGBgYGBgYGBgYG/AT4AIHph6aQGU7oAAAAASUVORK5CYII=') repeat;
animation: grain 8s steps(10) infinite;
opacity: 0.2;
pointer-events: none;
}
@keyframes grain {
0% { transform: translate(0, 0); }
10% { transform: translate(-5%, -5%); }
20% { transform: translate(-10%, 5%); }
30% { transform: translate(5%, -10%); }
40% { transform: translate(-5%, 15%); }
50% { transform: translate(-10%, 5%); }
60% { transform: translate(15%, 0); }
70% { transform: translate(0, 10%); }
80% { transform: translate(-15%, 0); }
90% { transform: translate(10%, 5%); }
100% { transform: translate(5%, 0); }
}
.container {
position: relative;
width: 100%;
max-width: 450px;
margin: 0 auto;
padding: 2rem;
background: rgba(18, 18, 18, 0.9);
backdrop-filter: blur(10px);
border-radius: 15px;
z-index: 1;
text-align: center;
box-shadow: 0 0 20px rgba(0, 0, 0, 0.8);
}
h1 {
margin-bottom: 1.5rem;
font-size: 1.8rem;
color: #ffffff;
text-shadow: 0 0 5px rgba(255, 255, 255, 0.2);
}
.btn {
display: inline-block;
position: relative;
padding: 12px 24px;
margin: 0.5rem;
font-size: 1rem;
font-weight: 600;
color: #ffffff;
background-color: #2a2a2a;
border: none;
border-radius: 5px;
cursor: pointer;
overflow: hidden;
z-index: 1;
transition: color 0.3s ease, box-shadow 0.3s ease;
}
.btn:hover {
color: #ffffff;
box-shadow: 0 0 15px rgba(200, 200, 200, 0.5);
}
.btn:hover::before {
content: '';
position: absolute;
inset: -10px;
background: radial-gradient(circle at center, rgba(200,200,200,0.2), transparent);
filter: blur(20px);
animation: glowAnimation 2s infinite;
z-index: -1;
pointer-events: none;
}
@keyframes glowAnimation {
0% { transform: scale(0.8); }
50% { transform: scale(1.2); }
100% { transform: scale(0.8); }
}
.btn:active {
transform: scale(0.98);
}
.small-btn {
padding: 6px 12px;
font-size: 0.8rem;
font-weight: 500;
background-color: #2a2a2a;
color: #ffffff;
border: none;
border-radius: 5px;
cursor: pointer;
transition: color 0.3s ease, box-shadow 0.3s ease;
position: relative;
overflow: hidden;
z-index: 1;
margin: 0.25rem;
}
.small-btn:hover {
color: #ffffff;
box-shadow: 0 0 10px rgba(200, 200, 200, 0.5);
}
.small-btn:hover::before {
content: '';
position: absolute;
inset: -10px;
background: radial-gradient(circle at center, rgba(200,200,200,0.2), transparent);
filter: blur(15px);
animation: glowAnimation 2s infinite;
z-index: -1;
pointer-events: none;
}
.small-btn:active {
transform: scale(0.98);
}
.drop-zone {
position: relative;
padding: 20px;
margin-bottom: 1rem;
border: 2px dashed #aaa;
border-radius: 10px;
cursor: pointer;
transition: all 0.3s ease;
background: rgba(255, 255, 255, 0.05);
overflow: hidden;
}
.drop-zone:hover, .drop-zone.drag-over {
border-color: #ffffff;
background: rgba(255, 255, 255, 0.1);
position: relative;
}
.drop-zone:hover::before, .drop-zone.drag-over::before {
content: '';
position: absolute;
inset: -10px;
background: radial-gradient(circle at center, rgba(200,200,200,0.2), transparent);
filter: blur(30px);
animation: grainGlow 5s infinite;
z-index: -1;
pointer-events: none;
}
@keyframes grainGlow {
0% { opacity: 0.2; }
50% { opacity: 0.5; }
100% { opacity: 0.2; }
}
.file-input {
display: none;
}
.file-name {
margin-top: 1rem;
font-size: 0.9rem;
color: #aaa;
word-break: break-all;
}
.progress-container {
display: none;
margin-top: 1.5rem;
}
.progress-bar {
width: 100%;
height: 10px;
background-color: #333;
border-radius: 5px;
overflow: hidden;
margin-bottom: 10px;
}
.progress {
width: 0%;
height: 100%;
background-color: #ffffff;
transition: width 0.3s ease;
}
.loading-spinner {
display: none;
width: 40px;
height: 40px;
border: 4px solid #333;
border-top: 4px solid #ffffff;
border-radius: 50%;
animation: spin 1s linear infinite;
margin: 20px auto;
}
@keyframes spin {
0% { transform: rotate(0deg); }
100% { transform: rotate(360deg); }
}
.result-container {
display: none;
margin-top: 1.5rem;
}
.result-link {
color: #ffffff;
text-decoration: none;
font-weight: 600;
transition: all 0.3s ease;
margin-right: 10px;
word-break: break-all;
}
.result-link:hover {
text-decoration: underline;
}
.link-buttons {
display: flex;
justify-content: center;
flex-wrap: wrap;
margin-top: 10px;
}
/* File Types */
.file-types {
margin-top: 2rem;
font-size: 0.8rem;
color: #aaa;
}
.modal {
display: none;
position: fixed;
z-index: 2;
left: 0;
top: 0;
width: 100%;
height: 100%;
overflow: auto;
background-color: rgba(0,0,0,0.8);
}
.modal-content {
background-color: #1e1e1e;
margin: 15% auto;
padding: 20px;
border: 1px solid #333;
width: 90%;
max-width: 600px;
border-radius: 10px;
color: #e0e0e0;
animation: modalFadeIn 0.3s;
position: relative;
}
@keyframes modalFadeIn {
from {opacity: 0; transform: scale(0.8);}
to {opacity: 1; transform: scale(1);}
}
.close {
color: #aaa;
position: absolute;
top: 10px;
right: 15px;
font-size: 28px;
font-weight: bold;
transition: color 0.3s ease;
}
.close:hover,
.close:focus {
color: #fff;
text-decoration: none;
cursor: pointer;
}
.embed-container {
display: flex;
flex-direction: column;
align-items: stretch;
margin-top: 15px;
}
#embedLink {
width: 100%;
padding: 10px;
background-color: #333;
border: 1px solid #555;
color: #e0e0e0;
border-radius: 5px;
margin-bottom: 10px;
font-size: 0.9rem;
}
.history-btn {
display: inline-block;
padding: 8px 16px;
font-size: 0.9rem;
font-weight: 500;
color: #ffffff;
background-color: #2a2a2a;
border: none;
border-radius: 3px;
cursor: pointer;
transition: background-color 0.3s ease, box-shadow 0.3s ease;
margin-top: 1rem;
}
.history-btn:hover {
background-color: #3a3a3a;
box-shadow: 0 0 10px rgba(200, 200, 200, 0.3);
}
.history-modal {
display: none;
position: fixed;
z-index: 3;
left: 0;
top: 0;
width: 100%;
height: 100%;
overflow: auto;
background-color: rgba(0,0,0,0.8);
}
.history-modal-content {
background-color: #1e1e1e;
margin: 10% auto;
padding: 20px;
border: 1px solid #333;
width: 90%;
max-width: 600px;
border-radius: 10px;
color: #e0e0e0;
animation: modalFadeIn 0.3s;
position: relative;
max-height: 80vh;
overflow-y: auto;
}
.history-item {
display: flex;
justify-content: space-between;
align-items: center;
padding: 10px;
border-bottom: 1px solid #333;
transition: background-color 0.3s ease;
}
.history-item:hover {
background-color: #2a2a2a;
}
.history-item-name {
flex-grow: 1;
margin-right: 10px;
word-break: break-all;
}
.history-item-actions {
display: flex;
gap: 5px;
}
@media (max-width: 480px) {
.container {
padding: 1.5rem;
}
h1 {
font-size: 1.5rem;
}
.btn, .small-btn {
font-size: 0.9rem;
padding: 10px 20px;
margin: 0.25rem;
}
.file-types {
font-size: 0.7rem;
}
.modal-content, .history-modal-content {
width: 95%;
margin: 5% auto;
padding: 15px;
}
.history-item {
flex-direction: column;
align-items: flex-start;
}
.history-item-actions {
margin-top: 10px;
flex-wrap: wrap;
}
.history-item-name {
font-size: 0.9rem;
}
.drop-zone {
padding: 15px;
}
.drop-zone p {
font-size: 0.9rem;
}
.result-link {
font-size: 0.9rem;
}
.link-buttons {
flex-direction: column;
align-items: stretch;
}
.link-buttons .small-btn {
margin: 0.25rem 0;
}
.close {
top: 5px;
right: 10px;
font-size: 24px;
}
}
</style>
</head>
<body>
<div class="container">
<h1>Radd PRO Uploader</h1>
<form id="uploadForm">
<div id="dropZone" class="drop-zone">
<input type="file" name="file" id="file" class="file-input" accept=".zip,.mp4,.txt,.mp3,image/*,.pdf" required>
<label for="file" class="btn">Choose File</label>
<p>or drag and drop file here/paste image</p>
</div>
<div class="file-name" id="fileName"></div>
<button type="submit" id="uploadBtn" class="btn" style="display: none; margin-top: 1rem;">Upload File</button>
<div class="progress-container" id="progressContainer"></div>
<div class="loading-spinner" id="loadingSpinner"></div>
</form>
<div class="result-container" id="resultContainer"></div>
<div class="file-types">
Allowed file types: .zip, .mp4, .txt, .mp3, all image types, .pdf
</div>
<button id="historyBtn" class="history-btn">View Upload History</button>
</div>
<div id="embedModal" class="modal">
<div class="modal-content">
<span class="close">&times;</span>
<h2>Embed Video Link</h2>
<p>copy the link to embed it on discord:</p>
<div class="embed-container">
<input type="text" id="embedLink" readonly>
<button onclick="copyEmbedLink()" class="small-btn copy-embed-btn">Copy</button>
</div>
</div>
</div>
<div id="historyModal" class="history-modal">
<div class="history-modal-content">
<span class="close">&times;</span>
<h2>Upload History</h2>
<div id="historyList"></div>
</div>
</div>
<script>
const fileInput = document.getElementById('file');
const fileName = document.getElementById('fileName');
const uploadForm = document.getElementById('uploadForm');
const progressContainer = document.getElementById('progressContainer');
const loadingSpinner = document.getElementById('loadingSpinner');
const resultContainer = document.getElementById('resultContainer');
const dropZone = document.getElementById('dropZone');
const modal = document.getElementById('embedModal');
const historyModal = document.getElementById('historyModal');
const span = document.getElementsByClassName("close");
const embedLinkInput = document.getElementById('embedLink');
const uploadBtn = document.getElementById('uploadBtn');
const historyBtn = document.getElementById('historyBtn');
const historyList = document.getElementById('historyList');
fileInput.addEventListener('change', handleFileSelect);
uploadForm.addEventListener('submit', (e) => {
e.preventDefault();
if (fileInput.files.length > 0) {
uploadFile(fileInput.files[0]);
}
});
dropZone.addEventListener('dragover', (e) => {
e.preventDefault();
dropZone.classList.add('drag-over');
});
dropZone.addEventListener('dragleave', () => {
dropZone.classList.remove('drag-over');
});
dropZone.addEventListener('drop', (e) => {
e.preventDefault();
dropZone.classList.remove('drag-over');
handleFileSelect({ target: { files: e.dataTransfer.files } });
});
document.addEventListener('paste', (e) => {
const items = e.clipboardData.items;
for (let i = 0; i < items.length; i++) {
if (items[i].kind === 'file') {
const file = items[i].getAsFile();
handleFileSelect({ target: { files: [file] } });
break;
}
}
});
span[0].onclick = function() {
modal.style.display = "none";
}
span[1].onclick = function() {
historyModal.style.display = "none";
}
window.onclick = function(event) {
if (event.target == modal) {
modal.style.display = "none";
}
if (event.target == historyModal) {
historyModal.style.display = "none";
}
}
historyBtn.onclick = function() {
showHistory();
}
function handleFileSelect(e) {
if (e.target.files && e.target.files.length > 0) {
const file = e.target.files[0];
fileName.textContent = file.name;
uploadBtn.style.display = 'inline-block';
const dataTransfer = new DataTransfer();
dataTransfer.items.add(file);
fileInput.files = dataTransfer.files;
}
}
async function uploadFile(file) {
progressContainer.innerHTML = '';
progressContainer.style.display = 'block';
loadingSpinner.style.display = 'block';
uploadBtn.disabled = true;
resultContainer.innerHTML = '';
resultContainer.style.display = 'none';
const progressBar = createProgressBar(file.name);
progressContainer.appendChild(progressBar);
const formData = new FormData();
formData.append('file', file);
while (true) {
try {
const xhr = new XMLHttpRequest();
xhr.open('POST', '/upload', true);
xhr.upload.onprogress = (event) => updateProgress(event, progressBar.querySelector('.progress'));
xhr.onload = function() {
if (xhr.status === 200) {
const response = JSON.parse(xhr.responseText);
if (response.url) {
addResultLink(response.url, file.name);
saveToHistory(file.name, response.url);
resetUploadState();
return;
} else {
throw new Error('Upload failed: ' + response.error);
}
} else {
throw new Error(`HTTP error! status: ${xhr.status}`);
}
};
xhr.onerror = function() {
throw new Error('Network error occurred');
};
xhr.send(formData);
await new Promise((resolve, reject) => {
xhr.onloadend = resolve;
xhr.onerror = reject;
});
break;
} catch (error) {
console.error('Upload error:', error);
await new Promise(resolve => setTimeout(resolve, 1000));
}
}
}
function createProgressBar(fileName) {
const progressBarContainer = document.createElement('div');
progressBarContainer.className = 'progress-bar';
const progress = document.createElement('div');
progress.className = 'progress';
progressBarContainer.appendChild(progress);
const label = document.createElement('div');
label.textContent = fileName;
label.style.fontSize = '0.8rem';
label.style.marginBottom = '5px';
const container = document.createElement('div');
container.appendChild(label);
container.appendChild(progressBarContainer);
return container;
}
function updateProgress(event, progressBar) {
if (event.lengthComputable) {
const percentComplete = (event.loaded / event.total) * 100;
progressBar.style.width = percentComplete + '%';
}
}
function resetUploadState() {
fileInput.value = '';
fileName.textContent = '';
uploadBtn.style.display = 'none';
uploadBtn.disabled = false;
loadingSpinner.style.display = 'none';
}
function addResultLink(url, fileName) {
const linkContainer = document.createElement('div');
linkContainer.style.marginBottom = '10px';
const link = document.createElement('a');
link.href = url;
link.textContent = `View ${fileName}`;
link.className = 'result-link';
link.target = '_blank';
linkContainer.appendChild(link);
const buttonsContainer = document.createElement('div');
buttonsContainer.className = 'link-buttons';
const copyBtn = document.createElement('button');
copyBtn.textContent = 'Copy Link';
copyBtn.className = 'small-btn copy-btn';
copyBtn.onclick = () => {
navigator.clipboard.writeText(window.location.origin + url).then(() => {
alert('Link copied to clipboard!');
});
};
buttonsContainer.appendChild(copyBtn);
if (fileName.toLowerCase().endsWith('.mp4')) {
const embedBtn = document.createElement('button');
embedBtn.textContent = 'Embed Video for Discord';
embedBtn.className = 'small-btn embed-btn';
embedBtn.onclick = () => {
showEmbedModal(url);
};
buttonsContainer.appendChild(embedBtn);
}
linkContainer.appendChild(buttonsContainer);
resultContainer.appendChild(linkContainer);
resultContainer.style.display = 'block';
}
function showEmbedModal(url) {
const embedUrl = `${window.location.origin}/embed?url=${encodeURIComponent(window.location.origin + url)}&thumbnail=${encodeURIComponent('https://coollsd-fileuploader.hf.space/rbxg/LdnShkhZFgMlMmCwkeX78RqHbiol6r554v5BryQS9upEC1wu/Untitled.png')}`;
embedLinkInput.value = embedUrl;
modal.style.display = "block";
}
function copyEmbedLink() {
embedLinkInput.select();
document.execCommand('copy');
alert('Embed link copied to clipboard!');
}
function saveToHistory(fileName, url) {
let history = JSON.parse(localStorage.getItem('uploadHistory')) || [];
history.unshift({ fileName, url, timestamp: new Date().toISOString() });
if (history.length > 500) history = history.slice(0, 500);
localStorage.setItem('uploadHistory', JSON.stringify(history));
}
function showHistory() {
const history = JSON.parse(localStorage.getItem('uploadHistory')) || [];
historyList.innerHTML = '';
history.forEach(item => {
const historyItem = document.createElement('div');
historyItem.className = 'history-item';
const itemName = document.createElement('span');
itemName.className = 'history-item-name';
itemName.textContent = item.fileName;
historyItem.appendChild(itemName);
const actionsContainer = document.createElement('div');
actionsContainer.className = 'history-item-actions';
const copyBtn = document.createElement('button');
copyBtn.textContent = 'Copy Link';
copyBtn.className = 'small-btn';
copyBtn.onclick = () => {
navigator.clipboard.writeText(window.location.origin + item.url).then(() => {
alert('Link copied to clipboard!');
});
};
actionsContainer.appendChild(copyBtn);
const openBtn = document.createElement('button');
openBtn.textContent = 'Open';
openBtn.className = 'small-btn';
openBtn.onclick = () => {
window.open(window.location.origin + item.url, '_blank');
};
actionsContainer.appendChild(openBtn);
if (item.fileName.toLowerCase().endsWith('.mp4')) {
const embedBtn = document.createElement('button');
embedBtn.textContent = 'Embed';
embedBtn.className = 'small-btn';
embedBtn.onclick = () => {
showEmbedModal(item.url);
historyModal.style.display = "none";
};
actionsContainer.appendChild(embedBtn);
}
const encryptBtn = document.createElement('button');
encryptBtn.textContent = 'Encrypt';
encryptBtn.className = 'small-btn';
encryptBtn.onclick = () => {
const encryptedUrl = encryptUrl(item.url);
navigator.clipboard.writeText(window.location.origin + '/encrypted/' + encryptedUrl).then(() => {
alert('Encrypted link copied to clipboard!');
});
};
actionsContainer.appendChild(encryptBtn);
historyItem.appendChild(actionsContainer);
historyList.appendChild(historyItem);
});
historyModal.style.display = "block";
}
function encryptUrl(url) {
const key = 'your-secret-key'; // Replace with a secure key
const encodedUrl = btoa(url);
return encodedUrl.split('').reverse().join('');
}
</script>
</body>
</html>
"""
@app.get("/", response_class=HTMLResponse)
async def index():
return HTML_CONTENT
@app.post("/upload")
async def handle_upload(file: UploadFile = File(...)):
if not file.filename:
return JSONResponse(content={"error": "No file selected."}, status_code=400)
cookies = await get_cookies()
if 'csrftoken' not in cookies or 'sessionid' not in cookies:
return JSONResponse(content={"error": "Failed to obtain necessary cookies"}, status_code=500)
upload_result = await initiate_upload(cookies, file.filename, file.content_type)
if not upload_result or 'upload_url' not in upload_result:
return JSONResponse(content={"error": "Failed to initiate upload"}, status_code=500)
file_content = await file.read()
upload_success = await retry_upload(upload_result['upload_url'], file_content, file.content_type)
if not upload_success:
return JSONResponse(content={"error": "File upload failed after multiple attempts"}, status_code=500)
original_url = upload_result['serving_url']
mirrored_url = f"/rbxg/{original_url.split('/pbxt/')[1]}"
return JSONResponse(content={"url": mirrored_url})
@app.get("/rbxg/{path:path}")
async def handle_video_stream(path: str, request: Request):
original_url = f'https://replicate.delivery/pbxt/{path}'
range_header = request.headers.get('Range')
headers = {'Range': range_header} if range_header else {}
response = requests.get(original_url, headers=headers, stream=True)
def generate():
for chunk in response.iter_content(chunk_size=8192):
yield chunk
headers = dict(response.headers)
headers['Access-Control-Allow-Origin'] = '*'
headers['Content-Disposition'] = 'inline'
if response.status_code == 206:
headers['Content-Range'] = response.headers.get('Content-Range')
return StreamingResponse(generate(), status_code=response.status_code, headers=headers)
@app.get("/encrypt")
async def encrypt_url(request: Request, url: str):
session = request.session
session_id = secrets.token_urlsafe(16)
session[session_id] = url
encrypted_url = fernet.encrypt(f"{session_id}:{url}".encode()).decode()
return JSONResponse(content={"encrypted_url": f"/encrypted/{encrypted_url}"})
@app.get("/encrypted/{encrypted_url}")
async def handle_encrypted_url(encrypted_url: str, request: Request):
try:
decrypted = fernet.decrypt(encrypted_url.encode()).decode()
session_id, original_url = decrypted.split(':', 1)
if session_id not in request.session or request.session[session_id] != original_url:
raise HTTPException(status_code=403, detail="Invalid or expired encrypted URL")
if '/pbxt/' not in original_url:
raise HTTPException(status_code=400, detail="Invalid URL format")
path = original_url.split('/pbxt/')[1]
return await handle_video_stream(path, request)
except Exception as e:
raise HTTPException(status_code=400, detail="Invalid encrypted URL")
async def get_cookies() -> Dict[str, str]:
try:
response = requests.get('https://replicate.com/levelsio/neon-tokyo', headers={
'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'
})
return dict(response.cookies)
except Exception as e:
print(f'Error fetching the page: {e}')
return {}
async def initiate_upload(cookies: Dict[str, str], filename: str, content_type: str) -> Dict:
url = f'https://replicate.com/api/upload/{filename}?content_type={content_type}'
try:
response = requests.post(url, cookies=cookies, headers={
'X-CSRFToken': cookies.get('csrftoken'),
'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',
'Referer': 'https://replicate.com/levelsio/neon-tokyo',
'Origin': 'https://replicate.com',
'Accept': '*/*',
'Accept-Language': 'en-US,en;q=0.5',
'Accept-Encoding': 'identity',
'Sec-Fetch-Dest': 'empty',
'Sec-Fetch-Mode': 'cors',
'Sec-Fetch-Site': 'same-origin',
'Sec-GPC': '1',
'Priority': 'u=1, i'
})
return response.json()
except Exception as e:
print(f'Error initiating upload: {e}')
raise
async def upload_file(upload_url: str, file_content: bytes, content_type: str) -> bool:
try:
response = requests.put(upload_url, data=file_content, headers={'Content-Type': content_type})
return response.status_code == 200
except Exception as e:
print(f'Error uploading file: {e}')
return False
async def retry_upload(upload_url: str, file_content: bytes, content_type: str, max_retries: int = 5, delay: int = 1) -> bool:
while True:
try:
success = await upload_file(upload_url, file_content, content_type)
if success:
return True
print("Upload failed. Retrying...")
except Exception as e:
print(f"Error during upload: {e}")
await asyncio.sleep(delay)
delay = min(delay * 2, 60) # Exponential backoff, capped at 60 seconds
return False
if __name__ == "__main__":
import uvicorn
uvicorn.run(app, host="0.0.0.0", port=7860)