coollsd commited on
Commit
2b158ec
1 Parent(s): 75193ce

Update app.py

Browse files
Files changed (1) hide show
  1. app.py +166 -104
app.py CHANGED
@@ -1,131 +1,195 @@
1
  from fastapi import FastAPI, File, UploadFile, Request
2
- from fastapi.responses import HTMLResponse, StreamingResponse, JSONResponse
3
  import requests
4
- from urllib.parse import urljoin
5
  import time
6
  from typing import Dict
7
- import uvicorn
8
 
9
  app = FastAPI()
10
 
11
- HTML_CONTENT = '''
12
  <!DOCTYPE html>
13
  <html lang="en">
14
  <head>
15
  <meta charset="UTF-8">
16
- <title>File Upload</title>
17
- <!-- Include Bootstrap CSS for styling -->
18
- <link rel="stylesheet" href="https://stackpath.bootstrapcdn.com/bootstrap/4.5.2/css/bootstrap.min.css">
19
- <!-- Include custom styles -->
20
  <style>
21
  body {
22
- background: linear-gradient(135deg, #1abc9c, #3498db);
23
- color: #fff;
24
  height: 100vh;
 
25
  display: flex;
26
  justify-content: center;
27
  align-items: center;
28
- flex-direction: column;
29
- font-family: Arial, sans-serif;
30
- overflow: hidden;
 
 
 
 
 
 
 
 
 
 
 
 
31
  }
32
  h1 {
33
- margin-bottom: 30px;
34
- animation: fadeInDown 1s;
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
35
  }
36
- form {
37
- background: rgba(255, 255, 255, 0.1);
38
- padding: 30px;
39
- border-radius: 10px;
40
- animation: fadeInUp 1s;
41
  }
42
- .btn-upload {
43
- margin-top: 20px;
 
 
 
 
 
 
 
 
44
  }
45
  .progress {
46
- margin-top: 20px;
 
 
 
 
 
47
  display: none;
 
 
 
 
 
 
 
48
  }
49
- @keyframes fadeInDown {
50
- from {opacity: 0; transform: translateY(-50px);}
51
- to {opacity: 1; transform: translateY(0);}
52
  }
53
- @keyframes fadeInUp {
54
- from {opacity: 0; transform: translateY(50px);}
55
- to {opacity: 1; transform: translateY(0);}
 
 
 
 
 
 
 
 
56
  }
57
  </style>
58
  </head>
59
  <body>
60
- <h1>Upload Your File</h1>
61
- <form id="upload-form">
62
- <div class="custom-file">
63
- <input type="file" class="custom-file-input" id="file-input" name="file" accept="/" required>
64
- <label class="custom-file-label" for="file-input">Choose file...</label>
65
- </div>
66
- <button type="submit" class="btn btn-primary btn-upload">Upload</button>
67
- <div class="progress">
68
- <div class="progress-bar progress-bar-striped progress-bar-animated" role="progressbar" style="width: 0%;"></div>
69
- </div>
70
- </form>
71
-
72
- <!-- Include jQuery and Bootstrap JS for handling events and styles -->
73
- <script src="https://code.jquery.com/jquery-3.5.1.min.js"></script>
74
- <!-- Include Popper and Bootstrap JS -->
75
- <script src="https://cdn.jsdelivr.net/npm/popper.js@1.16.1/dist/umd/popper.min.js"></script>
76
- <script src="https://stackpath.bootstrapcdn.com/bootstrap/4.5.2/js/bootstrap.min.js"></script>
77
- <!-- Custom script -->
78
  <script>
79
- $(document).ready(function(){
80
- $('#file-input').on('change', function(){
81
- // Get the file name and display it
82
- var fileName = $(this).val().split('\\').pop();
83
- $(this).next('.custom-file-label').html(fileName);
84
- });
85
-
86
- $('#upload-form').on('submit', function(e){
87
- e.preventDefault();
88
- var formData = new FormData();
89
- var fileInput = $('#file-input')[0];
90
- if (fileInput.files.length === 0) {
91
- alert('Please select a file to upload.');
92
- return;
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
93
  }
94
- formData.append('file', fileInput.files[0]);
95
- $('.progress').show();
96
- $.ajax({
97
- url: '/upload',
98
- type: 'POST',
99
- data: formData,
100
- contentType: false,
101
- processData: false,
102
- xhr: function(){
103
- var xhr = new window.XMLHttpRequest();
104
- xhr.upload.addEventListener('progress', function(e){
105
- if (e.lengthComputable) {
106
- var percentComplete = (e.loaded / e.total) * 100;
107
- $('.progress-bar').css('width', percentComplete + '%');
108
- $('.progress-bar').attr('aria-valuenow', percentComplete);
109
- }
110
- }, false);
111
- return xhr;
112
- },
113
- success: function(response){
114
- window.location.href = response.url;
115
- },
116
- error: function(jqXHR){
117
- var errorMsg = jqXHR.responseJSON && jqXHR.responseJSON.error ? jqXHR.responseJSON.error : 'File upload failed.';
118
- alert(errorMsg);
119
- $('.progress').hide();
120
- $('.progress-bar').css('width', '0%');
121
- }
122
- });
123
  });
124
- });
 
 
 
 
 
 
 
 
 
 
 
 
 
 
125
  </script>
126
  </body>
127
  </html>
128
- '''
129
 
130
  @app.get("/", response_class=HTMLResponse)
131
  async def index():
@@ -138,22 +202,20 @@ async def handle_upload(file: UploadFile = File(...)):
138
 
139
  cookies = await get_cookies()
140
  if 'csrftoken' not in cookies or 'sessionid' not in cookies:
141
- return JSONResponse(content={"error": "Failed to obtain necessary cookies."}, status_code=500)
142
 
143
- try:
144
- upload_result = await initiate_upload(cookies, file.filename, file.content_type)
145
- except Exception as e:
146
- return JSONResponse(content={"error": f"Failed to initiate upload: {e}"}, status_code=500)
147
  if not upload_result or 'upload_url' not in upload_result:
148
- return JSONResponse(content={"error": "Failed to initiate upload."}, status_code=500)
149
 
150
  file_content = await file.read()
151
  upload_success = await retry_upload(upload_result['upload_url'], file_content, file.content_type)
152
  if not upload_success:
153
- return JSONResponse(content={"error": "File upload failed after multiple attempts."}, status_code=500)
154
 
155
  original_url = upload_result['serving_url']
156
  mirrored_url = f"/rbxg/{original_url.split('/pbxt/')[1]}"
 
157
  return JSONResponse(content={"url": mirrored_url})
158
 
159
  @app.get("/rbxg/{path:path}")
@@ -168,13 +230,13 @@ async def handle_video_stream(path: str, request: Request):
168
  for chunk in response.iter_content(chunk_size=8192):
169
  yield chunk
170
 
171
- response_headers = dict(response.headers)
172
- response_headers['Access-Control-Allow-Origin'] = ''
173
 
174
  if response.status_code == 206:
175
- response_headers['Content-Range'] = response.headers.get('Content-Range')
176
 
177
- return StreamingResponse(generate(), status_code=response.status_code, headers=response_headers)
178
 
179
  async def get_cookies() -> Dict[str, str]:
180
  try:
@@ -194,7 +256,7 @@ async def initiate_upload(cookies: Dict[str, str], filename: str, content_type:
194
  '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',
195
  'Referer': 'https://replicate.com/levelsio/neon-tokyo',
196
  'Origin': 'https://replicate.com',
197
- 'Accept': '/*',
198
  'Accept-Language': 'en-US,en;q=0.5',
199
  'Accept-Encoding': 'identity',
200
  'Sec-Fetch-Dest': 'empty',
 
1
  from fastapi import FastAPI, File, UploadFile, Request
2
+ from fastapi.responses import HTMLResponse, JSONResponse, StreamingResponse
3
  import requests
 
4
  import time
5
  from typing import Dict
 
6
 
7
  app = FastAPI()
8
 
9
+ HTML_CONTENT = """
10
  <!DOCTYPE html>
11
  <html lang="en">
12
  <head>
13
  <meta charset="UTF-8">
14
+ <meta name="viewport" content="width=device-width, initial-scale=1.0">
15
+ <title>Pro File Uploader</title>
16
+ <link href="https://fonts.googleapis.com/css2?family=Poppins:wght@300;400;600&display=swap" rel="stylesheet">
 
17
  <style>
18
  body {
19
+ font-family: 'Poppins', sans-serif;
20
+ background: linear-gradient(135deg, #20B2AA 0%, #48D1CC 100%);
21
  height: 100vh;
22
+ margin: 0;
23
  display: flex;
24
  justify-content: center;
25
  align-items: center;
26
+ color: #333;
27
+ }
28
+ .container {
29
+ background: rgba(255, 255, 255, 0.95);
30
+ padding: 2rem;
31
+ border-radius: 20px;
32
+ box-shadow: 0 10px 30px rgba(0, 0, 0, 0.1);
33
+ text-align: center;
34
+ max-width: 400px;
35
+ width: 100%;
36
+ transition: all 0.3s ease;
37
+ }
38
+ .container:hover {
39
+ transform: translateY(-5px);
40
+ box-shadow: 0 15px 35px rgba(0, 0, 0, 0.2);
41
  }
42
  h1 {
43
+ color: #20B2AA;
44
+ margin-bottom: 1.5rem;
45
+ font-weight: 600;
46
+ }
47
+ .file-input {
48
+ display: none;
49
+ }
50
+ .file-label {
51
+ background-color: #20B2AA;
52
+ color: white;
53
+ padding: 12px 24px;
54
+ border-radius: 30px;
55
+ cursor: pointer;
56
+ transition: all 0.3s ease;
57
+ display: inline-block;
58
+ font-weight: 600;
59
+ }
60
+ .file-label:hover {
61
+ background-color: #48D1CC;
62
+ transform: scale(1.05);
63
  }
64
+ .file-name {
65
+ margin-top: 1rem;
66
+ font-size: 0.9rem;
67
+ color: #666;
 
68
  }
69
+ .progress-container {
70
+ margin-top: 1.5rem;
71
+ display: none;
72
+ }
73
+ .progress-bar {
74
+ width: 100%;
75
+ height: 10px;
76
+ background-color: #e0e0e0;
77
+ border-radius: 5px;
78
+ overflow: hidden;
79
  }
80
  .progress {
81
+ width: 0%;
82
+ height: 100%;
83
+ background-color: #20B2AA;
84
+ transition: width 0.5s ease;
85
+ }
86
+ .loading-spinner {
87
  display: none;
88
+ width: 40px;
89
+ height: 40px;
90
+ border: 4px solid #f3f3f3;
91
+ border-top: 4px solid #20B2AA;
92
+ border-radius: 50%;
93
+ animation: spin 1s linear infinite;
94
+ margin: 20px auto;
95
  }
96
+ @keyframes spin {
97
+ 0% { transform: rotate(0deg); }
98
+ 100% { transform: rotate(360deg); }
99
  }
100
+ .result-link {
101
+ display: none;
102
+ margin-top: 1rem;
103
+ color: #20B2AA;
104
+ text-decoration: none;
105
+ font-weight: 600;
106
+ transition: all 0.3s ease;
107
+ }
108
+ .result-link:hover {
109
+ color: #48D1CC;
110
+ text-decoration: underline;
111
  }
112
  </style>
113
  </head>
114
  <body>
115
+ <div class="container">
116
+ <h1>Pro File Uploader</h1>
117
+ <form id="uploadForm" action="/upload" method="post" enctype="multipart/form-data">
118
+ <input type="file" name="file" id="file" class="file-input" accept="*/*" required>
119
+ <label for="file" class="file-label">Choose File</label>
120
+ <div class="file-name" id="fileName"></div>
121
+ <div class="progress-container" id="progressContainer">
122
+ <div class="progress-bar">
123
+ <div class="progress" id="progress"></div>
124
+ </div>
125
+ </div>
126
+ <div class="loading-spinner" id="loadingSpinner"></div>
127
+ </form>
128
+ <a href="#" class="result-link" id="resultLink" target="_blank">View Uploaded File</a>
129
+ </div>
130
+
 
 
131
  <script>
132
+ const fileInput = document.getElementById('file');
133
+ const fileName = document.getElementById('fileName');
134
+ const uploadForm = document.getElementById('uploadForm');
135
+ const progressContainer = document.getElementById('progressContainer');
136
+ const progress = document.getElementById('progress');
137
+ const loadingSpinner = document.getElementById('loadingSpinner');
138
+ const resultLink = document.getElementById('resultLink');
139
+
140
+ fileInput.addEventListener('change', (e) => {
141
+ if (e.target.files.length > 0) {
142
+ fileName.textContent = e.target.files[0].name;
143
+ uploadFile(e.target.files[0]);
144
+ }
145
+ });
146
+
147
+ function uploadFile(file) {
148
+ const formData = new FormData();
149
+ formData.append('file', file);
150
+
151
+ progressContainer.style.display = 'block';
152
+ loadingSpinner.style.display = 'block';
153
+
154
+ fetch('/upload', {
155
+ method: 'POST',
156
+ body: formData
157
+ })
158
+ .then(response => response.json())
159
+ .then(data => {
160
+ loadingSpinner.style.display = 'none';
161
+ if (data.url) {
162
+ resultLink.href = data.url;
163
+ resultLink.textContent = 'View Uploaded File';
164
+ resultLink.style.display = 'inline-block';
165
+ } else {
166
+ resultLink.style.display = 'none';
167
+ alert('Upload failed: ' + data.error);
168
  }
169
+ })
170
+ .catch(error => {
171
+ loadingSpinner.style.display = 'none';
172
+ alert('Upload failed: ' + error);
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
173
  });
174
+
175
+ simulateProgress();
176
+ }
177
+
178
+ function simulateProgress() {
179
+ let width = 0;
180
+ const interval = setInterval(() => {
181
+ if (width >= 90) {
182
+ clearInterval(interval);
183
+ } else {
184
+ width++;
185
+ progress.style.width = width + '%';
186
+ }
187
+ }, 50);
188
+ }
189
  </script>
190
  </body>
191
  </html>
192
+ """
193
 
194
  @app.get("/", response_class=HTMLResponse)
195
  async def index():
 
202
 
203
  cookies = await get_cookies()
204
  if 'csrftoken' not in cookies or 'sessionid' not in cookies:
205
+ return JSONResponse(content={"error": "Failed to obtain necessary cookies"}, status_code=500)
206
 
207
+ upload_result = await initiate_upload(cookies, file.filename, file.content_type)
 
 
 
208
  if not upload_result or 'upload_url' not in upload_result:
209
+ return JSONResponse(content={"error": "Failed to initiate upload"}, status_code=500)
210
 
211
  file_content = await file.read()
212
  upload_success = await retry_upload(upload_result['upload_url'], file_content, file.content_type)
213
  if not upload_success:
214
+ return JSONResponse(content={"error": "File upload failed after multiple attempts"}, status_code=500)
215
 
216
  original_url = upload_result['serving_url']
217
  mirrored_url = f"/rbxg/{original_url.split('/pbxt/')[1]}"
218
+
219
  return JSONResponse(content={"url": mirrored_url})
220
 
221
  @app.get("/rbxg/{path:path}")
 
230
  for chunk in response.iter_content(chunk_size=8192):
231
  yield chunk
232
 
233
+ headers = dict(response.headers)
234
+ headers['Access-Control-Allow-Origin'] = '*'
235
 
236
  if response.status_code == 206:
237
+ headers['Content-Range'] = response.headers.get('Content-Range')
238
 
239
+ return StreamingResponse(generate(), status_code=response.status_code, headers=headers)
240
 
241
  async def get_cookies() -> Dict[str, str]:
242
  try:
 
256
  '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',
257
  'Referer': 'https://replicate.com/levelsio/neon-tokyo',
258
  'Origin': 'https://replicate.com',
259
+ 'Accept': '*/*',
260
  'Accept-Language': 'en-US,en;q=0.5',
261
  'Accept-Encoding': 'identity',
262
  'Sec-Fetch-Dest': 'empty',