From b4578cf523be1e86ed7befc6c993e7a848f3aac2 Mon Sep 17 00:00:00 2001
From: Ludovic <54670129+lbr38@users.noreply.github.com>
Date: Tue, 10 Dec 2024 15:54:56 +0100
Subject: [PATCH] patch

---
 docker/config/nginx/motionui.conf             |   6 +
 www/controllers/Camera/Timelapse.php          |   2 +-
 www/public/resources/js/camera.js             |  58 +++++----
 www/public/resources/js/motion.js             |  26 +++-
 www/public/resources/js/pre/camera.js         |   4 +-
 www/public/resources/styles/motionui.css      |  51 +++++---
 www/views/includes/camera/timelapse.inc.php   | 116 +++++++++---------
 .../includes/containers/cameras/list.inc.php  |   4 -
 .../containers/motion/events/list.inc.php     |   2 +-
 9 files changed, 153 insertions(+), 116 deletions(-)

diff --git a/docker/config/nginx/motionui.conf b/docker/config/nginx/motionui.conf
index ac4ec265..cfa55022 100644
--- a/docker/config/nginx/motionui.conf
+++ b/docker/config/nginx/motionui.conf
@@ -83,6 +83,7 @@ server {
         fastcgi_request_buffering off;
     }
 
+    # Go2rtc stream access
     location ~ /api/stream.mjpeg { 
         proxy_pass http://127.0.0.1:1984;
         proxy_http_version 1.1; 
@@ -92,6 +93,11 @@ server {
         proxy_read_timeout 86400;
     }
 
+    # Go2rtc main page
+    location ~ /go2rtc { 
+        proxy_pass http://127.0.0.1:1984/;
+    }
+
     location ~ \.php$ {
         root $WWW_DIR/public;
         include fastcgi_params;
diff --git a/www/controllers/Camera/Timelapse.php b/www/controllers/Camera/Timelapse.php
index 0dd42a90..92c7e15d 100644
--- a/www/controllers/Camera/Timelapse.php
+++ b/www/controllers/Camera/Timelapse.php
@@ -130,7 +130,7 @@ public function timelapse()
                     /**
                      *  Ignore if it fails to capture image because the camera may not be running 24/7
                      */
-                    if ($content === false) {
+                    if ($content === false or empty($content)) {
                         continue;
                     }
 
diff --git a/www/public/resources/js/camera.js b/www/public/resources/js/camera.js
index 82853e74..9bedadbb 100644
--- a/www/public/resources/js/camera.js
+++ b/www/public/resources/js/camera.js
@@ -328,6 +328,9 @@ $(document).on('click','.timelapse-camera-btn',function () {
         // Execute functions :
         [ "$('footer').append(jsonValue.message)" ]
     );
+
+    // Temporary hide all other stream images to avoid CPU loads
+    $('.camera-image').hide();
 });
 
 /**
@@ -380,9 +383,8 @@ $(document).on('click','#timelapse-play-btn',function () {
 
 /**
  *  Play timelapse
- *  @returns
  */
-async function playTimelapse()
+function playTimelapse()
 {
     /**
      *  Retrieve camera id, date, max range and all pictures names
@@ -587,6 +589,9 @@ $(document).on('click','.hide-camera-configuration-btn',function () {
  *  Event: close timelapse screen
  */
 $(document).on('click','.close-timelapse-btn',function () {
+    // Show all stream images
+    $('.camera-image').show();
+
     $('#timelapse').remove();
 });
 
@@ -594,40 +599,33 @@ $(document).on('click','.close-timelapse-btn',function () {
  *  Event: set a camera on full screen
  */
 $(document).on('click','.full-screen-camera-btn',function () {
-    var cameraId = $(this).attr('camera-id');
-
-    /**
-     *  Add full-screen class to set the div on full screen
-     */
-    $('.camera-container[camera-id='+cameraId+']').addClass("full-screen");
-
-    /**
-     *  Show and hide certain buttons
-     */
-    $('.delete-camera-btn[camera-id='+cameraId+']').hide();
-    $('.configure-camera-btn[camera-id='+cameraId+']').hide();
-    $('.timelapse-camera-btn[camera-id='+cameraId+']').hide();
-    $('.close-full-screen-container[camera-id='+cameraId+']').css('display', 'block');
+    var img = $(this);
+
+    html = '<div id="fullscreen">'
+    + '<div class="flex align-item-center">'
+    + '<img src="' + img.attr('src') + '" class="fullscreen-image" alt="Camera Image" />'
+    + '</div>'
+    + '<div class="flex align-item-center justify-center">'
+    + '<img src="/assets/icons/close.svg" class="close-fullscreen-btn pointer lowopacity" title="Close fullscreen">'
+    + '</div>'
+    + '</div>';
+
+    // Append the fullscreen div to the body
+    $('body').append(html);
+
+    // Temporary hide all other stream images to avoid CPU loads
+    $('.camera-image').hide();
 });
 
 /**
  *  Event: close camera full screen
  */
-$(document).on('click','.close-full-screen-btn',function () {
-    var cameraId = $(this).attr('camera-id');
+$(document).on('click','.close-fullscreen-btn',function () {
+    // Show all stream images
+    $('.camera-image').show();
 
-    /**
-     *  Remove full-screen class to set the div on normal screen
-     */
-    $('.camera-container[camera-id='+cameraId+']').removeClass("full-screen");
-
-    /**
-     *  Show and hide certain buttons
-     */
-    $('.delete-camera-btn[camera-id='+cameraId+']').show();
-    $('.configure-camera-btn[camera-id='+cameraId+']').show();
-    $('.timelapse-camera-btn[camera-id='+cameraId+']').show();
-    $('.close-full-screen-container[camera-id='+cameraId+']').hide();
+    // Remove the fullscreen div
+    $('#fullscreen').remove();
 });
 
 /**
diff --git a/www/public/resources/js/motion.js b/www/public/resources/js/motion.js
index 96eba13b..ca16adb1 100644
--- a/www/public/resources/js/motion.js
+++ b/www/public/resources/js/motion.js
@@ -247,8 +247,17 @@ $(document).on('change','.event-date-input',function () {
 $(document).on('click','.play-picture-btn',function () {
     var fileId = $(this).attr('file-id');
 
-    $('.event-print-file').html('<img src="/media?id=' + fileId + '" />');
-    $('.event-print-file-container').css('display', 'flex');
+    html = '<div id="fullscreen">'
+    + '<div class="flex align-item-center">'
+    + '<img src="/media?id=' + fileId + '" title="Full screen event picture" />'
+    + '</div>'
+    + '<div class="flex align-item-center justify-center">'
+    + '<img src="/assets/icons/close.svg" class="close-fullscreen-btn pointer lowopacity" title="Close fullscreen">'
+    + '</div>'
+    + '</div>';
+
+    // Append the fullscreen div to the body
+    $('body').append(html);
 });
 
 /**
@@ -257,8 +266,17 @@ $(document).on('click','.play-picture-btn',function () {
 $(document).on('click','.play-video-btn',function () {
     var fileId = $(this).attr('file-id');
 
-    $('.event-print-file').html('<video controls><source src="/media?id=' + fileId + '"><p>You browser does not support embedded videos.</p></video>');
-    $('.event-print-file-container').css('display', 'flex');
+    html = '<div id="fullscreen">'
+    + '<div class="flex align-item-center">'
+    + '<video controls title="Full screen event video"><source src="/media?id=' + fileId + '"><p>You browser does not support embedded videos.</p></video>'
+    + '</div>'
+    + '<div class="flex align-item-center justify-center">'
+    + '<img src="/assets/icons/close.svg" class="close-fullscreen-btn pointer lowopacity" title="Close fullscreen">'
+    + '</div>'
+    + '</div>';
+
+    // Append the fullscreen div to the body
+    $('body').append(html);
 });
 
 /**
diff --git a/www/public/resources/js/pre/camera.js b/www/public/resources/js/pre/camera.js
index 9dbbc21a..7b9b864d 100644
--- a/www/public/resources/js/pre/camera.js
+++ b/www/public/resources/js/pre/camera.js
@@ -4,7 +4,7 @@
  */
 function setUnavailable(cameraId)
 {
-    $('.camera-container[camera-id=' + cameraId + ']').find('.camera-loading').hide();
-    $('.camera-container[camera-id=' + cameraId + ']').find('.camera-image').hide();
+    $('.camera-container[camera-id=' + cameraId + ']').find('.camera-loading').remove();
+    $('.camera-container[camera-id=' + cameraId + ']').find('.camera-image').remove();
     $('.camera-container[camera-id=' + cameraId + ']').find('.camera-unavailable').css('display', 'flex');
 }
diff --git a/www/public/resources/styles/motionui.css b/www/public/resources/styles/motionui.css
index 45727bea..ad3c25c2 100644
--- a/www/public/resources/styles/motionui.css
+++ b/www/public/resources/styles/motionui.css
@@ -470,7 +470,7 @@ h3 {
     display: flex;
     flex-direction: column;
     justify-content: center;
-    margin: 20px 15px;
+    margin: 15px;
 }
 
 .camera-image > img {
@@ -507,7 +507,11 @@ h3 {
     width: 30%;
     height: 30%;
 }
-#timelapse, .full-screen {
+
+#fullscreen, #timelapse {
+    display: grid;
+    row-gap: 15px;
+    justify-content: center;
     position: fixed;
     top: 0;
     left: 0;
@@ -519,16 +523,29 @@ h3 {
     -webkit-box-shadow: rgb(0 0 0) 0px 10px 13px -12px, rgb(0 0 0 / 15%) 0px 0px 10px 2px;
     box-shadow: rgb(0 0 0) 0px 10px 13px -12px, rgb(0 0 0 / 15%) 0px 0px 10px 2px;
 }
+#fullscreen {
+    grid-template-rows: 80% 20%;    
+}
+#timelapse {
+    grid-template-rows: 40% 40% 20%;
+}
 #timelapse-picture-container {
     display: flex;
+    flex-direction: column;
     align-items: center;
     justify-content: center;
-    max-height: 40vh;
-    max-width: 100vw;
+    row-gap: 15px;
+    height: 100% !important;
+    max-height: 100% !important;
+}
+#timelapse-picture-container div:nth-child(1) {
+    max-height: 100%;
 }
 #timelapse-picture {
     max-height: 100%;
-    max-width: 100vw;
+    width: auto;
+    max-width: 100%;
+    margin: auto;
     border-radius: 2px;
     box-shadow: 0px 1px 5px 0px rgb(13 13 13 / 50%);
 }
@@ -536,17 +553,13 @@ h3 {
     width: 85vw;
 }
 
-.close-timelapse-btn, .close-full-screen-btn {
+.close-timelapse-btn, .close-fullscreen-btn {
     width: 50px;
     height: 50px;
-    margin: auto;
 }
-.full-screen img {
-    max-height: 85vh;
-    max-width: 100vw;
-    display: block !important;
-    margin: auto;
-    border-radius: 2px;
+#fullscreen img:first-child, #fullscreen video {
+    max-height: 100% !important;
+    max-width: 100% !important;
 }
 
 .hide {
@@ -758,10 +771,6 @@ footer #github img { width: 25px; }
         justify-content: space-around;
     }
 
-    #timelapse-picture-container {
-        max-height: 70vh;
-    }
-
     #motion-events-captures-container {
         grid-template-columns: repeat(2, 45%);
         justify-content: space-between;
@@ -848,6 +857,14 @@ footer #github img { width: 25px; }
         grid-template-columns: repeat(3, 1fr);
     }
 
+    #timelapse {
+        grid-template-rows: 65% 20% 15%;
+    }
+
+    #fullscreen {
+        grid-template-rows: 85% 15%;
+    }
+
     .bottom-buttons {
         justify-content: center;
         align-items: center;
diff --git a/www/views/includes/camera/timelapse.inc.php b/www/views/includes/camera/timelapse.inc.php
index 920d36c1..5171f024 100644
--- a/www/views/includes/camera/timelapse.inc.php
+++ b/www/views/includes/camera/timelapse.inc.php
@@ -1,69 +1,71 @@
 <div id="timelapse" class="grid justify-items-center row-gap-10">
     <div id="timelapse-picture-container">
-        <?php
-        if (empty($date)) {
-            $date = date('Y-m-d');
-        }
-
-        if (!empty($picture)) {
-            $picture = $date . '/' . $picture;
-        }
-
-        /**
-         *  Retrieve timelapse pictures for the specified date
-         */
-        try {
-            /**
-             *  Timelapse pictures root directory
-             */
-            $timelapseDir = CAMERAS_TIMELAPSE_DIR . '/camera-' . $cameraId;
+        <div class="flex align-item-center">
+            <?php
+            if (empty($date)) {
+                $date = date('Y-m-d');
+            }
 
-            /**
-             *  Check if specified date directory exists
-             */
-            if (!file_exists($timelapseDir . '/' . $date)) {
-                throw new Exception('No timelapse images for this date yet');
+            if (!empty($picture)) {
+                $picture = $date . '/' . $picture;
             }
 
             /**
-             *  Retrieve pictures name for the specified date
+             *  Retrieve timelapse pictures for the specified date
              */
-            $pictures = array();
-            $picturesGlob = glob($timelapseDir . '/' . $date . '/*.jpg');
+            try {
+                /**
+                 *  Timelapse pictures root directory
+                 */
+                $timelapseDir = CAMERAS_TIMELAPSE_DIR . '/camera-' . $cameraId;
 
-            foreach ($picturesGlob as $pictureGlob) {
-                $pictures[] = basename($pictureGlob);
-            }
+                /**
+                 *  Check if specified date directory exists
+                 */
+                if (!file_exists($timelapseDir . '/' . $date)) {
+                    throw new Exception('No timelapse images for this date yet');
+                }
 
-            /**
-             *  If there are no pictures, throw an exception
-             */
-            if (empty($pictures)) {
-                throw new Exception('No timelapse images for this date yet');
-            }
+                /**
+                 *  Retrieve pictures name for the specified date
+                 */
+                $pictures = array();
+                $picturesGlob = glob($timelapseDir . '/' . $date . '/*.jpg');
 
-            /**
-             *  Print first image first
-             */
-            if (empty($picture)) {
-                $picture = $date . '/' . $pictures[0];
-            }
+                foreach ($picturesGlob as $pictureGlob) {
+                    $pictures[] = basename($pictureGlob);
+                }
 
-            /**
-             *  Print all pictures in a hidden element
-             */
-            echo '<timelapse-data pictures="' . implode(',', $pictures) . '"></timelapse-data>';
+                /**
+                 *  If there are no pictures, throw an exception
+                 */
+                if (empty($pictures)) {
+                    throw new Exception('No timelapse images for this date yet');
+                }
 
-            /**
-             *  Print picture
-             */
-            echo '<img id="timelapse-picture" src="/timelapse?id=' . $cameraId . '&picture=' . $picture . '" />';
-        } catch (Exception $e) {
-            echo '<p>' . $e->getMessage() . '</p>';
-        } ?>
+                /**
+                 *  Print first image first
+                 */
+                if (empty($picture)) {
+                    $picture = $date . '/' . $pictures[0];
+                }
+
+                /**
+                 *  Print all pictures in a hidden element
+                 */
+                echo '<timelapse-data pictures="' . implode(',', $pictures) . '"></timelapse-data>';
+
+                /**
+                 *  Print picture
+                 */
+                echo '<img id="timelapse-picture" src="/timelapse?id=' . $cameraId . '&picture=' . $picture . '" />';
+            } catch (Exception $e) {
+                echo '<p>' . $e->getMessage() . '</p>';
+            } ?>
+        </div>
     </div>
 
-    <div class="grid justify-space-between row-gap-10 padding-left-15 padding-right-15">
+    <div class="flex flex-direction-column row-gap-10 padding-left-15 padding-right-15">
         <div>
             <?php
             if (!empty($picture)) {
@@ -97,7 +99,7 @@
                     $firstPictureMin = explode('-', $firstPictureTime)[1];
                     $firstPictureSec = explode('-', $firstPictureTime)[2];
 
-                    echo '<div><p class="lowopacity-cst">' . $firstPictureHour . ':' . $firstPictureMin . ':' . $firstPictureSec . '</p></div>';
+                    echo '<div><p class="lowopacity-cst font-size-13">' . $firstPictureHour . ':' . $firstPictureMin . ':' . $firstPictureSec . '</p></div>';
 
                     /**
                      *  Print last picture time
@@ -107,7 +109,7 @@
                     $lastPictureMin = explode('-', $lastPictureTime)[1];
                     $lastPictureSec = explode('-', $lastPictureTime)[2];
 
-                    echo '<div><p class="lowopacity-cst">' . $lastPictureHour . ':' . $lastPictureMin . ':' . $lastPictureSec . '</p></div>';
+                    echo '<div><p class="lowopacity-cst font-size-13">' . $lastPictureHour . ':' . $lastPictureMin . ':' . $lastPictureSec . '</p></div>';
                 } ?>
             </div>
 
@@ -172,9 +174,9 @@
                 </select>
             </div>
         </div>
+    </div>
 
-        <div class="flex margin-bottom-40">
-            <img src="/assets/icons/close.svg" class="close-timelapse-btn pointer lowopacity" title="Close timelapse screen">
-        </div>
+    <div class="flex align-item-center">
+        <img src="/assets/icons/close.svg" class="close-timelapse-btn pointer lowopacity" title="Close timelapse screen">
     </div>
 </div>
\ No newline at end of file
diff --git a/www/views/includes/containers/cameras/list.inc.php b/www/views/includes/containers/cameras/list.inc.php
index 853ceeec..bf02d887 100644
--- a/www/views/includes/containers/cameras/list.inc.php
+++ b/www/views/includes/containers/cameras/list.inc.php
@@ -126,10 +126,6 @@
                                 </div>
                             </div>
                         </div>
-
-                        <div class="close-full-screen-container margin-bottom-30 hide" camera-id="<?= $camera['Id'] ?>">
-                            <img src="/assets/icons/close.svg" class="close-full-screen-btn pointer lowopacity" camera-id="<?= $camera['Id'] ?>" title="Close full screen" />
-                        </div>
                     </div>
                 </div>
                 <?php
diff --git a/www/views/includes/containers/motion/events/list.inc.php b/www/views/includes/containers/motion/events/list.inc.php
index 91852c73..b8eeca5f 100644
--- a/www/views/includes/containers/motion/events/list.inc.php
+++ b/www/views/includes/containers/motion/events/list.inc.php
@@ -41,6 +41,6 @@
 
     <!-- Close button -->
     <div class="event-print-file-close-btn margin-bottom-30 hide" style="display: block;">
-        <img src="/assets/icons/close.svg" class="close-full-screen-btn pointer lowopacity" title="Close full screen">
+        <img src="/assets/icons/close.svg" class="close-fullscreen-btn pointer lowopacity" title="Close full screen">
     </div>
 </div>