requestHandler.py 3.3 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107
  1. ########################################################################
  2. # Wiizard - A Wii games manager
  3. # Copyright (C) 2023 CYBERDEViL
  4. #
  5. # This file is part of Wiizard.
  6. #
  7. # Wiizard is free software: you can redistribute it and/or modify
  8. # it under the terms of the GNU General Public License as published by
  9. # the Free Software Foundation, either version 3 of the License, or
  10. # (at your option) any later version.
  11. #
  12. # Wiizard is distributed in the hope that it will be useful,
  13. # but WITHOUT ANY WARRANTY; without even the implied warranty of
  14. # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
  15. # GNU General Public License for more details.
  16. #
  17. # You should have received a copy of the GNU General Public License
  18. # along with this program. If not, see <https://www.gnu.org/licenses/>.
  19. #
  20. ########################################################################
  21. import requests
  22. from PIL import Image, UnidentifiedImageError
  23. import io
  24. class ImageDownloadException(Exception):
  25. pass
  26. class RequestHandler:
  27. USERAGENT = "Mozilla/5.0 (X11; Linux x86_64; rv:109.0) Gecko/20100101 iceweasel/109.0"
  28. MAX_IMG_SIZE = 40000000 # 4MB
  29. def __init__(self):
  30. self.__headers = {"User-Agent": self.USERAGENT}
  31. def get(self, url):
  32. """ This may raise requests.RequestException
  33. """
  34. headers = self.__headers
  35. response = requests.get(url, headers=headers)
  36. return response
  37. def head(self, url):
  38. """ This may raise requests.RequestException
  39. """
  40. headers = self.__headers
  41. response = requests.head(url, headers=headers)
  42. return response
  43. def downloadImage(self, url, path):
  44. """ This may raise a ImageDownloadException
  45. """
  46. # First do a HEAD request
  47. try:
  48. response = self.head(url)
  49. except requests.RequestException as err:
  50. raise ImageDownloadException(err)
  51. headers = response.headers
  52. contentType = headers.get("Content-Type", "")
  53. if contentType != "image/png":
  54. raise ImageDownloadException("No a img", url)
  55. contentLength = headers.get("Content-Length", "")
  56. if not contentLength.isnumeric():
  57. raise ImageDownloadException("No valid content length set " + url)
  58. contentLength = int(contentLength)
  59. if contentLength > __class__.MAX_IMG_SIZE:
  60. raise ImageDownloadException("What kind of img is this? It's to large.. " + url)
  61. # Get the image data
  62. response = requests.get(url, stream=True)
  63. if response.status_code != 200:
  64. raise ImageDownloadException("Wrong status for fetching img " + url)
  65. response.raw.decode_content = True
  66. outputSize = 0
  67. data = b''
  68. for chunk in response:
  69. outputSize += len(chunk)
  70. if outputSize > __class__.MAX_IMG_SIZE:
  71. raise ImageDownloadException("Img is to large! HEAD was lying! " + url)
  72. data += chunk
  73. # Verify image data
  74. # https://pillow.readthedocs.io/en/stable/PIL.html
  75. try:
  76. img = Image.open(io.BytesIO(data))
  77. # https://pillow.readthedocs.io/en/stable/reference/Image.html#PIL.Image.Image.verify
  78. # TODO what "suitable exceptions" are referenced in the docs?
  79. img.verify()
  80. except UnidentifiedImageError:
  81. raise ImageDownloadException("Invalid image data for " + url)
  82. # Write image data
  83. try:
  84. with open(path, "wb") as f:
  85. f.write(data)
  86. except OSError as err:
  87. raise ImageDownloadException(err)