ISE_Python_Scripts_Manual (next Master version): add the history lines, update thequoted MediaProcessor version (v9.18 in Master v6) to v9.24, and add the usage block to the MediaProcessor section. This replaces the v9.21 to v9.24 entries from the earlier zips.
ISE v9.25 (2026-10-06) -- A video that yields no frame at all now says why. ffmpeg runs with -v error, its stderr is captured, and one [!] No frame from ID n (file): ... line shows ffmpeg's last two error lines (or "exited 0 but wrote no frame"), the ffprobe duration and the sample window. duration 60.0 means ffprobe failed or is missing; samples are then taken at 7.5/15/22.5 s, which is past the end of any clip shorter than that (the cause on Live, which had no ffprobe: IDs 2416, 4683, 3711 are 4.9, 5.1 and 7.0 s long). Which frames are taken and what is stored are unchanged. Live fix: copy /usr/local/bin/ffprobe from Clone (same build as Live's ffmpeg).
ISE v9.24 (2026-10-06) -- ffprobe/ffmpeg now survive fork() failing with ENOMEM (v9.20 only handled it for the caption call, so one failure killed the instance with a traceback). Each start is retried 3 times, 5s apart, with every attempt printed. If it is still out of memory the item is reported FAILED (it stays un-embedded and is retried next run) and the run moves on; 3 items in a row stop THIS instance cleanly (exit 1, one message). Everything saved before that is intact.
ISE v9.23 (2026-10-06) -- --progress prints FAILED -- no embedding stored for an item that produced nothing (v9.22 said "done, 0 frames") and skipped for a file type the script does not encode. New opt-in --allow-truncated: images whose file is cut short ("image file is truncated") are decoded as far as they go, so they get an embedding and caption from what is there. Default unchanged: such files fail on every run.
ISE v9.22 (2026-10-06) -- --progress prints a line when each item starts and when it is done. Launcher fix: it now polls its instances, so Ctrl-C (or kill -INT on the launcher) stops all of them; v9.21 could miss the signal.
ISE v9.21 (2026-10-06) -- --ft=image|video|all splits a run by file type; --instances=N (1-4) runs N copies in parallel. With N > 1 the shared stores are saved under a lock (read, merge only this copy's new keys, write), so copies cannot overwrite each other. With N = 1 and no --ft the behaviour is exactly v9.20.
python3.8 MediaProcessor.py --ft=image --instances=2 --progress
python3.8 MediaProcessor.py --ft=image --allow-truncated --progress
python3.8 MediaProcessor.py --ft=video --instances=2 --log
--ft: image = jpg jpeg png webp gif; video = mp4 webm 3gp; default all. Items of the other type are left alone and not counted as skipped.--instances N: copy k of N takes attachment ids with id % N == k-1. Output lines are prefixed [k/N]. Each copy gets cores/N threads for torch and, if llama-mtmd-cli --help lists --threads, for llama (-t). --attachid always runs as one instance. --chunk-size applies per instance.--ft=image and --ft=video together): their instances add up. The stores themselves stay safe (same lock), but the memory does not.--progress: [>] ID n (file) -- k of M in this run when an item starts; [<] ID n done -- k of M, frames, seconds, caption, [<] ID n FAILED -- ... or [<] ID n skipped -- ... when it ends; [~] before a caption retry of an already embedded item. M = new items in this run's scope, counted up front. Off by default. Already-embedded items are skipped silently as before (--verbose lists them).--allow-truncated: see the v9.23 line. A half-decoded image is embedded as it is; re-uploading the file is the alternative.ISE_Data/.mediaprocessor.lock (N > 1 only); processor_checkpoint_i<k>of<N>.json per copy instead of processor_checkpoint.json (N > 1 only).[!] FATAL and writes nothing.subprocess.run(text=True) (3.7+), so call it with an explicit python3.8, not plain python3 (3.6.3 on Live).