поламалаь с новой логикой, чиним
All checks were successful
Deploy timelaps / deploy (push) Successful in 6s
All checks were successful
Deploy timelaps / deploy (push) Successful in 6s
This commit is contained in:
@@ -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):
|
||||
|
||||
Reference in New Issue
Block a user