117 lines
No EOL
3.9 KiB
Python
117 lines
No EOL
3.9 KiB
Python
from PySide6.QtCore import QObject, QThread, Signal
|
||
from datetime import datetime, timedelta
|
||
from pathlib import Path
|
||
import shutil
|
||
import tempfile
|
||
from models.api_model import HelioviewerAPI
|
||
from utils.video_creator import VideoCreator
|
||
|
||
|
||
class TimelapseWorker(QThread):
|
||
log = Signal(str)
|
||
progress = Signal(int, int)
|
||
finished = Signal(bool, str)
|
||
|
||
def __init__(self, source_id, start_date, end_date, output_path, fps=10):
|
||
super().__init__()
|
||
self.source_id = source_id
|
||
self.start_date = start_date
|
||
self.end_date = end_date
|
||
self.output_path = output_path
|
||
self.fps = fps
|
||
self.cancelled = False
|
||
self.temp_dir = None
|
||
|
||
def cancel(self):
|
||
self.cancelled = True
|
||
self.log.emit("⏹️ Отмена процесса...")
|
||
|
||
def run(self):
|
||
try:
|
||
# Создаем временную папку
|
||
self.temp_dir = Path(tempfile.mkdtemp(prefix="timelapse_"))
|
||
self.log.emit(f"📁 Временная папка: {self.temp_dir}")
|
||
|
||
# Генерируем даты
|
||
dates = []
|
||
current = self.start_date.replace(hour=12, minute=0, second=0)
|
||
while current <= self.end_date:
|
||
dates.append(current)
|
||
current += timedelta(days=1)
|
||
|
||
total = len(dates)
|
||
self.log.emit(f"📊 Всего файлов: {total}")
|
||
|
||
downloaded = []
|
||
|
||
# Скачиваем
|
||
for i, date in enumerate(dates):
|
||
if self.cancelled:
|
||
self.cleanup()
|
||
self.finished.emit(False, "Отменено")
|
||
return
|
||
|
||
percent = int((i + 1) / total * 100)
|
||
self.progress.emit(i + 1, total)
|
||
self.log.emit(f"📥 [{i + 1}/{total}] {percent}% - {date.strftime('%Y-%m-%d')}")
|
||
|
||
filepath = HelioviewerAPI.download_image(self.source_id, date, self.temp_dir)
|
||
if filepath:
|
||
downloaded.append(filepath)
|
||
self.log.emit(f"✅ [{i + 1}/{total}] Успешно")
|
||
else:
|
||
self.log.emit(f"❌ [{i + 1}/{total}] Ошибка")
|
||
|
||
if self.cancelled:
|
||
self.cleanup()
|
||
self.finished.emit(False, "Отменено")
|
||
return
|
||
|
||
if not downloaded:
|
||
self.cleanup()
|
||
self.finished.emit(False, "Нет файлов")
|
||
return
|
||
|
||
# Создаем видео
|
||
self.log.emit("🎬 Создание видео...")
|
||
self.progress.emit(total, total)
|
||
|
||
video_path = VideoCreator.create_timelapse(downloaded, self.output_path, self.fps)
|
||
|
||
# Очистка
|
||
self.cleanup()
|
||
|
||
if video_path and video_path.exists():
|
||
self.finished.emit(True, str(video_path))
|
||
else:
|
||
self.finished.emit(False, "Ошибка создания видео")
|
||
|
||
except Exception as e:
|
||
self.cleanup()
|
||
self.finished.emit(False, str(e))
|
||
|
||
def cleanup(self):
|
||
if self.temp_dir and self.temp_dir.exists():
|
||
shutil.rmtree(self.temp_dir)
|
||
self.log.emit("🗑️ Временные файлы удалены")
|
||
|
||
|
||
class TimelapseController(QObject):
|
||
def __init__(self):
|
||
super().__init__()
|
||
self.worker = None
|
||
self.log = Signal(str)
|
||
self.progress = Signal(int, int)
|
||
self.finished = Signal(bool, str)
|
||
|
||
def create(self, source_id, start_date, end_date, output_path, fps=10):
|
||
self.worker = TimelapseWorker(source_id, start_date, end_date, output_path, fps)
|
||
self.worker.log.connect(self.log)
|
||
self.worker.progress.connect(self.progress)
|
||
self.worker.finished.connect(self.finished)
|
||
self.worker.start()
|
||
return self.worker
|
||
|
||
def cancel(self):
|
||
if self.worker:
|
||
self.worker.cancel() |