diff --git a/web/app.py b/web/app.py index 4abec5b..65a8839 100644 --- a/web/app.py +++ b/web/app.py @@ -1,5 +1,6 @@ """Flask app: status/preview page + one settings form per screen + rotation settings.""" +import logging from io import BytesIO import requests @@ -9,9 +10,11 @@ from werkzeug.utils import secure_filename from screens.picture import UPLOAD_DIR +logger = logging.getLogger(__name__) + ALLOWED_IMAGE_EXTENSIONS = {"png", "jpg", "jpeg", "gif", "bmp", "webp"} PIL_FORMAT_TO_EXT = {"JPEG": "jpg", "PNG": "png", "GIF": "gif", "BMP": "bmp", "WEBP": "webp"} -PICTURE_URL_TIMEOUT = 15 +PICTURE_URL_TIMEOUT = 30 # a one-time download at save-time, not a recurring poll -- fine to be generous MAX_SCHEDULE_RULES = 4 PICTURE_URL_HEADERS = { "User-Agent": "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/125.0.0.0 Safari/537.36", @@ -244,12 +247,25 @@ def create_app(config, screens: dict, scheduler) -> Flask: response = requests.get(url, timeout=PICTURE_URL_TIMEOUT, headers=PICTURE_URL_HEADERS) response.raise_for_status() content = response.content - fmt = Image.open(BytesIO(content)).format - except (requests.exceptions.RequestException, OSError): fmt = None + except requests.exceptions.Timeout: + content = fmt = None + error = f"Timed out downloading that URL after {PICTURE_URL_TIMEOUT}s -- the host might be slow or blocking this server." + except requests.exceptions.RequestException as exc: + content = fmt = None + logger.warning("Picture URL download failed for %s: %s", url, exc) + error = f"Could not download that URL -- {exc}" + else: + try: + fmt = Image.open(BytesIO(content)).format + except OSError as exc: + logger.warning("Picture URL %s downloaded but didn't decode as an image: %s", url, exc) + fmt = None + ext = PIL_FORMAT_TO_EXT.get(fmt or "") if not ext: - error = "Could not download a valid image from that URL -- try a different link, or upload a file instead." + if not error: + error = "That URL doesn't look like a valid image -- try a different link, or upload a file instead." else: UPLOAD_DIR.mkdir(parents=True, exist_ok=True) # Only one picture is ever active -- clear any previous