Spaces:
Running
Running
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
|
|
|
|
|
|
|
|