Last active
August 16, 2025 11:01
-
-
Save AlexanderNenninger/c98b559ec2e65244b2740e20e0a31df0 to your computer and use it in GitHub Desktop.
Import Fotos into your Gallery using Pythonista
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| # save_as: import_dir_to_photos_share.py | |
| # Use via iOS Share Sheet: Files β Share β Run Pythonista Script β this script. | |
| import appex, photos, hashlib, json, sys | |
| from pathlib import Path | |
| # ---------- Settings ---------- | |
| IMAGE_EXTS = {'.jpg', '.jpeg', '.png', '.heic', '.tif', '.tiff', '.gif', '.bmp', '.webp', '.dng'} | |
| STATE_FILE = Path(__file__).with_suffix('.imported_hashes.json') | |
| CHUNK = 1 << 20 # 1 MiB chunk for hashing | |
| # ----------------------------- | |
| def load_state(): | |
| if STATE_FILE.exists(): | |
| try: | |
| return set(json.loads(STATE_FILE.read_text())) | |
| except Exception: | |
| pass | |
| return set() | |
| def save_state(hset): | |
| STATE_FILE.write_text(json.dumps(sorted(hset))) | |
| def sha256_file(p: Path): | |
| h = hashlib.sha256() | |
| with p.open('rb') as f: | |
| while True: | |
| b = f.read(CHUNK) | |
| if not b: | |
| break | |
| h.update(b) | |
| return h.hexdigest() | |
| def iter_media_paths(paths): | |
| for p in paths: | |
| if p.is_dir(): | |
| for q in p.rglob('*'): | |
| if q.is_file() and q.suffix.lower() in IMAGE_EXTS: | |
| yield q | |
| else: | |
| if p.is_file() and p.suffix.lower() in IMAGE_EXTS: | |
| yield p | |
| def main(): | |
| if not appex.is_running_extension(): | |
| print("Run this from the iOS Share Sheet.") | |
| return | |
| raw_paths = appex.get_file_paths() or [] | |
| if not raw_paths: | |
| print("No files or folders received.") | |
| return | |
| inputs = [Path(s) for s in raw_paths] | |
| candidates = list(iter_media_paths(inputs)) | |
| print(f"Found {len(candidates)} image file(s) to consider.") | |
| imported_hashes = load_state() | |
| imported = 0 | |
| skipped = 0 | |
| errors = 0 | |
| for i, p in enumerate(candidates, 1): | |
| try: | |
| if not p.exists(): | |
| print(f"[{i}/{len(candidates)}] Missing or unavailable: {p}") | |
| errors += 1 | |
| continue | |
| h = sha256_file(p) | |
| if h in imported_hashes: | |
| skipped += 1 | |
| continue | |
| photos.create_image_asset(str(p)) | |
| imported_hashes.add(h) | |
| imported += 1 | |
| if imported % 25 == 0: | |
| print(f"Imported {imported} so far...") | |
| except Exception as e: | |
| errors += 1 | |
| print(f"Failed: {p} -> {e}") | |
| save_state(imported_hashes) | |
| print(f"Done. Imported {imported}, skipped {skipped} duplicate(s), errors {errors}.") | |
| if __name__ == "__main__": | |
| main() |
Author
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
πΈ Import Directory to iOS Photos (Pythonista Share Extension)
This Pythonista script lets you import entire folders of images into the iOS Photos app directly from the Share Sheet.
When invoked from the Files app (or any other app that can share files/folders), it will:
Recursively scan the selected folder(s) for images.
Import them into the Photos library.
Skip duplicates by hashing files and keeping a local record (.imported_hashes.json).
Usage
Save the script in Pythonista (e.g. import_dir_to_photos_share.py).
In Pythonista, tap the wrench icon β Shortcuts β App Extensions and enable this script.
In the Files app, select one or more folders or images β Share β Run Pythonista Script β choose this script.
The script will show log output in Pythonista and add all new images to the Photos app.
This gives you a simple, repeatable way to bulk-import folders of photos into the iOS gallery without manual selection.