# Сортировка фотографий Утилита приводит новые фотографии к единой структуре архива, находит дубли и создаёт **план**, который сначала можно проверить вручную. Файлы не перемещаются во время анализа. Перенос начинается только после отдельного подтверждения. ## Состав проекта - `Сортировка фото.command` — запуск двойным щелчком в macOS. - `photo_sort.py` — рабочая программа. - `test_photo_sort.py` — автоматические проверки алгоритма. - `vendor/exiftool/` — локальная копия ExifTool для чтения метаданных. Это сторонний компонент, поэтому его исходные тексты и лицензия сохранены на исходном языке. - `photo-sort-report-20260914/`, `photo_sort_20260914.py` и `photo-sort-summary-20260914.md` — архив первой, уже завершённой обработки. Старый скрипт повторно не запускайте. ## Быстрый запуск на Mac 1. Откройте папку проекта и дважды щёлкните `Сортировка фото.command`. 2. В меню выберите `1` — анализ папки. 3. Введите исходную папку с новой партией, обычно: ```text /Users/fofanovdmitry/Documents/Pictures/FOTO/BACKUP ``` 4. Введите папку архива: ```text /Users/fofanovdmitry/Documents/Pictures/FOTO ``` 5. Оставьте дату пустой, чтобы программа читала дату из фотографии. Введите дату только если она достоверно известна для всех выбранных файлов. 6. Для поиска версий одной фотографии в разном сжатии или разрешении ответьте `д` на вопрос о визуальных дублях. 7. После анализа программа покажет путь к новой папке отчёта. Сначала выберите `2` для ручной проверки, затем `3` для просмотра окончательного списка и только потом `4` для переноса. 8. Для фактического переноса введите `ПЕРЕНЕСТИ`. В первый раз macOS может спросить разрешение Terminal на доступ к папке «Документы». Его нужно разрешить в «Системные настройки → Конфиденциальность и безопасность → Файлы и папки». ## Ручная проверка Папка отчёта создаётся в `~/.photo-sort/runs/`. В режиме проверки: - `o` открывает текущую фотографию; - `w` открывает выбранную основную версию; - `t` назначает дату вручную и переводит читаемое фото в сортировку; - `d` переносит файл в `_DEL`; - `r` переносит файл в `_RAS`; - `s` оставляет файл на текущем месте; - Enter показывает следующую строку; - `q` сохраняет уже внесённые решения и завершает просмотр. Также можно открыть `review.csv` в Numbers. Сохраняйте CSV в UTF-8 с запятой как разделителем. Не удаляйте строки и не меняйте `id`, `source`, `reason`, `winner`; разрешено менять только `action` и `date`. Действия в таблице технически записываются как `sort`, `del`, `ras`, `skip`, `keep`: первые три означают сортировать, перенести в `_DEL`, перенести в `_RAS`; последние два оставляют файл на месте. ## Алгоритм работы 1. Программа берёт все файлы из исходной папки и сравнивает их с фотографиями архива, включая `_RAS`. Папки `_DEL` и `BACKUP` не участвуют в сравнении. 2. Для каждого изображения программа пытается полностью его декодировать. Поддерживаемые изображения с ошибкой декодирования считаются повреждёнными и направляются в `_DEL`. Не-фотографии, неподдерживаемые форматы и многостраничные изображения направляются в `_RAS`. 3. У читаемой фотографии считываются встроенные поля даты создания контента: EXIF, XMP и IPTC. Время создания или изменения файла в Finder, имя файла и название папки никогда не используются как дата съёмки. 4. Если во встроенных полях одна согласованная дата, фото получает её. Если даты нет или поля противоречат друг другу, файл направляется в `_RAS`. Дата не наследуется от другой версии фотографии. Назначенная вручную дата сохраняется только для того же файла в постоянном каталоге. 5. Поиск дублей проходит в несколько уровней: точный SHA-256 файла, одинаковые декодированные пиксели, а при включённой опции — строгая визуальная проверка миниатюр. Визуальные совпадения следует просматривать вручную. 6. В каждой группе дублей выбирается один лучший вариант: сначала большее разрешение в пикселях, затем больший размер файла в байтах. При полном равенстве предпочтение получает файл, уже находящийся в архиве. 7. Худшие варианты переносятся в `_DEL`. Если лучшая новая версия должна занять имя старой версии, программа сперва надёжно переносит старую в `_DEL`, затем размещает новую на её месте. 8. Основные фотографии размещаются по пути `ГОД/месяц/ДДММГГГГччммсс.ext`, например `2018/октябрь/15102018093000.jpg`. При совпадении имени добавляется `_dub`, затем `_dub2` и так далее. 9. Перед каждым переносом вычисляется SHA-256. Файл копируется без перезаписи, копия проверяется, и лишь затем удаляется исходник. Поэтому для переноса нужен свободный объём хотя бы с размер копируемого файла. ## Постоянная база и последующие партии База `~/.photo-sort/cache.sqlite` не удаляется автоматически. В ней хранятся кэш декодирования, пути и хеши известных файлов, группы дублей, ручные даты и история переносов. При следующем анализе `BACKUP` программа сверяет базу с реальным состоянием архива: вручную перемещённые или удалённые файлы не считаются действующими оригиналами. Если новая версия лучше старой, старая отправляется в `_DEL`, а новая занимает её место. Если новая версия хуже, в `_DEL` попадёт новая. Перемещения записываются в `moves.jsonl`, а таблица `history` в постоянной базе сохраняет историю. Не удаляйте базу без необходимости: при её удалении программе придётся заново проанализировать весь архив. Изменённый файл всё равно проверяется повторно по размеру, inode, времени изменения и SHA-256. ## Командная строка Команды выполняются из папки проекта: ```bash .venv/bin/python photo_sort.py analyze \ --source "/Users/fofanovdmitry/Documents/Pictures/FOTO/BACKUP" \ --dest "/Users/fofanovdmitry/Documents/Pictures/FOTO" \ --visual .venv/bin/python photo_sort.py review "/путь/к/отчёту" --only unresolved .venv/bin/python photo_sort.py review "/путь/к/отчёту" --only duplicates .venv/bin/python photo_sort.py show "/путь/к/отчёту" .venv/bin/python photo_sort.py apply "/путь/к/отчёту" ``` Для одного выбранного файла с известной датой: ```bash .venv/bin/python photo_sort.py analyze \ --source "/путь/FOTO/_RAS" \ --dest "/путь/FOTO" \ --select "фото.jpg" \ --date "2025-05-20 10:10:20" ``` Другую постоянную базу можно указать параметром `--database "/путь/catalog.sqlite"`. ## Восстановление среды и проверка Если папка `.venv` отсутствует или Python был обновлён, выполните: ```bash python3 -m venv .venv .venv/bin/pip install -r requirements.txt .venv/bin/python -m unittest -v test_photo_sort.py ``` ExifTool уже находится в `vendor/exiftool`. На macOS изображение открывается через `open`, на Linux — через `xdg-open`. ## Важные ограничения - RAW, HEIC и AVIF зависят от доступных декодеров; нечитаемые форматы останутся в `_RAS`. - Изображения больше 100 мегапикселей требуют ручной проверки. Лимит меняется параметром `--max-megapixels`. - После изменения файла или `review.csv` создайте новый анализ, если план больше не соответствует файлам. - Старые планы версии с наследованием даты блокируются. Старые отчёты сохранены, но для новых действий создавайте новый анализ.