diff --git a/camlaps/templates/camlaps/index.html b/camlaps/templates/camlaps/index.html index de5db57..054002d 100644 --- a/camlaps/templates/camlaps/index.html +++ b/camlaps/templates/camlaps/index.html @@ -3,21 +3,38 @@ {% block content %}

Твои камеры

- NFS смонтирована + {% if storage_available %} + Storage доступен + {% else %} + Storage недоступен + {% endif %}
-
-
-
-
Camera 1 (Вишня)
-

Путь: /app/storage/Camera1

-
- - + {% for camera in cameras %} +
+
+ {{ camera.name }} +
+
{{ camera.name }}
+

Путь: {{ camera.storage_path }}

+
-
+ {% empty %} +
+
Нет активных камер. Добавь их в админке.
+
+ {% endfor %}
{% endblock %} \ No newline at end of file diff --git a/camlaps/urls.py b/camlaps/urls.py index 7adc220..1983ba9 100644 --- a/camlaps/urls.py +++ b/camlaps/urls.py @@ -1,8 +1,13 @@ from django.urls import path + from . import views app_name = 'camlaps' urlpatterns = [ path('', views.index, name='index'), + path('cameras//preview/', views.camera_preview, name='camera_preview'), + path('cameras//jobs/new/', views.job_create, name='job_create'), + path('jobs/', views.job_list, name='job_list'), + path('jobs//', views.job_detail, name='job_detail'), ] \ No newline at end of file diff --git a/camlaps/views.py b/camlaps/views.py index 73eeae4..38bf6de 100644 --- a/camlaps/views.py +++ b/camlaps/views.py @@ -1,5 +1,62 @@ -from django.shortcuts import render +from django.http import FileResponse, Http404 +from django.shortcuts import get_object_or_404, redirect, render +from django.urls import reverse + +from .forms import TimelapseJobCreateForm +from .models import Camera, TimelapseJob +from .services.cameras import get_camera_lastsnap_path, is_storage_available, list_active_cameras + -# Create your views here. def index(request): - return render(request, 'camlaps/index.html') + cameras = list_active_cameras() + context = { + 'cameras': cameras, + 'storage_available': is_storage_available(), + } + return render(request, 'camlaps/index.html', context) + + +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}) + + +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): + 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() + + return render(request, 'camlaps/job_create.html', {'camera': camera, 'form': form}) diff --git a/requirements b/requirements new file mode 100644 index 0000000..9c868b3 Binary files /dev/null and b/requirements differ diff --git a/templates/inc/_navbar.html b/templates/inc/_navbar.html index 937a9c3..7bf12ab 100644 --- a/templates/inc/_navbar.html +++ b/templates/inc/_navbar.html @@ -10,7 +10,7 @@ Камеры