Spaces:
Running
Running
Update app.py
Browse files
app.py
CHANGED
@@ -1,17 +1,12 @@
|
|
1 |
-
from fastapi import FastAPI, File, UploadFile, Request
|
2 |
from fastapi.responses import HTMLResponse, JSONResponse, StreamingResponse
|
3 |
-
import
|
|
|
4 |
import asyncio
|
5 |
from typing import Dict
|
6 |
-
import io
|
7 |
-
import logging
|
8 |
|
9 |
app = FastAPI()
|
10 |
|
11 |
-
# Set up logging
|
12 |
-
logging.basicConfig(level=logging.INFO)
|
13 |
-
logger = logging.getLogger(__name__)
|
14 |
-
|
15 |
HTML_CONTENT = """
|
16 |
<!DOCTYPE html>
|
17 |
<html lang="en">
|
@@ -428,7 +423,7 @@ HTML_CONTENT = """
|
|
428 |
gap: 5px;
|
429 |
}
|
430 |
|
431 |
-
|
432 |
display: none;
|
433 |
position: fixed;
|
434 |
z-index: 4;
|
@@ -440,7 +435,7 @@ HTML_CONTENT = """
|
|
440 |
overflow: auto;
|
441 |
}
|
442 |
|
443 |
-
|
444 |
margin: 5% auto;
|
445 |
padding: 20px;
|
446 |
width: 90%;
|
@@ -701,28 +696,44 @@ HTML_CONTENT = """
|
|
701 |
const formData = new FormData();
|
702 |
formData.append('file', file);
|
703 |
|
704 |
-
|
705 |
-
|
706 |
-
|
707 |
-
|
708 |
-
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
709 |
|
710 |
-
|
711 |
-
|
712 |
-
|
|
|
|
|
713 |
|
714 |
-
|
715 |
-
|
716 |
-
|
717 |
-
|
718 |
-
|
719 |
-
|
|
|
|
|
|
|
720 |
}
|
721 |
-
} catch (error) {
|
722 |
-
console.error('Upload error:', error);
|
723 |
-
alert('Upload failed. Please try again.');
|
724 |
-
} finally {
|
725 |
-
resetUploadState();
|
726 |
}
|
727 |
}
|
728 |
|
@@ -742,13 +753,19 @@ HTML_CONTENT = """
|
|
742 |
return container;
|
743 |
}
|
744 |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
745 |
function resetUploadState() {
|
746 |
fileInput.value = '';
|
747 |
fileName.textContent = '';
|
748 |
uploadBtn.style.display = 'none';
|
749 |
uploadBtn.disabled = false;
|
750 |
loadingSpinner.style.display = 'none';
|
751 |
-
progressContainer.style.display = 'none';
|
752 |
}
|
753 |
|
754 |
function addResultLink(url, fileName) {
|
@@ -836,7 +853,7 @@ HTML_CONTENT = """
|
|
836 |
};
|
837 |
actionsContainer.appendChild(copyBtn);
|
838 |
|
839 |
-
|
840 |
openBtn.textContent = 'Open';
|
841 |
openBtn.className = 'small-btn';
|
842 |
openBtn.onclick = () => {
|
@@ -869,7 +886,7 @@ HTML_CONTENT = """
|
|
869 |
historyModal.style.display = "block";
|
870 |
}
|
871 |
|
872 |
-
|
873 |
quickOpenContent.innerHTML = '';
|
874 |
const fullUrl = window.location.origin + url;
|
875 |
|
@@ -914,6 +931,7 @@ HTML_CONTENT = """
|
|
914 |
</body>
|
915 |
</html>
|
916 |
"""
|
|
|
917 |
@app.get("/", response_class=HTMLResponse)
|
918 |
async def index():
|
919 |
return HTML_CONTENT
|
@@ -921,28 +939,25 @@ async def index():
|
|
921 |
@app.post("/upload")
|
922 |
async def handle_upload(file: UploadFile = File(...)):
|
923 |
if not file.filename:
|
924 |
-
|
925 |
|
926 |
-
|
927 |
-
|
928 |
-
|
929 |
-
raise HTTPException(status_code=500, detail="Failed to get cookies")
|
930 |
|
931 |
-
|
932 |
-
|
933 |
-
|
934 |
|
935 |
-
|
936 |
-
|
937 |
-
|
|
|
938 |
|
939 |
-
|
940 |
-
|
941 |
|
942 |
-
|
943 |
-
except Exception as e:
|
944 |
-
logger.error(f"Upload error: {str(e)}")
|
945 |
-
raise HTTPException(status_code=500, detail=str(e))
|
946 |
|
947 |
@app.get("/rbxg/{path:path}")
|
948 |
async def handle_video_stream(path: str, request: Request):
|
@@ -950,17 +965,20 @@ async def handle_video_stream(path: str, request: Request):
|
|
950 |
range_header = request.headers.get('Range')
|
951 |
|
952 |
headers = {'Range': range_header} if range_header else {}
|
953 |
-
|
954 |
-
async with session.get(original_url, headers=headers) as response:
|
955 |
-
content = await response.read()
|
956 |
-
headers = dict(response.headers)
|
957 |
-
headers['Access-Control-Allow-Origin'] = '*'
|
958 |
-
headers['Content-Disposition'] = 'inline'
|
959 |
|
960 |
-
|
961 |
-
|
|
|
962 |
|
963 |
-
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
964 |
|
965 |
@app.get("/embed")
|
966 |
async def embed_video(url: str, thumbnail: str):
|
@@ -1004,80 +1022,56 @@ async def embed_video(url: str, thumbnail: str):
|
|
1004 |
return HTMLResponse(content=html)
|
1005 |
|
1006 |
async def get_cookies() -> Dict[str, str]:
|
1007 |
-
|
1008 |
-
|
1009 |
'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'
|
1010 |
-
})
|
1011 |
-
|
|
|
|
|
|
|
1012 |
|
1013 |
async def initiate_upload(cookies: Dict[str, str], filename: str, content_type: str) -> Dict:
|
1014 |
url = f'https://replicate.com/api/upload/{filename}?content_type={content_type}'
|
1015 |
-
|
1016 |
-
|
1017 |
-
|
1018 |
-
|
1019 |
-
|
1020 |
-
|
1021 |
-
|
1022 |
-
|
1023 |
-
|
1024 |
-
|
1025 |
-
|
1026 |
-
|
1027 |
-
|
1028 |
-
|
1029 |
-
|
1030 |
-
|
1031 |
-
|
1032 |
-
|
1033 |
-
|
1034 |
-
|
1035 |
-
async def chunked_upload(upload_url: str, file: UploadFile, content_type: str, chunk_size: int = 1024 * 1024) -> bool:
|
1036 |
-
async with aiohttp.ClientSession() as session:
|
1037 |
-
file_size = await get_file_size(file)
|
1038 |
-
await file.seek(0)
|
1039 |
-
|
1040 |
-
for start in range(0, file_size, chunk_size):
|
1041 |
-
end = min(start + chunk_size, file_size)
|
1042 |
-
chunk = await file.read(end - start)
|
1043 |
-
|
1044 |
-
headers = {
|
1045 |
-
'Content-Type': content_type,
|
1046 |
-
'Content-Range': f'bytes {start}-{end-1}/{file_size}'
|
1047 |
-
}
|
1048 |
|
1049 |
-
|
1050 |
-
|
1051 |
-
|
1052 |
-
|
1053 |
-
|
1054 |
-
|
1055 |
-
|
1056 |
-
|
1057 |
-
|
1058 |
-
|
1059 |
-
|
1060 |
-
|
1061 |
-
|
1062 |
-
|
1063 |
-
|
1064 |
-
|
1065 |
-
|
1066 |
-
|
1067 |
-
|
1068 |
-
|
1069 |
-
|
1070 |
-
|
1071 |
-
|
1072 |
-
return True
|
1073 |
-
|
1074 |
-
async def get_file_size(file: UploadFile) -> int:
|
1075 |
-
size = 0
|
1076 |
-
while chunk := await file.read(8192):
|
1077 |
-
size += len(chunk)
|
1078 |
-
await file.seek(0)
|
1079 |
-
return size
|
1080 |
-
|
1081 |
-
if __name__ == "__main__":
|
1082 |
-
import uvicorn
|
1083 |
-
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 |
|
|
|
|
|
|
|
|
|
10 |
HTML_CONTENT = """
|
11 |
<!DOCTYPE html>
|
12 |
<html lang="en">
|
|
|
423 |
gap: 5px;
|
424 |
}
|
425 |
|
426 |
+
.quick-open-modal {
|
427 |
display: none;
|
428 |
position: fixed;
|
429 |
z-index: 4;
|
|
|
435 |
overflow: auto;
|
436 |
}
|
437 |
|
438 |
+
.quick-open-content {
|
439 |
margin: 5% auto;
|
440 |
padding: 20px;
|
441 |
width: 90%;
|
|
|
696 |
const formData = new FormData();
|
697 |
formData.append('file', file);
|
698 |
|
699 |
+
while (true) {
|
700 |
+
try {
|
701 |
+
const xhr = new XMLHttpRequest();
|
702 |
+
xhr.open('POST', '/upload', true);
|
703 |
+
xhr.upload.onprogress = (event) => updateProgress(event, progressBar.querySelector('.progress'));
|
704 |
+
|
705 |
+
xhr.onload = function() {
|
706 |
+
if (xhr.status === 200) {
|
707 |
+
const response = JSON.parse(xhr.responseText);
|
708 |
+
if (response.url) {
|
709 |
+
addResultLink(response.url, file.name);
|
710 |
+
saveToHistory(file.name, response.url);
|
711 |
+
resetUploadState();
|
712 |
+
return;
|
713 |
+
} else {
|
714 |
+
throw new Error('Upload failed: ' + response.error);
|
715 |
+
}
|
716 |
+
} else {
|
717 |
+
throw new Error(`HTTP error! status: ${xhr.status}`);
|
718 |
+
}
|
719 |
+
};
|
720 |
|
721 |
+
xhr.onerror = function() {
|
722 |
+
throw new Error('Network error occurred');
|
723 |
+
};
|
724 |
+
|
725 |
+
xhr.send(formData);
|
726 |
|
727 |
+
await new Promise((resolve, reject) => {
|
728 |
+
xhr.onloadend = resolve;
|
729 |
+
xhr.onerror = reject;
|
730 |
+
});
|
731 |
+
|
732 |
+
break;
|
733 |
+
} catch (error) {
|
734 |
+
console.error('Upload error:', error);
|
735 |
+
await new Promise(resolve => setTimeout(resolve, 1000));
|
736 |
}
|
|
|
|
|
|
|
|
|
|
|
737 |
}
|
738 |
}
|
739 |
|
|
|
753 |
return container;
|
754 |
}
|
755 |
|
756 |
+
function updateProgress(event, progressBar) {
|
757 |
+
if (event.lengthComputable) {
|
758 |
+
const percentComplete = (event.loaded / event.total) * 100;
|
759 |
+
progressBar.style.width = percentComplete + '%';
|
760 |
+
}
|
761 |
+
}
|
762 |
+
|
763 |
function resetUploadState() {
|
764 |
fileInput.value = '';
|
765 |
fileName.textContent = '';
|
766 |
uploadBtn.style.display = 'none';
|
767 |
uploadBtn.disabled = false;
|
768 |
loadingSpinner.style.display = 'none';
|
|
|
769 |
}
|
770 |
|
771 |
function addResultLink(url, fileName) {
|
|
|
853 |
};
|
854 |
actionsContainer.appendChild(copyBtn);
|
855 |
|
856 |
+
const openBtn = document.createElement('button');
|
857 |
openBtn.textContent = 'Open';
|
858 |
openBtn.className = 'small-btn';
|
859 |
openBtn.onclick = () => {
|
|
|
886 |
historyModal.style.display = "block";
|
887 |
}
|
888 |
|
889 |
+
function quickOpen(url, fileName) {
|
890 |
quickOpenContent.innerHTML = '';
|
891 |
const fullUrl = window.location.origin + url;
|
892 |
|
|
|
931 |
</body>
|
932 |
</html>
|
933 |
"""
|
934 |
+
|
935 |
@app.get("/", response_class=HTMLResponse)
|
936 |
async def index():
|
937 |
return HTML_CONTENT
|
|
|
939 |
@app.post("/upload")
|
940 |
async def handle_upload(file: UploadFile = File(...)):
|
941 |
if not file.filename:
|
942 |
+
return JSONResponse(content={"error": "No file selected."}, status_code=400)
|
943 |
|
944 |
+
cookies = await get_cookies()
|
945 |
+
if 'csrftoken' not in cookies or 'sessionid' not in cookies:
|
946 |
+
return JSONResponse(content={"error": "Failed"}, status_code=500)
|
|
|
947 |
|
948 |
+
upload_result = await initiate_upload(cookies, file.filename, file.content_type)
|
949 |
+
if not upload_result or 'upload_url' not in upload_result:
|
950 |
+
return JSONResponse(content={"error": "Failed to upload"}, status_code=500)
|
951 |
|
952 |
+
file_content = await file.read()
|
953 |
+
upload_success = await retry_upload(upload_result['upload_url'], file_content, file.content_type)
|
954 |
+
if not upload_success:
|
955 |
+
return JSONResponse(content={"error": "FAILED GOD MAN AFTER alot of attempts"}, status_code=500)
|
956 |
|
957 |
+
original_url = upload_result['serving_url']
|
958 |
+
mirrored_url = f"/rbxg/{original_url.split('/pbxt/')[1]}"
|
959 |
|
960 |
+
return JSONResponse(content={"url": mirrored_url})
|
|
|
|
|
|
|
961 |
|
962 |
@app.get("/rbxg/{path:path}")
|
963 |
async def handle_video_stream(path: str, request: Request):
|
|
|
965 |
range_header = request.headers.get('Range')
|
966 |
|
967 |
headers = {'Range': range_header} if range_header else {}
|
968 |
+
response = requests.get(original_url, headers=headers, stream=True)
|
|
|
|
|
|
|
|
|
|
|
969 |
|
970 |
+
def generate():
|
971 |
+
for chunk in response.iter_content(chunk_size=8192):
|
972 |
+
yield chunk
|
973 |
|
974 |
+
headers = dict(response.headers)
|
975 |
+
headers['Access-Control-Allow-Origin'] = '*'
|
976 |
+
headers['Content-Disposition'] = 'inline'
|
977 |
+
|
978 |
+
if response.status_code == 206:
|
979 |
+
headers['Content-Range'] = response.headers.get('Content-Range')
|
980 |
+
|
981 |
+
return StreamingResponse(generate(), status_code=response.status_code, headers=headers)
|
982 |
|
983 |
@app.get("/embed")
|
984 |
async def embed_video(url: str, thumbnail: str):
|
|
|
1022 |
return HTMLResponse(content=html)
|
1023 |
|
1024 |
async def get_cookies() -> Dict[str, str]:
|
1025 |
+
try:
|
1026 |
+
response = requests.get('https://replicate.com/levelsio/neon-tokyo', headers={
|
1027 |
'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'
|
1028 |
+
})
|
1029 |
+
return dict(response.cookies)
|
1030 |
+
except Exception as e:
|
1031 |
+
print(f'Error fetching the page: {e}')
|
1032 |
+
return {}
|
1033 |
|
1034 |
async def initiate_upload(cookies: Dict[str, str], filename: str, content_type: str) -> Dict:
|
1035 |
url = f'https://replicate.com/api/upload/{filename}?content_type={content_type}'
|
1036 |
+
try:
|
1037 |
+
response = requests.post(url, cookies=cookies, headers={
|
1038 |
+
'X-CSRFToken': cookies.get('csrftoken'),
|
1039 |
+
'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',
|
1040 |
+
'Referer': 'https://replicate.com/levelsio/neon-tokyo',
|
1041 |
+
'Origin': 'https://replicate.com',
|
1042 |
+
'Accept': '*/*',
|
1043 |
+
'Accept-Language': 'en-US,en;q=0.5',
|
1044 |
+
'Accept-Encoding': 'identity',
|
1045 |
+
'Sec-Fetch-Dest': 'empty',
|
1046 |
+
'Sec-Fetch-Mode': 'cors',
|
1047 |
+
'Sec-Fetch-Site': 'same-origin',
|
1048 |
+
'Sec-GPC': '1',
|
1049 |
+
'Priority': 'u=1, i'
|
1050 |
+
})
|
1051 |
+
return response.json()
|
1052 |
+
except Exception as e:
|
1053 |
+
print(f'Error initiating upload: {e}')
|
1054 |
+
raise
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
1055 |
|
1056 |
+
async def upload_file(upload_url: str, file_content: bytes, content_type: str) -> bool:
|
1057 |
+
try:
|
1058 |
+
response = requests.put(upload_url, data=file_content, headers={'Content-Type': content_type})
|
1059 |
+
return response.status_code == 200
|
1060 |
+
except Exception as e:
|
1061 |
+
print(f'Error uploading file: {e}')
|
1062 |
+
return False
|
1063 |
+
|
1064 |
+
async def retry_upload(upload_url: str, file_content: bytes, content_type: str, max_retries: int = 5, delay: int = 1) -> bool:
|
1065 |
+
while True:
|
1066 |
+
try:
|
1067 |
+
success = await upload_file(upload_url, file_content, content_type)
|
1068 |
+
if success:
|
1069 |
+
return True
|
1070 |
+
print("Upload failed. Retrying...")
|
1071 |
+
except Exception as e:
|
1072 |
+
print(f"Error during upload: {e}")
|
1073 |
+
|
1074 |
+
await asyncio.sleep(delay)
|
1075 |
+
delay = min(delay * 2, 60)
|
1076 |
+
|
1077 |
+
return False
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|