Skip to content

Commit 75325aa

Browse files
authored
Update postergeist.py to 1.4
# Postergeist Slideshow - Changelog All notable changes to this project will be documented in this file. --- ## v2.0.0 - 2025-09-26 This is a significant update that introduces a major new feature for themed overlays and fixes a critical bug related to video playback. ### ✨ New Features * **Themed Overlay Tagging:** * You can now assign specific overlays to entire folders of media. * **How it works:** Rename a subfolder inside your `posters` directory using the format `FolderName_tag`. For example, a folder named `MyMovies_vhs` will use the tag `vhs`. * The script will automatically look for an overlay file in the `overlays` folder with a filename that matches the tag (e.g., `vhs.png`, `vhs.gif`). * If no matching overlay is found for a tag, or if a folder has no tag, a random overlay will be used as a fallback. * **Subdirectory Scanning:** * The script now automatically scans for media files in all subfolders within the main `posters` directory. This allows for better organization of your media library and is essential for the new tagging feature. ### 🐞 Bug Fixes * **Video Transition Stall:** * Fixed a critical bug where the slideshow would not advance to the next item after a video file finished playing. * **Cause:** The `root.after()` scheduler was being given a reference to the `get_delay` method instead of the *result* of calling the method. * **Solution:** The call was corrected from `` `self.root.after(self.get_delay, ...)` `` to `` `self.root.after(self.get_delay(), ...)` ``, ensuring the scheduler receives a valid millisecond value. ### 🔧 Code & Logic Improvements * **`load_files()` Function:** * Rewritten to use `os.walk()` to recursively search through the entire directory tree of the specified `posters` folder. * **`_select_new_overlay()` Method:** * Refactored to accept the `media_path` of the current file as an argument. It now parses the parent directory name to check for a `_tag`. * **`show_image()` and `show_video()` Methods:** * Updated to pass the current file's path to the `_select_new_overlay()` method, enabling the new tag-based logic.
1 parent 51dfdbc commit 75325aa

File tree

1 file changed

+32
-17
lines changed

1 file changed

+32
-17
lines changed

postergeist.py

Lines changed: 32 additions & 17 deletions
Original file line numberDiff line numberDiff line change
@@ -22,7 +22,6 @@ def __init__(self, root, folder, overlay_folder, delay, random_delay, start_rota
2222
self.delay = delay
2323
self.random_delay = random_delay
2424
self.fade_height_percent = fade_height
25-
# --- NEW ---
2625
self.performance_mode = performance_mode
2726

2827
self.files = self.load_files(folder)
@@ -73,8 +72,13 @@ def __init__(self, root, folder, overlay_folder, delay, random_delay, start_rota
7372

7473
def load_files(self, folder):
7574
exts = (".jpg", ".jpeg", ".png", ".webp", ".bmp", ".gif", ".mp4", ".mov", ".avi", ".mkv")
75+
file_list = []
7676
try:
77-
return [os.path.join(folder, f) for f in os.listdir(folder) if f.lower().endswith(exts)]
77+
for root, _, files in os.walk(folder):
78+
for f in files:
79+
if f.lower().endswith(exts):
80+
file_list.append(os.path.join(root, f))
81+
return file_list
7882
except FileNotFoundError:
7983
return []
8084

@@ -121,7 +125,6 @@ def prepare_base_frame(self, img_to_process, is_video=False):
121125
self.suppress_overlay = True
122126
else:
123127
self.suppress_overlay = False
124-
# --- MODIFIED: Glow effect is skipped in performance mode ---
125128
if not self.performance_mode:
126129
glow = poster.filter(ImageFilter.GaussianBlur(25))
127130
glow_x = (canvas_w - p_w) // 2
@@ -188,24 +191,38 @@ def do_step(step=0):
188191

189192
do_step()
190193

191-
def _select_new_overlay(self):
194+
def _select_new_overlay(self, media_path):
192195
self.active_overlay_path = None
193196
self.active_overlay_frames = []
194197
self.active_overlay_index = 0
195-
if self.overlays:
198+
tagged_overlay_found = False
199+
200+
folder_name = os.path.basename(os.path.dirname(media_path))
201+
202+
if '_' in folder_name:
203+
tag = folder_name.rsplit('_', 1)[-1]
204+
for overlay_file_path in self.overlays:
205+
overlay_filename_no_ext = os.path.splitext(os.path.basename(overlay_file_path))[0]
206+
if overlay_filename_no_ext == tag:
207+
self.active_overlay_path = overlay_file_path
208+
tagged_overlay_found = True
209+
break
210+
211+
if not tagged_overlay_found and self.overlays:
196212
self.active_overlay_path = random.choice(self.overlays)
197-
if self.active_overlay_path.lower().endswith((".gif", ".apng")):
198-
try:
199-
with Image.open(self.active_overlay_path) as img:
200-
self.active_overlay_duration = img.info.get('duration', 100)
201-
self.active_overlay_frames = [frame.copy() for frame in ImageSequence.Iterator(img)]
202-
except Exception as e:
203-
print(f"Error loading animated overlay {os.path.basename(self.active_overlay_path)}: {e}")
204-
self.active_overlay_path = None
213+
214+
if self.active_overlay_path and self.active_overlay_path.lower().endswith((".gif", ".apng")):
215+
try:
216+
with Image.open(self.active_overlay_path) as img:
217+
self.active_overlay_duration = img.info.get('duration', 100)
218+
self.active_overlay_frames = [frame.copy() for frame in ImageSequence.Iterator(img)]
219+
except Exception as e:
220+
print(f"Error loading animated overlay {os.path.basename(self.active_overlay_path)}: {e}")
221+
self.active_overlay_path = None
205222

206223
def show_image(self, path):
207224
self.cached_video_background = None
208-
self._select_new_overlay()
225+
self._select_new_overlay(path)
209226
try:
210227
with Image.open(path) as img:
211228
img_rgba = img.convert("RGBA")
@@ -233,7 +250,7 @@ def show_video(self, path):
233250
screen_w = self.root.winfo_width()
234251
screen_h = self.root.winfo_height()
235252
if vid_w < screen_w * 0.95 or vid_h < screen_h * 0.95:
236-
self._select_new_overlay()
253+
self._select_new_overlay(path)
237254
else:
238255
self.active_overlay_path = None
239256
self.active_overlay_frames = []
@@ -318,7 +335,6 @@ def rotate_poster(self):
318335
if self.video_capture and self.video_capture.isOpened():
319336
self.show_file()
320337
else:
321-
# Need to reload the static image to redraw it
322338
if self.files:
323339
self.show_image(self.files[self.index])
324340

@@ -357,7 +373,6 @@ def main():
357373
parser.add_argument("--rotate", type=int, default=0, choices=[0, 90, 180, 270], help="Starting rotation")
358374
parser.add_argument("--fade-height", type=int, default=20,
359375
help="Fade height at bottom of poster as a percentage (e.g., 20)")
360-
# --- NEW ARGUMENT ---
361376
parser.add_argument("--performance-mode", action="store_true",
362377
help="Disable intensive effects like glow for better performance")
363378
args = parser.parse_args()

0 commit comments

Comments
 (0)