Files
timelaps/camlaps/views.py
ack 4a10958445
All checks were successful
Deploy timelaps / deploy (push) Successful in 5s
добавил обработчик задач
2026-04-19 19:41:33 +03:00

132 lines
4.0 KiB
Python

import subprocess
import sys
from django.conf import settings
from django.http import FileResponse, Http404
from django.shortcuts import get_object_or_404, redirect, render
from django.urls import reverse
from django.views.decorators.http import require_POST
from .models import Camera, TimelapseJob
from .services.cameras import (
create_cameras_from_candidates,
discover_camera_candidates,
get_camera_lastsnap_path,
is_storage_available,
list_active_cameras,
)
def index(request):
cameras = list_active_cameras()
context = {
'cameras': cameras,
'storage_available': is_storage_available(),
'added': request.GET.get('added'),
}
return render(request, 'camlaps/index.html', context)
@require_POST
def discover_cameras(request):
cameras = list_active_cameras()
candidates = discover_camera_candidates()
context = {
'cameras': cameras,
'storage_available': is_storage_available(),
'discovered_candidates': candidates,
'discovered_count': len(candidates),
}
return render(request, 'camlaps/index.html', context)
@require_POST
def apply_discovered_cameras(request):
selected_paths = request.POST.getlist('selected_storage_paths')
created = create_cameras_from_candidates(selected_paths)
return redirect(f"{reverse('camlaps:index')}?added={created}")
def camera_preview(request, camera_id: int):
camera = get_object_or_404(Camera, pk=camera_id, is_active=True)
path = get_camera_lastsnap_path(camera)
if not path:
raise Http404
return FileResponse(path.open('rb'), content_type='image/jpeg')
def job_list(request):
qs = TimelapseJob.objects.select_related('camera').all()
camera_id = request.GET.get('camera')
if camera_id:
qs = qs.filter(camera_id=camera_id)
jobs = qs.order_by('-created_at')[:200]
return render(request, 'camlaps/job_list.html', {'jobs': jobs, 'queue_started': request.GET.get('started')})
@require_POST
def start_queue(request):
has_planned = TimelapseJob.objects.filter(status=TimelapseJob.Status.PLANNED).exists()
if not has_planned:
return redirect(f"{reverse('camlaps:job_list')}?started=none")
cmd = [sys.executable, 'manage.py', 'run_timelapse_worker', '--once']
kwargs = {
'cwd': settings.BASE_DIR,
'stdout': subprocess.DEVNULL,
'stderr': subprocess.DEVNULL,
}
if sys.platform.startswith('win'):
kwargs['creationflags'] = subprocess.DETACHED_PROCESS | subprocess.CREATE_NEW_PROCESS_GROUP
try:
subprocess.Popen(cmd, **kwargs)
return redirect(f"{reverse('camlaps:job_list')}?started=worker")
except Exception:
return redirect(f"{reverse('camlaps:job_list')}?started=error")
def job_detail(request, job_id: int):
job = get_object_or_404(TimelapseJob.objects.select_related('camera'), pk=job_id)
video_url = None
if job.output_rel_path:
rel = job.output_rel_path.lstrip('/')
if rel.startswith('timelapses/'):
video_url = '/' + rel
else:
video_url = '/timelapses/' + rel.split('/')[-1]
return render(request, 'camlaps/job_detail.html', {'job': job, 'video_url': video_url})
def job_create(request, camera_id: int):
from .forms import TimelapseJobCreateForm
camera = get_object_or_404(Camera, pk=camera_id, is_active=True)
if request.method == 'POST':
form = TimelapseJobCreateForm(request.POST)
if form.is_valid():
job = form.save(commit=False)
job.camera = camera
job.save()
return redirect(reverse('camlaps:job_detail', kwargs={'job_id': job.id}))
else:
form = TimelapseJobCreateForm()
sampling_choices = TimelapseJob.SamplingPreset.choices
sampling_max = len(TimelapseJob.SAMPLING_PRESET_MINUTES) - 1
return render(
request,
'camlaps/job_create.html',
{
'camera': camera,
'form': form,
'sampling_choices': sampling_choices,
'sampling_max': sampling_max,
},
)