downloader.py 2.4 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293
  1. from inspect import iscoroutinefunction
  2. from os.path import abspath as absolute_path
  3. from time import time
  4. import aiofiles
  5. from wbb import aiohttpsession as session
  6. from wbb.modules.userbot import add_task, rm_task, tasks
  7. def ensure_status(status_code: int):
  8. if status_code < 200 or status_code >= 300:
  9. raise Exception(f"HttpProcessingError: {status_code}")
  10. async def download_url(
  11. url,
  12. file_path,
  13. chunk_size,
  14. progress_func,
  15. ):
  16. global tasks
  17. file_path = file_path or url.split("/")[-1][:20]
  18. progress = 0
  19. total_size = 0
  20. # Check if the provided progress function is
  21. # async for sync in order to call it correctly.
  22. if progress_func:
  23. p_f_args = progress_func[1]
  24. progress_func = progress_func[0]
  25. is_async = iscoroutinefunction(progress_func)
  26. # Check if the server responds
  27. async with session.get(url) as resp:
  28. ensure_status(resp.status)
  29. total_size = int(resp.headers["Content-Length"])
  30. async with session.get(url) as response:
  31. ensure_status(response.status)
  32. async with aiofiles.open(file_path, "wb") as f:
  33. # Save content in file using aiohttp streamReader.
  34. async for chunk in response.content.iter_chunked(
  35. chunk_size
  36. ):
  37. await f.write(chunk)
  38. # Call the progress func on each chunk downloaded
  39. progress += chunk_size
  40. if progress_func:
  41. if is_async:
  42. await progress_func(
  43. progress, total_size, *p_f_args
  44. )
  45. else:
  46. progress_func(progress, total_size, *p_f_args)
  47. return absolute_path(file_path)
  48. async def download(
  49. url: str,
  50. file_path: str = None,
  51. chunk_size: int = 1024,
  52. progress_func=None,
  53. task_id: int = int(time()),
  54. ):
  55. """
  56. :url: url where the file is located
  57. :file_path: path/to/file
  58. :chunk_size: size of a single chunk
  59. """
  60. global tasks
  61. # Create a task and add it to main tasks dict
  62. # So we can cancel it using .cancelTask
  63. task = await add_task(
  64. download_url,
  65. task_id,
  66. url=url,
  67. file_path=file_path,
  68. chunk_size=chunk_size,
  69. progress_func=progress_func,
  70. )
  71. await task
  72. await rm_task(task_id)
  73. return task.result()