123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107 |
- ########################################################################
- # Wiizard - A Wii games manager
- # Copyright (C) 2023 CYBERDEViL
- #
- # This file is part of Wiizard.
- #
- # Wiizard is free software: you can redistribute it and/or modify
- # it under the terms of the GNU General Public License as published by
- # the Free Software Foundation, either version 3 of the License, or
- # (at your option) any later version.
- #
- # Wiizard is distributed in the hope that it will be useful,
- # but WITHOUT ANY WARRANTY; without even the implied warranty of
- # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- # GNU General Public License for more details.
- #
- # You should have received a copy of the GNU General Public License
- # along with this program. If not, see <https://www.gnu.org/licenses/>.
- #
- ########################################################################
- import requests
- from PIL import Image, UnidentifiedImageError
- import io
- class ImageDownloadException(Exception):
- pass
- class RequestHandler:
- USERAGENT = "Mozilla/5.0 (X11; Linux x86_64; rv:109.0) Gecko/20100101 iceweasel/109.0"
- MAX_IMG_SIZE = 40000000 # 4MB
- def __init__(self):
- self.__headers = {"User-Agent": self.USERAGENT}
- def get(self, url):
- """ This may raise requests.RequestException
- """
- headers = self.__headers
- response = requests.get(url, headers=headers)
- return response
- def head(self, url):
- """ This may raise requests.RequestException
- """
- headers = self.__headers
- response = requests.head(url, headers=headers)
- return response
- def downloadImage(self, url, path):
- """ This may raise a ImageDownloadException
- """
- # First do a HEAD request
- try:
- response = self.head(url)
- except requests.RequestException as err:
- raise ImageDownloadException(err)
- headers = response.headers
- contentType = headers.get("Content-Type", "")
- if contentType != "image/png":
- raise ImageDownloadException("No a img", url)
- contentLength = headers.get("Content-Length", "")
- if not contentLength.isnumeric():
- raise ImageDownloadException("No valid content length set " + url)
- contentLength = int(contentLength)
- if contentLength > __class__.MAX_IMG_SIZE:
- raise ImageDownloadException("What kind of img is this? It's to large.. " + url)
- # Get the image data
- response = requests.get(url, stream=True)
- if response.status_code != 200:
- raise ImageDownloadException("Wrong status for fetching img " + url)
- response.raw.decode_content = True
- outputSize = 0
- data = b''
- for chunk in response:
- outputSize += len(chunk)
- if outputSize > __class__.MAX_IMG_SIZE:
- raise ImageDownloadException("Img is to large! HEAD was lying! " + url)
- data += chunk
- # Verify image data
- # https://pillow.readthedocs.io/en/stable/PIL.html
- try:
- img = Image.open(io.BytesIO(data))
- # https://pillow.readthedocs.io/en/stable/reference/Image.html#PIL.Image.Image.verify
- # TODO what "suitable exceptions" are referenced in the docs?
- img.verify()
- except UnidentifiedImageError:
- raise ImageDownloadException("Invalid image data for " + url)
- # Write image data
- try:
- with open(path, "wb") as f:
- f.write(data)
- except OSError as err:
- raise ImageDownloadException(err)
|