From bfecfa05b63961e8198109005d180b40225fb931 Mon Sep 17 00:00:00 2001 From: oscar Date: Fri, 3 Oct 2025 00:49:03 +0300 Subject: [PATCH] optimized or some shit (by chatgpt) --- .DS_Store | Bin 12292 -> 12292 bytes storysave_scanner.py | 130 ++++++++++++++++++++++--------------------- 2 files changed, 66 insertions(+), 64 deletions(-) diff --git a/.DS_Store b/.DS_Store index 7497584286794dd599aef02e2db12ba0c7445a62..f83ab77e8b846410f4417a96050ff18f8fc2748d 100644 GIT binary patch delta 364 zcmZokXi3;0Day>GZ#6kURB5uEC>NW}*V!%N4wL;v^$<)Y{(=m{;N<+=0tOIZO4z(v zRGFEDon1;{@-2xtW_GR*o2?~Zv&FhN0;O3P^cd0^G8sy8^Icq$a`KaaVjP^U4~xYe zj-$z^;FU+QRDHwdW`!jz%r;(&Cu^xnvGxA>!Y1fC*-KRh#>`QbWwf2#rE1Rnm+#!< zBdYOC;R2IY)pjx&GfaMRYf>}F2|$j_WG!_rWC5woVd@uIX=V82F!gl+LP>A) delta 364 zcmZokXi3;0Day>S-D`4ysM2IRQ7$%~WqWfw>?Zq(>LHj)`~?|?!O8i#1q@*DVDn~C zWo8y1FFD7_wOVu4VH!Cb*VK!R6Z?cxE6x$uUC51qDda265m^rGlj3$%2RLz;MDz2J* zL^YmC^TT9SwVg}`LX#h;sd226m>|ujdE61mk(sQe&V?)>wK+`vA}g&7pB$#X4ghn2 BbQk~t diff --git a/storysave_scanner.py b/storysave_scanner.py index 10c6593..f0c41be 100644 --- a/storysave_scanner.py +++ b/storysave_scanner.py @@ -1,116 +1,118 @@ from watchdog.events import FileSystemEventHandler from watchdog.observers import Observer +from pathlib import Path import shutil import time import os from funcs import get_media_dimensions -media_dir = 'media' -stories_dir = 'stories' -posts_dir = 'posts' +# Base directories +media_dir = Path("media") +stories_dir = media_dir / "stories" +posts_dir = media_dir / "posts" + +# Ensure output dirs exist +stories_dir.mkdir(parents=True, exist_ok=True) +posts_dir.mkdir(parents=True, exist_ok=True) + + +def wait_for_complete(file_path, timeout=10): + """ + Wait until a file is fully written (size stops changing). + Returns True if stable within timeout, else False. + """ + file_path = Path(file_path) + prev_size = -1 + for _ in range(timeout * 2): # check every 0.5 sec + try: + size = file_path.stat().st_size + except FileNotFoundError: + return False + if size == prev_size: + return True + prev_size = size + time.sleep(0.5) + return False + def is_story(width, height, tolerance=0.02): """ - Determine if the given width/height are close to 9:16 (0.5625) ratio - within a certain tolerance. Default tolerance is 2%. - - Tolerance means how close the ratio must be to 9/16 for it - to be considered a story. + Check if dimensions are close to 9:16 (0.5625) ratio. """ if width == 0 or height == 0: return False - - # Calculate the ratio in portrait orientation (ensure width < height). - # You can also just do width/height, but watch out for landscape images. - # We’ll assume portrait means stories. - ratio = width / height if width < height else height / width - - # The official story ratio is 9/16 = 0.5625 - story_ratio = 9/16 - # Check how far off we are from the official ratio - difference = abs(ratio - story_ratio) - - # If the difference is within the tolerance, we consider it a story - return difference <= (story_ratio * tolerance) + ratio = min(width, height) / max(width, height) + return abs(ratio - (9 / 16)) <= (9 / 16 * tolerance) + def determine_post_type(filepath): """ - Determines if a file is for 'posts' or 'stories' based on its aspect ratio. - - If the path includes 'posts' (as you mentioned), we automatically return 'posts'. - - Otherwise, we check if the aspect ratio matches (roughly) the 9:16 ratio. - - If it does, we say 'stories', otherwise 'posts'. + Determines if a file is 'posts' or 'stories' based on aspect ratio. """ - # If "posts" is part of the filepath, consider it a post - if 'posts' in filepath.lower(): - return 'posts' - - # Get actual dimensions + lower = str(filepath).lower() + if "posts" in lower: + return "posts" try: width, height = get_media_dimensions(filepath) - except: - # If we fail to get dimensions, return None or some fallback - return None - - # If dimensions are invalid, return None or False - if width == 0 or height == 0: + except Exception as e: + print(f"Error getting dimensions for {filepath}: {e}") return None - - # Use our ratio check - if is_story(width, height): - return 'stories' - else: - return 'posts' + return "stories" if is_story(width, height) else "posts" + class DownloadHandler(FileSystemEventHandler): def process_file(self, file_path): - file = os.path.basename(file_path) - - if 'crdownload' in file: + file_path = Path(file_path) + file = file_path.name + + # Skip temp/incomplete files + if "crdownload" in file or file.count("~") != 3: return - if file.count('~') != 3: + if not file_path.exists(): return - if not os.path.exists(file_path): + if not wait_for_complete(file_path): + print(f"File {file_path} did not stabilize. Skipping.") return post_type = determine_post_type(file_path) - if post_type == 'posts': - media_type_dir = posts_dir - elif post_type == 'stories': - media_type_dir = stories_dir + if post_type == "posts": + dest_dir = posts_dir + elif post_type == "stories": + dest_dir = stories_dir else: print(f"Could not determine post type for {file}. Skipping...") return - outputPath = os.path.join(media_dir, media_type_dir, file) + output_path = dest_dir / file - if os.path.exists(outputPath): - print(f"File already exists {outputPath}. Removing...") - os.remove(file_path) + if output_path.exists(): + print(f"File already exists {output_path}. Removing...") + file_path.unlink(missing_ok=True) return - shutil.move(file_path, outputPath) - print(f"Moved {file_path} to {outputPath}") + shutil.move(str(file_path), str(output_path)) + print(f"Moved {file_path} → {output_path}") def on_created(self, event): - if not event.is_directory and 'crdownload' not in event.src_path: + if not event.is_directory: self.process_file(event.src_path) def on_moved(self, event): - if not event.is_directory and 'crdownload' not in event.dest_path: + if not event.is_directory: self.process_file(event.dest_path) + if __name__ == "__main__": - downloadPath = os.path.join(os.path.expanduser('~'), 'Downloads') + download_path = Path.home() / "Downloads" event_handler = DownloadHandler() observer = Observer() - observer.schedule(event_handler, downloadPath, recursive=False) + observer.schedule(event_handler, str(download_path), recursive=False) observer.start() try: - while True: - time.sleep(1) # Add a 1-second sleep to reduce CPU usage + observer.join() # idle until interrupted except KeyboardInterrupt: observer.stop() - observer.join() \ No newline at end of file + observer.join()