Spaces:
Paused
Paused
Update app.py
Browse files
app.py
CHANGED
|
@@ -1,12 +1,9 @@
|
|
| 1 |
-
from fastapi import FastAPI, File, UploadFile, Request
|
| 2 |
-
from fastapi.responses import HTMLResponse, JSONResponse, StreamingResponse
|
| 3 |
import requests
|
| 4 |
import time
|
| 5 |
import asyncio
|
| 6 |
from typing import Dict
|
| 7 |
-
import base64
|
| 8 |
-
import hashlib
|
| 9 |
-
from cryptography.fernet import Fernet
|
| 10 |
|
| 11 |
app = FastAPI()
|
| 12 |
|
|
@@ -409,7 +406,41 @@ HTML_CONTENT = """
|
|
| 409 |
gap: 5px;
|
| 410 |
}
|
| 411 |
|
| 412 |
-
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 413 |
.container {
|
| 414 |
padding: 1.5rem;
|
| 415 |
}
|
|
@@ -428,7 +459,7 @@ HTML_CONTENT = """
|
|
| 428 |
font-size: 0.7rem;
|
| 429 |
}
|
| 430 |
|
| 431 |
-
|
| 432 |
width: 95%;
|
| 433 |
margin: 5% auto;
|
| 434 |
padding: 15px;
|
|
@@ -474,6 +505,11 @@ HTML_CONTENT = """
|
|
| 474 |
right: 10px;
|
| 475 |
font-size: 24px;
|
| 476 |
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 477 |
}
|
| 478 |
</style>
|
| 479 |
</head>
|
|
@@ -518,6 +554,13 @@ HTML_CONTENT = """
|
|
| 518 |
</div>
|
| 519 |
</div>
|
| 520 |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 521 |
<script>
|
| 522 |
const fileInput = document.getElementById('file');
|
| 523 |
const fileName = document.getElementById('fileName');
|
|
@@ -528,11 +571,13 @@ HTML_CONTENT = """
|
|
| 528 |
const dropZone = document.getElementById('dropZone');
|
| 529 |
const modal = document.getElementById('embedModal');
|
| 530 |
const historyModal = document.getElementById('historyModal');
|
|
|
|
| 531 |
const span = document.getElementsByClassName("close");
|
| 532 |
const embedLinkInput = document.getElementById('embedLink');
|
| 533 |
const uploadBtn = document.getElementById('uploadBtn');
|
| 534 |
const historyBtn = document.getElementById('historyBtn');
|
| 535 |
const historyList = document.getElementById('historyList');
|
|
|
|
| 536 |
|
| 537 |
fileInput.addEventListener('change', handleFileSelect);
|
| 538 |
|
|
@@ -577,6 +622,10 @@ HTML_CONTENT = """
|
|
| 577 |
historyModal.style.display = "none";
|
| 578 |
}
|
| 579 |
|
|
|
|
|
|
|
|
|
|
|
|
|
| 580 |
window.onclick = function(event) {
|
| 581 |
if (event.target == modal) {
|
| 582 |
modal.style.display = "none";
|
|
@@ -584,6 +633,9 @@ HTML_CONTENT = """
|
|
| 584 |
if (event.target == historyModal) {
|
| 585 |
historyModal.style.display = "none";
|
| 586 |
}
|
|
|
|
|
|
|
|
|
|
| 587 |
}
|
| 588 |
|
| 589 |
historyBtn.onclick = function() {
|
|
@@ -723,17 +775,6 @@ HTML_CONTENT = """
|
|
| 723 |
buttonsContainer.appendChild(embedBtn);
|
| 724 |
}
|
| 725 |
|
| 726 |
-
const encryptBtn = document.createElement('button');
|
| 727 |
-
encryptBtn.textContent = 'Encrypt Link';
|
| 728 |
-
encryptBtn.className = 'small-btn encrypt-btn';
|
| 729 |
-
encryptBtn.onclick = () => {
|
| 730 |
-
const encryptedUrl = encryptUrl(url);
|
| 731 |
-
navigator.clipboard.writeText(encryptedUrl).then(() => {
|
| 732 |
-
alert('Encrypted link copied to clipboard!');
|
| 733 |
-
});
|
| 734 |
-
};
|
| 735 |
-
buttonsContainer.appendChild(encryptBtn);
|
| 736 |
-
|
| 737 |
linkContainer.appendChild(buttonsContainer);
|
| 738 |
|
| 739 |
resultContainer.appendChild(linkContainer);
|
|
@@ -792,6 +833,14 @@ HTML_CONTENT = """
|
|
| 792 |
};
|
| 793 |
actionsContainer.appendChild(openBtn);
|
| 794 |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 795 |
if (item.fileName.toLowerCase().endsWith('.mp4')) {
|
| 796 |
const embedBtn = document.createElement('button');
|
| 797 |
embedBtn.textContent = 'Embed';
|
|
@@ -803,32 +852,54 @@ HTML_CONTENT = """
|
|
| 803 |
actionsContainer.appendChild(embedBtn);
|
| 804 |
}
|
| 805 |
|
| 806 |
-
const encryptBtn = document.createElement('button');
|
| 807 |
-
encryptBtn.textContent = 'Encrypt';
|
| 808 |
-
encryptBtn.className = 'small-btn';
|
| 809 |
-
encryptBtn.onclick = () => {
|
| 810 |
-
const encryptedUrl = encryptUrl(item.url);
|
| 811 |
-
navigator.clipboard.writeText(encryptedUrl).then(() => {
|
| 812 |
-
alert('Encrypted link copied to clipboard!');
|
| 813 |
-
});
|
| 814 |
-
};
|
| 815 |
-
actionsContainer.appendChild(encryptBtn);
|
| 816 |
-
|
| 817 |
historyItem.appendChild(actionsContainer);
|
| 818 |
historyList.appendChild(historyItem);
|
| 819 |
});
|
| 820 |
historyModal.style.display = "block";
|
| 821 |
}
|
| 822 |
|
| 823 |
-
|
| 824 |
-
|
| 825 |
-
const
|
| 826 |
-
|
| 827 |
-
|
| 828 |
-
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 829 |
}
|
| 830 |
</script>
|
| 831 |
-
<script src="https://cdnjs.cloudflare.com/ajax/libs/crypto-js/4.1.1/crypto-js.min.js"></script>
|
| 832 |
</body>
|
| 833 |
</html>
|
| 834 |
"""
|
|
@@ -881,23 +952,6 @@ async def handle_video_stream(path: str, request: Request):
|
|
| 881 |
|
| 882 |
return StreamingResponse(generate(), status_code=response.status_code, headers=headers)
|
| 883 |
|
| 884 |
-
@app.get("/e/{encrypted_data}")
|
| 885 |
-
async def handle_encrypted_stream(encrypted_data: str, request: Request):
|
| 886 |
-
try:
|
| 887 |
-
browser_info = request.headers.get('User-Agent', '') + request.headers.get('Accept-Language', '') + str(request.client.host)
|
| 888 |
-
key = hashlib.sha256(browser_info.encode()).hexdigest()[:32].encode()
|
| 889 |
-
fernet = Fernet(base64.urlsafe_b64encode(key))
|
| 890 |
-
|
| 891 |
-
decrypted_url = fernet.decrypt(encrypted_data.encode()).decode()
|
| 892 |
-
|
| 893 |
-
if not decrypted_url.startswith('/rbxg/'):
|
| 894 |
-
raise ValueError("Invalid decrypted URL")
|
| 895 |
-
|
| 896 |
-
path = decrypted_url.split('/rbxg/')[1]
|
| 897 |
-
return await handle_video_stream(path, request)
|
| 898 |
-
except Exception as e:
|
| 899 |
-
raise HTTPException(status_code=400, detail="Invalid or expired link")
|
| 900 |
-
|
| 901 |
@app.get("/embed")
|
| 902 |
async def embed_video(url: str, thumbnail: str):
|
| 903 |
html = f'''
|
|
@@ -980,7 +1034,7 @@ async def upload_file(upload_url: str, file_content: bytes, content_type: str) -
|
|
| 980 |
return False
|
| 981 |
|
| 982 |
async def retry_upload(upload_url: str, file_content: bytes, content_type: str, max_retries: int = 5, delay: int = 1) -> bool:
|
| 983 |
-
|
| 984 |
try:
|
| 985 |
success = await upload_file(upload_url, file_content, content_type)
|
| 986 |
if success:
|
|
@@ -993,7 +1047,3 @@ async def retry_upload(upload_url: str, file_content: bytes, content_type: str,
|
|
| 993 |
delay = min(delay * 2, 60) # Exponential backoff, capped at 60 seconds
|
| 994 |
|
| 995 |
return False
|
| 996 |
-
|
| 997 |
-
if __name__ == "__main__":
|
| 998 |
-
import uvicorn
|
| 999 |
-
uvicorn.run(app, host="0.0.0.0", port=7860)
|
|
|
|
| 1 |
+
from fastapi import FastAPI, File, UploadFile, Request
|
| 2 |
+
from fastapi.responses import HTMLResponse, JSONResponse, StreamingResponse
|
| 3 |
import requests
|
| 4 |
import time
|
| 5 |
import asyncio
|
| 6 |
from typing import Dict
|
|
|
|
|
|
|
|
|
|
| 7 |
|
| 8 |
app = FastAPI()
|
| 9 |
|
|
|
|
| 406 |
gap: 5px;
|
| 407 |
}
|
| 408 |
|
| 409 |
+
.quick-open-modal {
|
| 410 |
+
display: none;
|
| 411 |
+
position: fixed;
|
| 412 |
+
z-index: 4;
|
| 413 |
+
left: 0;
|
| 414 |
+
top: 0;
|
| 415 |
+
width: 100%;
|
| 416 |
+
height: 100%;
|
| 417 |
+
background-color: rgba(0,0,0,0.9);
|
| 418 |
+
overflow: auto;
|
| 419 |
+
}
|
| 420 |
+
|
| 421 |
+
.quick-open-content {
|
| 422 |
+
margin: 5% auto;
|
| 423 |
+
padding: 20px;
|
| 424 |
+
width: 90%;
|
| 425 |
+
max-width: 800px;
|
| 426 |
+
text-align: center;
|
| 427 |
+
}
|
| 428 |
+
|
| 429 |
+
.quick-open-content img,
|
| 430 |
+
.quick-open-content video,
|
| 431 |
+
.quick-open-content audio {
|
| 432 |
+
max-width: 100%;
|
| 433 |
+
max-height: 70vh;
|
| 434 |
+
margin-bottom: 20px;
|
| 435 |
+
}
|
| 436 |
+
|
| 437 |
+
.quick-open-content iframe {
|
| 438 |
+
width: 100%;
|
| 439 |
+
height: 70vh;
|
| 440 |
+
border: none;
|
| 441 |
+
}
|
| 442 |
+
|
| 443 |
+
@media (max-width: 480px) {
|
| 444 |
.container {
|
| 445 |
padding: 1.5rem;
|
| 446 |
}
|
|
|
|
| 459 |
font-size: 0.7rem;
|
| 460 |
}
|
| 461 |
|
| 462 |
+
.modal-content, .history-modal-content {
|
| 463 |
width: 95%;
|
| 464 |
margin: 5% auto;
|
| 465 |
padding: 15px;
|
|
|
|
| 505 |
right: 10px;
|
| 506 |
font-size: 24px;
|
| 507 |
}
|
| 508 |
+
|
| 509 |
+
.quick-open-content {
|
| 510 |
+
margin: 10% auto;
|
| 511 |
+
padding: 10px;
|
| 512 |
+
}
|
| 513 |
}
|
| 514 |
</style>
|
| 515 |
</head>
|
|
|
|
| 554 |
</div>
|
| 555 |
</div>
|
| 556 |
|
| 557 |
+
<div id="quickOpenModal" class="quick-open-modal">
|
| 558 |
+
<div class="quick-open-content">
|
| 559 |
+
<span class="close">×</span>
|
| 560 |
+
<div id="quickOpenContent"></div>
|
| 561 |
+
</div>
|
| 562 |
+
</div>
|
| 563 |
+
|
| 564 |
<script>
|
| 565 |
const fileInput = document.getElementById('file');
|
| 566 |
const fileName = document.getElementById('fileName');
|
|
|
|
| 571 |
const dropZone = document.getElementById('dropZone');
|
| 572 |
const modal = document.getElementById('embedModal');
|
| 573 |
const historyModal = document.getElementById('historyModal');
|
| 574 |
+
const quickOpenModal = document.getElementById('quickOpenModal');
|
| 575 |
const span = document.getElementsByClassName("close");
|
| 576 |
const embedLinkInput = document.getElementById('embedLink');
|
| 577 |
const uploadBtn = document.getElementById('uploadBtn');
|
| 578 |
const historyBtn = document.getElementById('historyBtn');
|
| 579 |
const historyList = document.getElementById('historyList');
|
| 580 |
+
const quickOpenContent = document.getElementById('quickOpenContent');
|
| 581 |
|
| 582 |
fileInput.addEventListener('change', handleFileSelect);
|
| 583 |
|
|
|
|
| 622 |
historyModal.style.display = "none";
|
| 623 |
}
|
| 624 |
|
| 625 |
+
span[2].onclick = function() {
|
| 626 |
+
quickOpenModal.style.display = "none";
|
| 627 |
+
}
|
| 628 |
+
|
| 629 |
window.onclick = function(event) {
|
| 630 |
if (event.target == modal) {
|
| 631 |
modal.style.display = "none";
|
|
|
|
| 633 |
if (event.target == historyModal) {
|
| 634 |
historyModal.style.display = "none";
|
| 635 |
}
|
| 636 |
+
if (event.target == quickOpenModal) {
|
| 637 |
+
quickOpenModal.style.display = "none";
|
| 638 |
+
}
|
| 639 |
}
|
| 640 |
|
| 641 |
historyBtn.onclick = function() {
|
|
|
|
| 775 |
buttonsContainer.appendChild(embedBtn);
|
| 776 |
}
|
| 777 |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 778 |
linkContainer.appendChild(buttonsContainer);
|
| 779 |
|
| 780 |
resultContainer.appendChild(linkContainer);
|
|
|
|
| 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';
|
|
|
|
| 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 |
+
|
| 865 |
+
if (fileName.match(/\.(jpeg|jpg|gif|png)$/i)) {
|
| 866 |
+
const img = document.createElement('img');
|
| 867 |
+
img.src = fullUrl;
|
| 868 |
+
img.alt = fileName;
|
| 869 |
+
quickOpenContent.appendChild(img);
|
| 870 |
+
} else if (fileName.toLowerCase().endsWith('.mp4')) {
|
| 871 |
+
const video = document.createElement('video');
|
| 872 |
+
video.src = fullUrl;
|
| 873 |
+
video.controls = true;
|
| 874 |
+
quickOpenContent.appendChild(video);
|
| 875 |
+
} else if (fileName.toLowerCase().endsWith('.mp3')) {
|
| 876 |
+
const audio = document.createElement('audio');
|
| 877 |
+
audio.src = fullUrl;
|
| 878 |
+
audio.controls = true;
|
| 879 |
+
quickOpenContent.appendChild(audio);
|
| 880 |
+
} else if (fileName.toLowerCase().endsWith('.pdf')) {
|
| 881 |
+
const iframe = document.createElement('iframe');
|
| 882 |
+
iframe.src = fullUrl;
|
| 883 |
+
quickOpenContent.appendChild(iframe);
|
| 884 |
+
} else if (fileName.toLowerCase().endsWith('.txt')) {
|
| 885 |
+
fetch(fullUrl)
|
| 886 |
+
.then(response => response.text())
|
| 887 |
+
.then(text => {
|
| 888 |
+
const pre = document.createElement('pre');
|
| 889 |
+
pre.textContent = text;
|
| 890 |
+
quickOpenContent.appendChild(pre);
|
| 891 |
+
});
|
| 892 |
+
} else {
|
| 893 |
+
const link = document.createElement('a');
|
| 894 |
+
link.href = fullUrl;
|
| 895 |
+
link.textContent = 'Download ' + fileName;
|
| 896 |
+
link.target = '_blank';
|
| 897 |
+
quickOpenContent.appendChild(link);
|
| 898 |
+
}
|
| 899 |
+
|
| 900 |
+
quickOpenModal.style.display = "block";
|
| 901 |
}
|
| 902 |
</script>
|
|
|
|
| 903 |
</body>
|
| 904 |
</html>
|
| 905 |
"""
|
|
|
|
| 952 |
|
| 953 |
return StreamingResponse(generate(), status_code=response.status_code, headers=headers)
|
| 954 |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 955 |
@app.get("/embed")
|
| 956 |
async def embed_video(url: str, thumbnail: str):
|
| 957 |
html = f'''
|
|
|
|
| 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
|
|
|
|
|
|
|
|
|
|
|
|