поламалаь с новой логикой, чиним
All checks were successful
Deploy timelaps / deploy (push) Successful in 6s

This commit is contained in:
ack
2026-04-19 22:59:40 +03:00
parent 035cbac430
commit 587cb0bcb4
3 changed files with 54 additions and 2 deletions

View File

@@ -13,6 +13,7 @@ logger = logging.getLogger('camlaps')
def _iter_dates(date_from: date, date_to: date):
"""Итерируется по датам включительно в указанном диапазоне."""
current = date_from
while current <= date_to:
yield current
@@ -20,6 +21,7 @@ def _iter_dates(date_from: date, date_to: date):
def _safe_camera_root(job: TimelapseJob) -> Path:
"""Возвращает безопасный путь к каталогу камеры внутри STORAGE_PATH."""
storage_root = Path(settings.STORAGE_PATH).resolve()
camera_root = (storage_root / job.camera.storage_path).resolve()
@@ -38,6 +40,7 @@ def _time_to_minutes(t: time) -> int:
def _pick_nearest_frame_for_day(job: TimelapseJob, day_files: list[Path]) -> Path | None:
"""Выбирает кадр дня, ближайший к anchor_time с учетом фильтра дня/ночи."""
candidates: list[tuple[int, Path]] = []
anchor_minutes = _time_to_minutes(job.anchor_time)
@@ -64,16 +67,46 @@ def _pick_nearest_frame_for_day(job: TimelapseJob, day_files: list[Path]) -> Pat
def _select_frames(job: TimelapseJob, camera_root: Path) -> tuple[list[Path], int, int]:
"""Подбирает кадры и возвращает (кадры, всего_дней, дней_садрами)."""
logger.info('worker:select_frames:start job_id=%s', job.id)
selected: list[Path] = []
days_total = 0
days_with_frames = 0
# Для 1 кадра/сутки берем ближайший кадр к якорному времени в каждом дне.
if int(job.sampling_interval_minutes) == 1440:
for day in _iter_dates(job.date_from, job.date_to):
days_total += 1
day_dir = camera_root / day.isoformat()
if not day_dir.exists() or not day_dir.is_dir():
continue
day_files = sorted(day_dir.glob('*.jpg'))
picked = _pick_nearest_frame_for_day(job, day_files)
if picked is not None:
selected.append(picked)
days_with_frames += 1
logger.info(
'worker:select_frames:done job_id=%s selected=%s days_total=%s days_with_frames=%s mode=daily_anchor',
job.id,
len(selected),
days_total,
days_with_frames,
)
return selected, days_total, days_with_frames
# Для остальных интервалов применяем шаг по времени по общей временной оси.
interval_seconds = int(job.sampling_interval_minutes) * 60
last_selected_dt: datetime | None = None
for day in _iter_dates(job.date_from, job.date_to):
days_total += 1
day_dir = camera_root / day.isoformat()
if not day_dir.exists() or not day_dir.is_dir():
continue
day_has_selected = False
day_files = sorted(day_dir.glob('*.jpg'))
for img_path in day_files:
if img_path.name.lower() == 'lastsnap.jpg':
@@ -91,9 +124,19 @@ def _select_frames(job: TimelapseJob, camera_root: Path) -> tuple[list[Path], in
if last_selected_dt is None or (current_dt - last_selected_dt).total_seconds() >= interval_seconds:
selected.append(img_path)
last_selected_dt = current_dt
day_has_selected = True
logger.info('worker:select_frames:done job_id=%s selected=%s', job.id, len(selected))
return selected
if day_has_selected:
days_with_frames += 1
logger.info(
'worker:select_frames:done job_id=%s selected=%s days_total=%s days_with_frames=%s mode=interval',
job.id,
len(selected),
days_total,
days_with_frames,
)
return selected, days_total, days_with_frames
def _copy_frames_to_temp(job: TimelapseJob, frame_paths: list[Path], temp_dir: Path):