wuhp commited on
Commit
ffa2b77
·
verified ·
1 Parent(s): c721733

Update app.py

Browse files
Files changed (1) hide show
  1. app.py +5 -25
app.py CHANGED
@@ -37,7 +37,6 @@ def is_http_url(s: str) -> bool:
37
  return s.startswith("http://") or s.startswith("https://")
38
 
39
  def ensure_parent_dir(path: str) -> None:
40
- """Create parent directory for a file path if missing."""
41
  parent = os.path.dirname(path)
42
  if parent:
43
  os.makedirs(parent, exist_ok=True)
@@ -86,7 +85,6 @@ def fetch_bytes(url: str, timeout: int = 45) -> bytes:
86
  return r.content
87
 
88
  def parse_torrent(raw: bytes) -> Dict[str, Any]:
89
- # Use top-level decode; current bencodepy has no Bencode class
90
  data = bencodepy.decode(raw)
91
  if not isinstance(data, dict) or b"info" not in data:
92
  raise ValueError("Invalid .torrent: missing 'info' dictionary.")
@@ -278,10 +276,8 @@ def _sha256_file(path: pathlib.Path, bufsize: int = 1024 * 1024) -> str:
278
  return h.hexdigest()
279
 
280
  def _supports_range(url: str, timeout: int = 30) -> Tuple[bool, Optional[int]]:
281
- # HEAD to learn size and Accept-Ranges
282
  r = requests.head(url, timeout=timeout, allow_redirects=True)
283
  if r.status_code >= 400:
284
- # Some servers don't allow HEAD; try GET without download
285
  r = requests.get(url, stream=True, timeout=timeout, allow_redirects=True)
286
  r.raise_for_status()
287
  size = int(r.headers.get("Content-Length", "0") or 0)
@@ -296,10 +292,6 @@ def _supports_range(url: str, timeout: int = 30) -> Tuple[bool, Optional[int]]:
296
  return ("bytes" in accept_ranges.lower() or size > 0, size if size > 0 else None)
297
 
298
  def _download_with_resume(url: str, dest_path: pathlib.Path, timeout: int = 120) -> Tuple[int, Optional[int]]:
299
- """
300
- Download URL to dest_path with simple resume (HTTP Range).
301
- Returns (bytes_written, total_expected or None).
302
- """
303
  dest_path.parent.mkdir(parents=True, exist_ok=True)
304
  tmp_path = dest_path.with_suffix(dest_path.suffix + ".part")
305
 
@@ -320,22 +312,12 @@ def _download_with_resume(url: str, dest_path: pathlib.Path, timeout: int = 120)
320
  f.write(chunk)
321
  bytes_written += len(chunk)
322
 
323
- # finalize
324
  final_size = (existing + bytes_written)
325
- # If we know total_size and match or server returned 200 with complete payload, rename
326
  if total_size is None or final_size >= (total_size or 0):
327
  tmp_path.rename(dest_path)
328
- else:
329
- # Keep .part if incomplete
330
- pass
331
  return bytes_written, total_size
332
 
333
  def prepare_download(parsed_json: str, base_url_override: str) -> Tuple[str, List[str], List[str], str]:
334
- """
335
- Build seed list and file choices.
336
- - If torrent has web seeds → use them.
337
- - Else if base_url_override provided → use that as a 'seed'.
338
- """
339
  if not parsed_json:
340
  return "Parse something in Inspect first.", [], [], ""
341
  parsed = json.loads(parsed_json)
@@ -353,10 +335,6 @@ def prepare_download(parsed_json: str, base_url_override: str) -> Tuple[str, Lis
353
  return msg, seeds, file_list, root
354
 
355
  def download_selected(parsed_json: str, seed_url: str, root_dir: str, selected_files: List[str]) -> Tuple[str, List[str]]:
356
- """
357
- Download selected files into /mnt/data/downloads/<infohash>/...
358
- Create .sha256 sidecar after successful completion.
359
- """
360
  if not parsed_json:
361
  raise gr.Error("Parse a torrent first.")
362
  if not seed_url:
@@ -378,10 +356,8 @@ def download_selected(parsed_json: str, seed_url: str, root_dir: str, selected_f
378
  url = _join_url(seed_url, root_dir, rel)
379
  dest_path = out_root / rel
380
  bytes_written, total_expected = _download_with_resume(url, dest_path)
381
- # Verify size if server told us
382
  if total_expected is not None and dest_path.exists() and dest_path.stat().st_size != total_expected:
383
  logs.append(f"⚠️ Size mismatch for {rel} (got {dest_path.stat().st_size}, expected {total_expected}). Kept .part if incomplete.")
384
- # SHA256
385
  if dest_path.exists():
386
  sha = _sha256_file(dest_path)
387
  with open(str(dest_path) + ".sha256", "w") as f:
@@ -526,4 +502,8 @@ with gr.Blocks(css=CSS, title="Torrent Inspector + Full HTTP Downloader") as dem
526
  )
527
 
528
  if __name__ == "__main__":
529
- demo.launch(server_name="0.0.0.0", server_port=int(os.environ.get("PORT", 7860)))
 
 
 
 
 
37
  return s.startswith("http://") or s.startswith("https://")
38
 
39
  def ensure_parent_dir(path: str) -> None:
 
40
  parent = os.path.dirname(path)
41
  if parent:
42
  os.makedirs(parent, exist_ok=True)
 
85
  return r.content
86
 
87
  def parse_torrent(raw: bytes) -> Dict[str, Any]:
 
88
  data = bencodepy.decode(raw)
89
  if not isinstance(data, dict) or b"info" not in data:
90
  raise ValueError("Invalid .torrent: missing 'info' dictionary.")
 
276
  return h.hexdigest()
277
 
278
  def _supports_range(url: str, timeout: int = 30) -> Tuple[bool, Optional[int]]:
 
279
  r = requests.head(url, timeout=timeout, allow_redirects=True)
280
  if r.status_code >= 400:
 
281
  r = requests.get(url, stream=True, timeout=timeout, allow_redirects=True)
282
  r.raise_for_status()
283
  size = int(r.headers.get("Content-Length", "0") or 0)
 
292
  return ("bytes" in accept_ranges.lower() or size > 0, size if size > 0 else None)
293
 
294
  def _download_with_resume(url: str, dest_path: pathlib.Path, timeout: int = 120) -> Tuple[int, Optional[int]]:
 
 
 
 
295
  dest_path.parent.mkdir(parents=True, exist_ok=True)
296
  tmp_path = dest_path.with_suffix(dest_path.suffix + ".part")
297
 
 
312
  f.write(chunk)
313
  bytes_written += len(chunk)
314
 
 
315
  final_size = (existing + bytes_written)
 
316
  if total_size is None or final_size >= (total_size or 0):
317
  tmp_path.rename(dest_path)
 
 
 
318
  return bytes_written, total_size
319
 
320
  def prepare_download(parsed_json: str, base_url_override: str) -> Tuple[str, List[str], List[str], str]:
 
 
 
 
 
321
  if not parsed_json:
322
  return "Parse something in Inspect first.", [], [], ""
323
  parsed = json.loads(parsed_json)
 
335
  return msg, seeds, file_list, root
336
 
337
  def download_selected(parsed_json: str, seed_url: str, root_dir: str, selected_files: List[str]) -> Tuple[str, List[str]]:
 
 
 
 
338
  if not parsed_json:
339
  raise gr.Error("Parse a torrent first.")
340
  if not seed_url:
 
356
  url = _join_url(seed_url, root_dir, rel)
357
  dest_path = out_root / rel
358
  bytes_written, total_expected = _download_with_resume(url, dest_path)
 
359
  if total_expected is not None and dest_path.exists() and dest_path.stat().st_size != total_expected:
360
  logs.append(f"⚠️ Size mismatch for {rel} (got {dest_path.stat().st_size}, expected {total_expected}). Kept .part if incomplete.")
 
361
  if dest_path.exists():
362
  sha = _sha256_file(dest_path)
363
  with open(str(dest_path) + ".sha256", "w") as f:
 
502
  )
503
 
504
  if __name__ == "__main__":
505
+ demo.launch(
506
+ server_name="0.0.0.0",
507
+ server_port=int(os.environ.get("PORT", 7860)),
508
+ allowed_paths=["/mnt/data"] # <-- allow returning files from /mnt/data
509
+ )