THED2 commited on
Commit
574870a
·
verified ·
1 Parent(s): 825abac

Update app.py

Browse files
Files changed (1) hide show
  1. app.py +35 -39
app.py CHANGED
@@ -29,6 +29,14 @@ os.makedirs(DATA_DIR, exist_ok=True)
29
  class DownloadRequest(BaseModel):
30
  url: str
31
 
 
 
 
 
 
 
 
 
32
  async def cleanup_old_files():
33
  while True:
34
  try:
@@ -52,13 +60,15 @@ async def startup_event():
52
  async def download_file(task_id: str, url: str):
53
  file_path = tasks[task_id]["file_path"]
54
  try:
55
- connector = aiohttp.TCPConnector(limit=10)
56
- async with aiohttp.ClientSession(connector=connector, read_bufsize=256 * 1024) as session:
 
57
  async with session.get(url, timeout=None) as response:
58
  response.raise_for_status()
59
  total_size = int(response.headers.get('Content-Length', 0))
60
  tasks[task_id]["total_size"] = total_size
61
 
 
62
  cd = response.headers.get('Content-Disposition')
63
  if cd and 'filename=' in cd:
64
  fname = re.findall('filename="([^"]+)"', cd)
@@ -66,10 +76,9 @@ async def download_file(task_id: str, url: str):
66
  fname = re.findall('filename=([^;]+)', cd)
67
  if fname:
68
  new_filename = fname[0]
69
- new_file_path = os.path.join(DATA_DIR, f"{task_id}_{new_filename}")
70
- tasks[task_id]["file_path"] = new_file_path
71
  tasks[task_id]["original_filename"] = new_filename
72
- file_path = new_file_path
73
 
74
  downloaded = 0
75
  start_time = time.time()
@@ -78,7 +87,7 @@ async def download_file(task_id: str, url: str):
78
  chunk_counter = 0
79
 
80
  with open(file_path, 'wb') as f:
81
- async for chunk in response.content.iter_chunked(256 * 1024):
82
  if not chunk:
83
  break
84
  f.write(chunk)
@@ -94,10 +103,10 @@ async def download_file(task_id: str, url: str):
94
 
95
  f.flush()
96
  chunk_counter += 1
97
- if chunk_counter % 20 == 0:
98
  os.fsync(f.fileno())
99
  del chunk
100
- gc.collect()
101
 
102
  tasks[task_id]["status"] = "completed"
103
  tasks[task_id]["speed"] = 0.0
@@ -110,11 +119,7 @@ async def download_file(task_id: str, url: str):
110
  @app.post("/start_download")
111
  async def start_download(req: DownloadRequest, background_tasks: BackgroundTasks):
112
  task_id = str(uuid.uuid4())
113
- filename = req.url.split("/")[-1]
114
- if "?" in filename:
115
- filename = filename.split("?")[0]
116
- if not filename or "." not in filename:
117
- filename = "downloaded_file.bin"
118
 
119
  tasks[task_id] = {
120
  "task_id": task_id,
@@ -166,7 +171,7 @@ async def stream(task_id: str, request: Request):
166
  def file_iterator(start, length):
167
  with open(file_path, "rb") as f:
168
  f.seek(start)
169
- chunk_size = 512 * 1024 # Reduced chunk size for memory safety
170
  while length > 0:
171
  read_size = min(chunk_size, length)
172
  data = f.read(read_size)
@@ -175,6 +180,7 @@ async def stream(task_id: str, request: Request):
175
  yield data
176
  length -= len(data)
177
  del data
 
178
 
179
  headers = {
180
  "Content-Range": f"bytes {byte1}-{byte1+length-1}/{file_size}",
@@ -215,18 +221,18 @@ async def upload_file(file: UploadFile = File(...)):
215
  original_filename = file.filename if file.filename else "uploaded_file.bin"
216
  file_path = os.path.join(DATA_DIR, f"{task_id}_{original_filename}")
217
 
218
- # Using chunked reading directly from the file stream to save memory
219
  with open(file_path, "wb") as buffer:
220
  while True:
221
- chunk = await file.read(256 * 1024)
222
  if not chunk:
223
  break
224
  buffer.write(chunk)
225
  buffer.flush()
226
  os.fsync(buffer.fileno())
227
  del chunk
 
228
 
229
- await file.close() # Strictly close file to free memory
230
  file_size = os.path.getsize(file_path)
231
 
232
  tasks[task_id] = {
@@ -246,11 +252,7 @@ async def upload_file(file: UploadFile = File(...)):
246
  @app.post("/start_gofile_transfer")
247
  async def start_gofile_transfer(req: DownloadRequest, background_tasks: BackgroundTasks):
248
  task_id = str(uuid.uuid4())
249
- filename = req.url.split("/")[-1]
250
- if "?" in filename:
251
- filename = filename.split("?")[0]
252
- if not filename or "." not in filename:
253
- filename = "transfer_file.bin"
254
 
255
  tasks[task_id] = {
256
  "task_id": task_id,
@@ -267,8 +269,7 @@ async def start_gofile_transfer(req: DownloadRequest, background_tasks: Backgrou
267
  background_tasks.add_task(process_gofile_transfer, task_id, req.url)
268
  return {"task_id": task_id}
269
 
270
- # Chunked file reader generator to avoid streaming upload memory spikes
271
- async def file_sender(file_path, chunk_size=256 * 1024):
272
  with open(file_path, 'rb') as f:
273
  while True:
274
  chunk = f.read(chunk_size)
@@ -276,13 +277,13 @@ async def file_sender(file_path, chunk_size=256 * 1024):
276
  break
277
  yield chunk
278
  del chunk
 
279
 
280
  async def process_gofile_transfer(task_id: str, url: str):
281
  file_path = tasks[task_id]["file_path"]
282
  try:
283
- # 1. Download Setup
284
- connector = aiohttp.TCPConnector(limit=10)
285
- async with aiohttp.ClientSession(connector=connector, read_bufsize=256 * 1024) as session:
286
  async with session.get(url, timeout=None) as response:
287
  response.raise_for_status()
288
  total_size = int(response.headers.get('Content-Length', 0))
@@ -295,10 +296,9 @@ async def process_gofile_transfer(task_id: str, url: str):
295
  fname = re.findall('filename=([^;]+)', cd)
296
  if fname:
297
  new_filename = fname[0]
298
- new_file_path = os.path.join(DATA_DIR, f"{task_id}_{new_filename}")
299
- tasks[task_id]["file_path"] = new_file_path
300
  tasks[task_id]["original_filename"] = new_filename
301
- file_path = new_file_path
302
 
303
  downloaded = 0
304
  start_time = time.time()
@@ -307,7 +307,7 @@ async def process_gofile_transfer(task_id: str, url: str):
307
  chunk_counter = 0
308
 
309
  with open(file_path, 'wb') as f:
310
- async for chunk in response.content.iter_chunked(256 * 1024):
311
  if not chunk:
312
  break
313
  f.write(chunk)
@@ -322,12 +322,11 @@ async def process_gofile_transfer(task_id: str, url: str):
322
 
323
  f.flush()
324
  chunk_counter += 1
325
- if chunk_counter % 20 == 0:
326
  os.fsync(f.fileno())
327
  del chunk
328
  gc.collect()
329
 
330
- # 2. Upload to GoFile (STREAMING JUGAD WITH ZERO RAM IMPRINT)
331
  tasks[task_id]["status"] = "uploading_to_gofile"
332
  tasks[task_id]["speed"] = 0.0
333
 
@@ -338,7 +337,6 @@ async def process_gofile_transfer(task_id: str, url: str):
338
 
339
  upload_url = f"https://{server}.gofile.io/uploadFile"
340
 
341
- # Form data wrapping without buffering entire file array into memory
342
  data = aiohttp.FormData()
343
  data.add_field('file', file_sender(file_path), filename=tasks[task_id]["original_filename"])
344
 
@@ -361,7 +359,7 @@ async def process_gofile_transfer(task_id: str, url: str):
361
  finally:
362
  gc.collect()
363
 
364
- # ==================== NEW ZIP MANAGEMENT FEATURES ====================
365
 
366
  @app.get("/list_zip/{task_id}")
367
  async def list_zip_contents(task_id: str):
@@ -410,15 +408,13 @@ async def extract_zip_file(task_id: str, background_tasks: BackgroundTasks):
410
  return {"status": "extraction_started", "task_id": task_id, "target_folder": extract_folder}
411
 
412
  def process_zip_extraction(task_id: str, zip_path: str, target_dir: str):
413
- """Memory safe extraction processing member by member loop"""
414
  try:
415
  with zipfile.ZipFile(zip_path, 'r') as z:
416
  file_counter = 0
417
  for member in z.namelist():
418
  z.extract(member, path=target_dir)
419
  file_counter += 1
420
- # Release lock periodically inside loops
421
- if file_counter % 50 == 0:
422
  gc.collect()
423
  tasks[task_id]["status"] = "extracted"
424
  except Exception as e:
@@ -429,4 +425,4 @@ def process_zip_extraction(task_id: str, zip_path: str, target_dir: str):
429
 
430
  if __name__ == "__main__":
431
  import uvicorn
432
- uvicorn.run(app, host="0.0.0.0", port=7860)
 
29
  class DownloadRequest(BaseModel):
30
  url: str
31
 
32
+ def clean_filename(url: str) -> str:
33
+ """URL se sahi extension aur filename nikalne ka jugaad"""
34
+ path = url.split("?")[0]
35
+ filename = path.split("/")[-1]
36
+ if not filename or "." not in filename:
37
+ return "downloaded_file.bin"
38
+ return filename
39
+
40
  async def cleanup_old_files():
41
  while True:
42
  try:
 
60
  async def download_file(task_id: str, url: str):
61
  file_path = tasks[task_id]["file_path"]
62
  try:
63
+ # Buffer limit ko strictly small rakha hai taaki RAM leak na ho
64
+ connector = aiohttp.TCPConnector(limit=5)
65
+ async with aiohttp.ClientSession(connector=connector, read_bufsize=64 * 1024) as session:
66
  async with session.get(url, timeout=None) as response:
67
  response.raise_for_status()
68
  total_size = int(response.headers.get('Content-Length', 0))
69
  tasks[task_id]["total_size"] = total_size
70
 
71
+ # Header check for proper filename extraction (.apk, .mp4, etc.)
72
  cd = response.headers.get('Content-Disposition')
73
  if cd and 'filename=' in cd:
74
  fname = re.findall('filename="([^"]+)"', cd)
 
76
  fname = re.findall('filename=([^;]+)', cd)
77
  if fname:
78
  new_filename = fname[0]
79
+ file_path = os.path.join(DATA_DIR, f"{task_id}_{new_filename}")
80
+ tasks[task_id]["file_path"] = file_path
81
  tasks[task_id]["original_filename"] = new_filename
 
82
 
83
  downloaded = 0
84
  start_time = time.time()
 
87
  chunk_counter = 0
88
 
89
  with open(file_path, 'wb') as f:
90
+ async for chunk in response.content.iter_chunked(64 * 1024):
91
  if not chunk:
92
  break
93
  f.write(chunk)
 
103
 
104
  f.flush()
105
  chunk_counter += 1
106
+ if chunk_counter % 10 == 0:
107
  os.fsync(f.fileno())
108
  del chunk
109
+ gc.collect() # Strict garbage collection
110
 
111
  tasks[task_id]["status"] = "completed"
112
  tasks[task_id]["speed"] = 0.0
 
119
  @app.post("/start_download")
120
  async def start_download(req: DownloadRequest, background_tasks: BackgroundTasks):
121
  task_id = str(uuid.uuid4())
122
+ filename = clean_filename(req.url)
 
 
 
 
123
 
124
  tasks[task_id] = {
125
  "task_id": task_id,
 
171
  def file_iterator(start, length):
172
  with open(file_path, "rb") as f:
173
  f.seek(start)
174
+ chunk_size = 128 * 1024 # Hugging Face RAM Optimization
175
  while length > 0:
176
  read_size = min(chunk_size, length)
177
  data = f.read(read_size)
 
180
  yield data
181
  length -= len(data)
182
  del data
183
+ gc.collect()
184
 
185
  headers = {
186
  "Content-Range": f"bytes {byte1}-{byte1+length-1}/{file_size}",
 
221
  original_filename = file.filename if file.filename else "uploaded_file.bin"
222
  file_path = os.path.join(DATA_DIR, f"{task_id}_{original_filename}")
223
 
 
224
  with open(file_path, "wb") as buffer:
225
  while True:
226
+ chunk = await file.read(64 * 1024)
227
  if not chunk:
228
  break
229
  buffer.write(chunk)
230
  buffer.flush()
231
  os.fsync(buffer.fileno())
232
  del chunk
233
+ gc.collect()
234
 
235
+ await file.close()
236
  file_size = os.path.getsize(file_path)
237
 
238
  tasks[task_id] = {
 
252
  @app.post("/start_gofile_transfer")
253
  async def start_gofile_transfer(req: DownloadRequest, background_tasks: BackgroundTasks):
254
  task_id = str(uuid.uuid4())
255
+ filename = clean_filename(req.url)
 
 
 
 
256
 
257
  tasks[task_id] = {
258
  "task_id": task_id,
 
269
  background_tasks.add_task(process_gofile_transfer, task_id, req.url)
270
  return {"task_id": task_id}
271
 
272
+ async def file_sender(file_path, chunk_size=64 * 1024):
 
273
  with open(file_path, 'rb') as f:
274
  while True:
275
  chunk = f.read(chunk_size)
 
277
  break
278
  yield chunk
279
  del chunk
280
+ gc.collect()
281
 
282
  async def process_gofile_transfer(task_id: str, url: str):
283
  file_path = tasks[task_id]["file_path"]
284
  try:
285
+ connector = aiohttp.TCPConnector(limit=5)
286
+ async with aiohttp.ClientSession(connector=connector, read_bufsize=64 * 1024) as session:
 
287
  async with session.get(url, timeout=None) as response:
288
  response.raise_for_status()
289
  total_size = int(response.headers.get('Content-Length', 0))
 
296
  fname = re.findall('filename=([^;]+)', cd)
297
  if fname:
298
  new_filename = fname[0]
299
+ file_path = os.path.join(DATA_DIR, f"{task_id}_{new_filename}")
300
+ tasks[task_id]["file_path"] = file_path
301
  tasks[task_id]["original_filename"] = new_filename
 
302
 
303
  downloaded = 0
304
  start_time = time.time()
 
307
  chunk_counter = 0
308
 
309
  with open(file_path, 'wb') as f:
310
+ async for chunk in response.content.iter_chunked(64 * 1024):
311
  if not chunk:
312
  break
313
  f.write(chunk)
 
322
 
323
  f.flush()
324
  chunk_counter += 1
325
+ if chunk_counter % 10 == 0:
326
  os.fsync(f.fileno())
327
  del chunk
328
  gc.collect()
329
 
 
330
  tasks[task_id]["status"] = "uploading_to_gofile"
331
  tasks[task_id]["speed"] = 0.0
332
 
 
337
 
338
  upload_url = f"https://{server}.gofile.io/uploadFile"
339
 
 
340
  data = aiohttp.FormData()
341
  data.add_field('file', file_sender(file_path), filename=tasks[task_id]["original_filename"])
342
 
 
359
  finally:
360
  gc.collect()
361
 
362
+ # ==================== ZIP MANAGEMENT FEATURES ====================
363
 
364
  @app.get("/list_zip/{task_id}")
365
  async def list_zip_contents(task_id: str):
 
408
  return {"status": "extraction_started", "task_id": task_id, "target_folder": extract_folder}
409
 
410
  def process_zip_extraction(task_id: str, zip_path: str, target_dir: str):
 
411
  try:
412
  with zipfile.ZipFile(zip_path, 'r') as z:
413
  file_counter = 0
414
  for member in z.namelist():
415
  z.extract(member, path=target_dir)
416
  file_counter += 1
417
+ if file_counter % 10 == 0:
 
418
  gc.collect()
419
  tasks[task_id]["status"] = "extracted"
420
  except Exception as e:
 
425
 
426
  if __name__ == "__main__":
427
  import uvicorn
428
+ uvicorn.run(app, host="0.0.0.0", port=7860)