From: Scott Gasch Date: Mon, 11 May 2026 20:05:11 +0000 (-0700) Subject: Fix race condition in choose_photo. X-Git-Url: https://git.acknak.org/gitweb/?a=commitdiff_plain;h=4a475bc5d5f5eaa0e9d13f95ed1fd15183822dfd;p=kiosk.git Fix race condition in choose_photo. --- diff --git a/immich_photo_renderer.py b/immich_photo_renderer.py index 5590154..1f2fea4 100644 --- a/immich_photo_renderer.py +++ b/immich_photo_renderer.py @@ -141,95 +141,101 @@ class immich_photo_renderer(renderer.abstaining_renderer): text ).strip() - def choose_photo(self): - """Pick one of the cached URLs and build a page.""" - if len(self.candidate_photo_uuids) == 0: - print("No photos!") - return False - selected_uuid = random.sample(list(self.candidate_photo_uuids), 1)[0] - asset = self.immich_cli.get_full_asset(selected_uuid) - if not asset: - print(f"Asset {selected_uuid} is unknown?!") - return False +def choose_photo(self): + """Pick one of the cached URLs and build a page.""" + if len(self.candidate_photo_uuids) == 0: + print("No photos!") + return False + + selected_uuid = random.sample(list(self.candidate_photo_uuids), 1)[0] + asset = self.immich_cli.get_full_asset(selected_uuid) + if not asset: + print(f"Asset {selected_uuid} is unknown?!") + return False + + # --- Fetch ALL network data first, before touching disk --- + try: + jpeg = self.immich_cli.get_asset_thumbnail(selected_uuid, size="fullsize") + except Exception: + print("Failed to get image!") + return False - try: - jpeg = self.immich_cli.get_asset_thumbnail(selected_uuid, size="fullsize") - with open("/var/www/kiosk/pages/mfs/current.jpeg", "wb") as f: - f.write(jpeg) - f.flush() - os.fsync(f.fileno()) - except Exception: - print("Failed to get image!") - return False - - # Simple aspect ratio check for layout decision. - layout_class = get_layout_class(asset) - - # Albums list... - try: - albums = self.immich_cli.get_asset_albums(selected_uuid) - except Exception: - print("Failed to get albums!") - albums = [] - - # Location, description, etc... - exif = asset.get('exifInfo', {}) - location = "Unknown location" - descr = '' - if exif: - date = parse_exif_date(exif) - city = exif.get("city", "") - state = exif.get("state", "") - country = exif.get("country", "") - lat = exif.get("latitude", "") - lon = exif.get("longitude", "") - if city: - location = city - if state: - if location: - location += f", {state}" - else: - location = state - if country: - if location: - location += f", {country}" - else: - location = country - if lat and lon: - if location: - location += f" @ {format_coords(lat, lon)}" - else: - location = format_coords(lat, lon) - descr = exif.get("description", "") - - if not descr: - people = asset.get('people', []) - if people: - descr = "A photo of " - descr += natural_join([p.get("name", "") for p in asset.get("people", [])]) - else: - descr = "No description data available. #needs description" - descr = self._highlight_hashtags(descr) - - album_html = '' - for album in albums: - album_name = album.get('albumName') - album_cover_uuid = album.get('albumThumbnailAssetId') - album_cover = self.immich_cli.get_asset_thumbnail( - album_cover_uuid, size="thumbnail" - ) - with open(f"/var/www/kiosk/pages/mfs/{album_cover_uuid}.jpeg", "wb") as f: - f.write(album_cover) + try: + albums = self.immich_cli.get_asset_albums(selected_uuid) + except Exception: + print("Failed to get albums!") + albums = [] + + album_covers = {} + for album in albums: + album_cover_uuid = album.get('albumThumbnailAssetId') + if album_cover_uuid: + try: + album_covers[album_cover_uuid] = self.immich_cli.get_asset_thumbnail( + album_cover_uuid, size="thumbnail" + ) + except Exception: + print(f"Failed to get album cover for {album_cover_uuid}, skipping.") + + # --- All network calls done. Now compute derived values. --- + layout_class = get_layout_class(asset) + exif = asset.get('exifInfo', {}) + date = None + location = "Unknown location" + descr = '' + if exif: + date = parse_exif_date(exif) + city = exif.get("city", "") + state = exif.get("state", "") + country = exif.get("country", "") + lat = exif.get("latitude", "") + lon = exif.get("longitude", "") + + if city: + location = city + if state: + location = f"{location}, {state}" if location else state + if country: + location = f"{location}, {country}" if location else country + if lat and lon: + location = f"{location} @ {format_coords(lat, lon)}" if location else format_coords(lat, lon) + descr = exif.get("description", "") + + if not descr: + people = asset.get('people', []) + if people: + descr = "A photo of " + natural_join([p.get("name", "") for p in people]) + else: + descr = "No description data available. #needs description" + + descr = self._highlight_hashtags(descr) + date_str = date.strftime("%B %-d, %Y") if date else "Unknown date" + album_html = '' + for album in albums: + album_name = album.get('albumName') + album_cover_uuid = album.get('albumThumbnailAssetId') + if album_cover_uuid and album_cover_uuid in album_covers: album_html += f"""
Album Art {album_name}
""" - cache_buster = int(time.time()) - with file_writer.file_writer("photo_33_3600.html") as f: - f.write( - f""" + + # --- All data ready. Now write to disk atomically. --- + with open("/var/www/kiosk/pages/mfs/current.jpeg", "wb") as f: + f.write(jpeg) + f.flush() + os.fsync(f.fileno()) + + for cover_uuid, cover_data in album_covers.items(): + with open(f"/var/www/kiosk/pages/mfs/{cover_uuid}.jpeg", "wb") as f: + f.write(cover_data) + + cache_buster = int(time.time()) + with file_writer.file_writer("photo_33_3600.html") as f: + f.write( + f"""