This commit is contained in:
2026-06-02 14:02:09 +05:00
parent f263d84a8d
commit 847c87fd7e
9 changed files with 79 additions and 29 deletions
+25 -12
View File
@@ -32,16 +32,17 @@ def _parse_started_at(path: str) -> int:
def _scan_segments(root: str) -> dict[str, list[str]]:
"""Возвращает {camera_id: [пути mp4, отсортированы]}.
"""Возвращает {имя_папки: [пути mp4, отсортированы]} (папка = номер слота или
легаси-id камеры — сопоставление в камеру делает вызывающий).
Файлы лежат в подпапке даты <cam>/<YYYY-MM-DD>/*.mp4; старые «плоские»
<cam>/*.mp4 тоже подхватываем (обратная совместимость). Сортировка по полному
Файлы лежат в подпапке даты <folder>/<YYYY-MM-DD>/*.mp4; старые «плоские»
<folder>/*.mp4 тоже подхватываем (обратная совместимость). Сортировка по полному
пути == хронологическая (ISO-даты и в каталоге, и в имени)."""
result: dict[str, list[str]] = {}
if not os.path.isdir(root):
return result
for cam_id in os.listdir(root):
cam_dir = os.path.join(root, cam_id)
for folder in os.listdir(root):
cam_dir = os.path.join(root, folder)
if not os.path.isdir(cam_dir):
continue
files: list[str] = []
@@ -58,7 +59,7 @@ def _scan_segments(root: str) -> dict[str, list[str]]:
# из-за чего пишущийся сейчас файл в подпапке не оказывался бы последним)
files.sort(key=os.path.basename)
if files:
result[cam_id] = files
result[folder] = files
return result
@@ -102,9 +103,10 @@ class Indexer:
store = self.config.storage_by_id(cam.storage_id) or self.config.active_storage()
if store.type == "nas" and not os.path.ismount(store.path):
continue
sub = self.config.archive_dir(cam.id) # папка-слот, напр. «05»
for d in days:
try:
os.makedirs(os.path.join(store.path, cam.id, d), exist_ok=True)
os.makedirs(os.path.join(store.path, sub, d), exist_ok=True)
except OSError:
pass
@@ -115,12 +117,23 @@ class Indexer:
# сканируем ВСЕ хранилища: после смены активного старые записи не теряются
for root in self.config.storage_paths():
by_cam = _scan_segments(root)
by_dir = _scan_segments(root)
is_active = (root == active_path)
for cam_id, files in by_cam.items():
# в активном хранилище последний файл ещё пишется — пропускаем;
# в неактивных все сегменты завершены, индексируем целиком.
complete = files[:-1] if is_active else files
for folder, files in by_dir.items():
# Сопоставление папки с камерой по приоритету:
# 1) точное совпадение с id камеры — легаси-папка по id (в т.ч. числовому),
# иначе папка камеры с id «5» спуталась бы со слотом 5;
# 2) папка-слот «NN» → камера в этом слоте (новая схема);
# 3) иначе оставляем имя папки (осиротевший архив индексируется как раньше).
cam = self.config.camera(folder) or self.config.camera_by_archive_dir(folder)
cam_id = cam.id if cam else folder
# последний файл ещё пишется только в активной папке-слоте ТЕКУЩЕЙ камеры;
# легаси-папки и неактивное хранилище дописаны — индексируем целиком.
being_written = (
is_active and cam is not None
and self.config.archive_dir(cam.id) == folder
)
complete = files[:-1] if being_written else files
for path in complete:
if path in known:
continue