Spaces:
Running
Running
Update app.py
Browse files
app.py
CHANGED
@@ -385,7 +385,7 @@ HTML_CONTENT = """
|
|
385 |
<div class="loading-spinner" id="loadingSpinner"></div>
|
386 |
</form>
|
387 |
<div class="result-container" id="resultContainer"></div>
|
388 |
-
|
389 |
Allowed file types: .zip, .mp4, .txt, .mp3, all image types, .pdf
|
390 |
</div>
|
391 |
</div>
|
@@ -409,7 +409,7 @@ HTML_CONTENT = """
|
|
409 |
const progressContainer = document.getElementById('progressContainer');
|
410 |
const loadingSpinner = document.getElementById('loadingSpinner');
|
411 |
const resultContainer = document.getElementById('resultContainer');
|
412 |
-
|
413 |
const modal = document.getElementById('embedModal');
|
414 |
const span = document.getElementsByClassName("close")[0];
|
415 |
const embedLinkInput = document.getElementById('embedLink');
|
@@ -486,45 +486,39 @@ HTML_CONTENT = """
|
|
486 |
const formData = new FormData();
|
487 |
formData.append('file', file);
|
488 |
|
489 |
-
let
|
490 |
-
const
|
491 |
-
const
|
|
|
|
|
|
|
|
|
492 |
|
493 |
-
while (retries < maxRetries) {
|
494 |
try {
|
495 |
-
const
|
496 |
-
|
497 |
-
|
498 |
-
|
499 |
-
|
500 |
-
|
501 |
-
if (xhr.status === 200) {
|
502 |
-
const response = JSON.parse(xhr.responseText);
|
503 |
-
if (response.url) {
|
504 |
-
resolve(response.url);
|
505 |
-
} else {
|
506 |
-
reject(new Error('Upload failed: ' + response.error));
|
507 |
-
}
|
508 |
-
} else {
|
509 |
-
reject(new Error(`HTTP error! status: ${xhr.status}`));
|
510 |
-
}
|
511 |
-
};
|
512 |
-
xhr.onerror = () => reject(new Error('Network error occurred'));
|
513 |
});
|
514 |
|
515 |
-
|
|
|
|
|
516 |
|
517 |
-
const
|
518 |
-
|
519 |
-
|
520 |
-
} catch (error) {
|
521 |
-
console.error('Upload error:', error);
|
522 |
-
retries++;
|
523 |
-
if (retries >= maxRetries) {
|
524 |
-
alert('Upload failed after multiple attempts: ' + error.message);
|
525 |
break;
|
526 |
}
|
527 |
-
|
|
|
|
|
|
|
|
|
|
|
|
|
528 |
}
|
529 |
}
|
530 |
|
@@ -547,11 +541,9 @@ HTML_CONTENT = """
|
|
547 |
return container;
|
548 |
}
|
549 |
|
550 |
-
function updateProgress(
|
551 |
-
|
552 |
-
|
553 |
-
progressBar.style.width = percentComplete + '%';
|
554 |
-
}
|
555 |
}
|
556 |
|
557 |
function resetUploadState() {
|
@@ -624,7 +616,14 @@ async def index():
|
|
624 |
return HTML_CONTENT
|
625 |
|
626 |
@app.post("/upload")
|
627 |
-
async def handle_upload(file: UploadFile = File(...)):
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
628 |
if not file:
|
629 |
raise HTTPException(status_code=400, detail="No file part")
|
630 |
if file.filename == '':
|
@@ -634,19 +633,25 @@ async def handle_upload(file: UploadFile = File(...)):
|
|
634 |
if 'csrftoken' not in cookies or 'sessionid' not in cookies:
|
635 |
raise HTTPException(status_code=500, detail="Failed to obtain necessary cookies")
|
636 |
|
637 |
-
|
638 |
-
|
639 |
-
|
|
|
|
|
|
|
640 |
|
641 |
file_content = await file.read()
|
642 |
-
upload_success = await
|
643 |
if not upload_success:
|
644 |
-
raise HTTPException(status_code=500, detail="
|
645 |
-
|
646 |
-
original_url = upload_result['serving_url']
|
647 |
-
mirrored_url = f"/rbxg/{original_url.split('/pbxt/')[1]}"
|
648 |
|
649 |
-
|
|
|
|
|
|
|
|
|
|
|
|
|
650 |
|
651 |
@app.get("/rbxg/{path:path}")
|
652 |
async def handle_video_stream(path: str, request: Request):
|
@@ -742,12 +747,16 @@ async def initiate_upload(cookies: Dict[str, str], filename: str, content_type:
|
|
742 |
print(f'Error initiating upload: {e}')
|
743 |
raise
|
744 |
|
745 |
-
async def
|
746 |
try:
|
747 |
-
|
748 |
-
|
|
|
|
|
|
|
|
|
749 |
except Exception as e:
|
750 |
-
print(f'Error uploading
|
751 |
return False
|
752 |
|
753 |
async def retry_upload(upload_url: str, file_content: bytes, content_type: str, max_retries: int = 5, delay: int = 1) -> bool:
|
@@ -765,4 +774,12 @@ async def retry_upload(upload_url: str, file_content: bytes, content_type: str,
|
|
765 |
await asyncio.sleep(delay)
|
766 |
delay = min(delay * 2, 60) # Exponential backoff, capped at 60 seconds
|
767 |
|
768 |
-
return False
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
385 |
<div class="loading-spinner" id="loadingSpinner"></div>
|
386 |
</form>
|
387 |
<div class="result-container" id="resultContainer"></div>
|
388 |
+
<div class="file-types">
|
389 |
Allowed file types: .zip, .mp4, .txt, .mp3, all image types, .pdf
|
390 |
</div>
|
391 |
</div>
|
|
|
409 |
const progressContainer = document.getElementById('progressContainer');
|
410 |
const loadingSpinner = document.getElementById('loadingSpinner');
|
411 |
const resultContainer = document.getElementById('resultContainer');
|
412 |
+
const dropZone = document.getElementById('dropZone');
|
413 |
const modal = document.getElementById('embedModal');
|
414 |
const span = document.getElementsByClassName("close")[0];
|
415 |
const embedLinkInput = document.getElementById('embedLink');
|
|
|
486 |
const formData = new FormData();
|
487 |
formData.append('file', file);
|
488 |
|
489 |
+
let uploadedBytes = 0;
|
490 |
+
const chunkSize = 1024 * 1024; // 1MB chunks
|
491 |
+
const totalSize = file.size;
|
492 |
+
|
493 |
+
while (uploadedBytes < totalSize) {
|
494 |
+
const chunk = file.slice(uploadedBytes, uploadedBytes + chunkSize);
|
495 |
+
formData.set('file', chunk, file.name);
|
496 |
|
|
|
497 |
try {
|
498 |
+
const response = await fetch('/upload', {
|
499 |
+
method: 'POST',
|
500 |
+
body: formData,
|
501 |
+
headers: {
|
502 |
+
'Content-Range': `bytes ${uploadedBytes}-${uploadedBytes + chunk.size - 1}/${totalSize}`
|
503 |
+
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
504 |
});
|
505 |
|
506 |
+
if (!response.ok) {
|
507 |
+
throw new Error(`HTTP error! status: ${response.status}`);
|
508 |
+
}
|
509 |
|
510 |
+
const result = await response.json();
|
511 |
+
if (result.url) {
|
512 |
+
addResultLink(result.url, file.name);
|
|
|
|
|
|
|
|
|
|
|
513 |
break;
|
514 |
}
|
515 |
+
|
516 |
+
uploadedBytes += chunk.size;
|
517 |
+
updateProgress(uploadedBytes, totalSize, progressBar.querySelector('.progress'));
|
518 |
+
} catch (error) {
|
519 |
+
console.error('Upload error:', error);
|
520 |
+
await new Promise(resolve => setTimeout(resolve, 1000)); // Wait 1 second before retrying
|
521 |
+
// The loop will continue from where it left off
|
522 |
}
|
523 |
}
|
524 |
|
|
|
541 |
return container;
|
542 |
}
|
543 |
|
544 |
+
function updateProgress(uploadedBytes, totalBytes, progressBar) {
|
545 |
+
const percentComplete = (uploadedBytes / totalBytes) * 100;
|
546 |
+
progressBar.style.width = percentComplete + '%';
|
|
|
|
|
547 |
}
|
548 |
|
549 |
function resetUploadState() {
|
|
|
616 |
return HTML_CONTENT
|
617 |
|
618 |
@app.post("/upload")
|
619 |
+
async def handle_upload(file: UploadFile = File(...), request: Request):
|
620 |
+
content_range = request.headers.get('Content-Range')
|
621 |
+
if not content_range:
|
622 |
+
raise HTTPException(status_code=400, detail="Content-Range header is missing")
|
623 |
+
|
624 |
+
_, range_str = content_range.split(' ')
|
625 |
+
start_byte, end_byte, total_size = map(int, range_str.replace('bytes', '').split('-')[0].split('/'))
|
626 |
+
|
627 |
if not file:
|
628 |
raise HTTPException(status_code=400, detail="No file part")
|
629 |
if file.filename == '':
|
|
|
633 |
if 'csrftoken' not in cookies or 'sessionid' not in cookies:
|
634 |
raise HTTPException(status_code=500, detail="Failed to obtain necessary cookies")
|
635 |
|
636 |
+
if start_byte == 0:
|
637 |
+
upload_result = await initiate_upload(cookies, file.filename, file.content_type)
|
638 |
+
if not upload_result or 'upload_url' not in upload_result:
|
639 |
+
raise HTTPException(status_code=500, detail="Failed to initiate upload")
|
640 |
+
else:
|
641 |
+
upload_result = {'upload_url': file.filename} # Use filename as a key to retrieve the upload URL
|
642 |
|
643 |
file_content = await file.read()
|
644 |
+
upload_success = await upload_chunk(upload_result['upload_url'], file_content, start_byte, end_byte, total_size)
|
645 |
if not upload_success:
|
646 |
+
raise HTTPException(status_code=500, detail="Chunk upload failed")
|
|
|
|
|
|
|
647 |
|
648 |
+
if end_byte + 1 >= total_size:
|
649 |
+
original_url = upload_result.get('serving_url')
|
650 |
+
if original_url:
|
651 |
+
mirrored_url = f"/rbxg/{original_url.split('/pbxt/')[1]}"
|
652 |
+
return JSONResponse(content={"url": mirrored_url})
|
653 |
+
|
654 |
+
return JSONResponse(content={"status": "chunk uploaded"})
|
655 |
|
656 |
@app.get("/rbxg/{path:path}")
|
657 |
async def handle_video_stream(path: str, request: Request):
|
|
|
747 |
print(f'Error initiating upload: {e}')
|
748 |
raise
|
749 |
|
750 |
+
async def upload_chunk(upload_url: str, chunk_content: bytes, start_byte: int, end_byte: int, total_size: int) -> bool:
|
751 |
try:
|
752 |
+
headers = {
|
753 |
+
'Content-Type': 'application/octet-stream',
|
754 |
+
'Content-Range': f'bytes {start_byte}-{end_byte}/{total_size}'
|
755 |
+
}
|
756 |
+
response = requests.put(upload_url, data=chunk_content, headers=headers)
|
757 |
+
return response.status_code in [200, 201, 204]
|
758 |
except Exception as e:
|
759 |
+
print(f'Error uploading chunk: {e}')
|
760 |
return False
|
761 |
|
762 |
async def retry_upload(upload_url: str, file_content: bytes, content_type: str, max_retries: int = 5, delay: int = 1) -> bool:
|
|
|
774 |
await asyncio.sleep(delay)
|
775 |
delay = min(delay * 2, 60) # Exponential backoff, capped at 60 seconds
|
776 |
|
777 |
+
return False
|
778 |
+
|
779 |
+
async def upload_file(upload_url: str, file_content: bytes, content_type: str) -> bool:
|
780 |
+
try:
|
781 |
+
response = requests.put(upload_url, data=file_content, headers={'Content-Type': content_type})
|
782 |
+
return response.status_code == 200
|
783 |
+
except Exception as e:
|
784 |
+
print(f'Error uploading file: {e}')
|
785 |
+
return False
|