2026-05-07 17:15:56 +03:00
|
|
|
|
"""
|
|
|
|
|
|
SessionService - сервис управления сессией
|
|
|
|
|
|
"""
|
|
|
|
|
|
from datetime import datetime
|
|
|
|
|
|
from pathlib import Path
|
|
|
|
|
|
from typing import Optional, Callable
|
|
|
|
|
|
from models.astro_object import AstroObject
|
|
|
|
|
|
from models.session import Session
|
|
|
|
|
|
from services.file_service import FileService
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
class SessionService:
|
|
|
|
|
|
"""Сервис для управления сессией наблюдения"""
|
|
|
|
|
|
|
|
|
|
|
|
def __init__(self):
|
|
|
|
|
|
self._current_session: Optional[Session] = None
|
|
|
|
|
|
self._file_service = FileService()
|
|
|
|
|
|
|
|
|
|
|
|
def start_session(self, watch_folder: Path, object_name: str, camera: str, optics: str) -> Session:
|
|
|
|
|
|
"""Начинает новую сессию"""
|
|
|
|
|
|
start_time = datetime.now()
|
|
|
|
|
|
self._current_session = Session(
|
|
|
|
|
|
camera=camera,
|
|
|
|
|
|
optics=optics,
|
|
|
|
|
|
start_time=start_time
|
|
|
|
|
|
)
|
|
|
|
|
|
|
|
|
|
|
|
session_folder = watch_folder / self._current_session.get_session_name()
|
|
|
|
|
|
session_folder.mkdir(parents=True, exist_ok=True)
|
|
|
|
|
|
self._current_session.session_folder = session_folder
|
|
|
|
|
|
|
|
|
|
|
|
self._log_session_event(f"Session started at {start_time}")
|
|
|
|
|
|
self._log_session_event(f"Camera: {camera}")
|
|
|
|
|
|
self._log_session_event(f"Optics: {optics}")
|
|
|
|
|
|
|
|
|
|
|
|
self.create_new_object(object_name)
|
|
|
|
|
|
return self._current_session
|
|
|
|
|
|
|
|
|
|
|
|
def create_new_object(self, object_name: str) -> AstroObject:
|
|
|
|
|
|
"""Создаёт новый объект съёмки"""
|
|
|
|
|
|
if not self._current_session:
|
|
|
|
|
|
raise ValueError("Session not started")
|
|
|
|
|
|
|
|
|
|
|
|
if self._current_session.get_current_object():
|
|
|
|
|
|
current_obj = self._current_session.get_current_object()
|
|
|
|
|
|
self._log_session_event(f"Object finished: {current_obj.name}, photos: {current_obj.photo_count}")
|
|
|
|
|
|
|
|
|
|
|
|
object_folder = self._current_session.session_folder / object_name
|
|
|
|
|
|
object_folder.mkdir(parents=True, exist_ok=True)
|
|
|
|
|
|
|
|
|
|
|
|
astro_object = AstroObject(
|
|
|
|
|
|
name=object_name,
|
|
|
|
|
|
folder=object_folder,
|
|
|
|
|
|
photo_count=0
|
|
|
|
|
|
)
|
|
|
|
|
|
|
|
|
|
|
|
self._current_session.add_object(astro_object)
|
|
|
|
|
|
self._log_session_event(f"New object: {object_name}")
|
|
|
|
|
|
return astro_object
|
|
|
|
|
|
|
|
|
|
|
|
def handle_file(self, file_path: Path) -> bool:
|
2026-05-07 21:13:00 +03:00
|
|
|
|
"""Обрабатывает новый файл: перемещает в папку текущего объекта с переименованием"""
|
2026-05-07 17:15:56 +03:00
|
|
|
|
if not self._current_session:
|
|
|
|
|
|
return False
|
|
|
|
|
|
|
|
|
|
|
|
current_object = self._current_session.get_current_object()
|
|
|
|
|
|
if not current_object:
|
|
|
|
|
|
return False
|
|
|
|
|
|
|
2026-05-07 21:13:00 +03:00
|
|
|
|
# Передаём имя объекта для переименования файла
|
2026-05-07 17:15:56 +03:00
|
|
|
|
success = self._file_service.move_file(
|
|
|
|
|
|
file_path,
|
|
|
|
|
|
current_object.folder,
|
|
|
|
|
|
self._current_session.camera,
|
2026-05-07 21:13:00 +03:00
|
|
|
|
self._current_session.optics,
|
|
|
|
|
|
current_object.name # Добавляем имя объекта для переименования
|
2026-05-07 17:15:56 +03:00
|
|
|
|
)
|
|
|
|
|
|
|
|
|
|
|
|
if success:
|
|
|
|
|
|
current_object.increment_photo_count()
|
|
|
|
|
|
|
|
|
|
|
|
return success
|
|
|
|
|
|
|
|
|
|
|
|
def move_remaining_files(self, watch_folder: Path, on_file_moved: Optional[Callable] = None) -> int:
|
|
|
|
|
|
"""Перемещает все существующие файлы из папки наблюдения"""
|
|
|
|
|
|
if not self._current_session:
|
|
|
|
|
|
return 0
|
|
|
|
|
|
|
|
|
|
|
|
current_object = self._current_session.get_current_object()
|
|
|
|
|
|
if not current_object:
|
|
|
|
|
|
return 0
|
|
|
|
|
|
|
|
|
|
|
|
count = 0
|
|
|
|
|
|
if watch_folder.exists():
|
|
|
|
|
|
for file_path in watch_folder.iterdir():
|
|
|
|
|
|
if file_path.is_file() and self._file_service.is_photo(file_path):
|
2026-05-07 21:13:00 +03:00
|
|
|
|
success = self._file_service.move_file(
|
2026-05-07 17:15:56 +03:00
|
|
|
|
file_path,
|
|
|
|
|
|
current_object.folder,
|
|
|
|
|
|
self._current_session.camera,
|
2026-05-07 21:13:00 +03:00
|
|
|
|
self._current_session.optics,
|
|
|
|
|
|
current_object.name # Добавляем имя объекта для переименования
|
|
|
|
|
|
)
|
|
|
|
|
|
if success:
|
2026-05-07 17:15:56 +03:00
|
|
|
|
current_object.increment_photo_count()
|
|
|
|
|
|
count += 1
|
|
|
|
|
|
if on_file_moved:
|
|
|
|
|
|
on_file_moved(file_path)
|
|
|
|
|
|
return count
|
|
|
|
|
|
|
|
|
|
|
|
def finish_session(self) -> Session:
|
|
|
|
|
|
"""Завершает сессию"""
|
|
|
|
|
|
if not self._current_session:
|
|
|
|
|
|
raise ValueError("No active session")
|
|
|
|
|
|
|
|
|
|
|
|
self._current_session.finish()
|
|
|
|
|
|
|
|
|
|
|
|
self._log_session_event(f"Session finished at {self._current_session.end_time}")
|
|
|
|
|
|
self._log_session_event("=== SESSION SUMMARY ===")
|
|
|
|
|
|
for obj in self._current_session.objects:
|
|
|
|
|
|
self._log_session_event(f"Object: {obj.name}, Photos: {obj.photo_count}")
|
|
|
|
|
|
|
|
|
|
|
|
return self._current_session
|
|
|
|
|
|
|
|
|
|
|
|
def get_current_session(self) -> Optional[Session]:
|
|
|
|
|
|
return self._current_session
|
|
|
|
|
|
|
|
|
|
|
|
def get_current_object(self) -> Optional[AstroObject]:
|
|
|
|
|
|
if self._current_session:
|
|
|
|
|
|
return self._current_session.get_current_object()
|
|
|
|
|
|
return None
|
|
|
|
|
|
|
|
|
|
|
|
def get_current_object_folder(self) -> Optional[Path]:
|
|
|
|
|
|
current_obj = self.get_current_object()
|
|
|
|
|
|
return current_obj.folder if current_obj else None
|
|
|
|
|
|
|
|
|
|
|
|
def change_camera(self, camera: str):
|
|
|
|
|
|
if self._current_session:
|
|
|
|
|
|
self._current_session.camera = camera
|
|
|
|
|
|
self._log_session_event(f"Camera changed to: {camera}")
|
|
|
|
|
|
|
|
|
|
|
|
def change_optics(self, optics: str):
|
|
|
|
|
|
if self._current_session:
|
|
|
|
|
|
self._current_session.optics = optics
|
|
|
|
|
|
self._log_session_event(f"Optics changed to: {optics}")
|
|
|
|
|
|
|
|
|
|
|
|
def _log_session_event(self, message: str):
|
|
|
|
|
|
if self._current_session and self._current_session.session_folder:
|
|
|
|
|
|
log_file = self._current_session.session_folder / "SessionLog.txt"
|
|
|
|
|
|
timestamp = datetime.now()
|
|
|
|
|
|
line = f"{timestamp} - {message}\n"
|
|
|
|
|
|
try:
|
|
|
|
|
|
with open(log_file, 'a', encoding='utf-8') as f:
|
|
|
|
|
|
f.write(line)
|
|
|
|
|
|
except Exception as e:
|
|
|
|
|
|
print(f"Ошибка записи лога: {e}")
|
|
|
|
|
|
|
|
|
|
|
|
def is_active(self) -> bool:
|
|
|
|
|
|
return self._current_session is not None and self._current_session.is_active()
|