]> www.vanbest.org Git - motioneye-debian/commitdiff
added media previews grouping support
authorCalin Crisan <ccrisan@gmail.com>
Sat, 16 Nov 2013 13:43:02 +0000 (15:43 +0200)
committerCalin Crisan <ccrisan@gmail.com>
Sat, 16 Nov 2013 13:43:23 +0000 (15:43 +0200)
doc/todo.txt
src/mediafiles.py
src/utils.py
static/css/main.css
static/js/main.js
static/js/ui.js

index 0b11b32e0869be82877f6bda776f04ffb695c31d..d9bf54532f4de0ccb6dd6247b74a56e4989d3d52 100644 (file)
@@ -1,7 +1,4 @@
--> add support for picture resizing
--> add a loading progress for media previews
--> add a pager for media files
--> add a download option in media list
+-> layout seems to be too wide for a modern mobile phone
 -> add a previewer for movies
 -> make camera frames positions configurable
 -> add a view log functionality
index f5cd3a3e6fb838a5233aafc6aea679471eedb840..c346b361b317dfa21eeb0439f301d86ce77a8080 100644 (file)
@@ -120,6 +120,7 @@ def list_pictures(camera_config):
         picture_files.append({
             'path': path,
             'momentStr': utils.pretty_date_time(datetime.datetime.fromtimestamp(os.path.getmtime(p))),
+            'sizeStr': utils.pretty_size(os.path.getsize(p)),
             'timestamp': os.path.getmtime(p)
         })
     
@@ -135,6 +136,7 @@ def list_movies(camera_config):
     movie_files = [{
         'path': p[len(target_dir):],
         'momentStr': utils.pretty_date_time(datetime.datetime.fromtimestamp(os.path.getmtime(p))),
+        'sizeStr': utils.pretty_size(os.path.getsize(p)),
         'timestamp': os.path.getmtime(p)
     } for p in full_paths]
     
index 25c9d65189597c66f300e49647d559369fda1be7..d6fff8ac085a58baf6674423e689a287b1806fb7 100644 (file)
@@ -169,6 +169,22 @@ def pretty_duration(duration):
     return format.format(d=days, h=hours, m=minutes, s=seconds)
 
 
+def pretty_size(size):
+    if size < 1024: # less than 1kB
+        size, unit = size, 'B'
+    
+    elif size < 1024 * 1024: # less than 1MB
+        size, unit = size / 1024.0, 'kB'
+        
+    elif size < 1024 * 1024 * 1024: # less than 1GB
+        size, unit = size / 1024.0 / 1024, 'MB'
+    
+    else: # greater than or equal to 1GB
+        size, unit = size / 1024.0 / 1024 / 1024, 'GB'
+    
+    return '%.1f %s' % (size, unit)
+    
+
 def get_disk_usage(path):
     logging.debug('getting disk usage for path %(path)s...' % {
             'path': path})
index d90e787797ab9e8d0fc931c13b9195d1748ec74b..100a04198dc35f381f619595c856aa618aaabde2 100644 (file)
@@ -356,6 +356,48 @@ table.add-camera-dialog input[type=password] {
 
 
 div.media-dialog {
+}
+
+div.media-dialog-groups {
+    text-align: center;
+}
+
+div.media-dialog-group-button {
+    display: inline-block;
+    height: 1.5em;
+    line-height: 1.5em;
+    text-align: center;
+    margin: 0em 0.2em 0.3em 0.2em;
+    padding: 0px 0.5em;
+    background-color: #414141;
+    color: #3498db;
+    border-radius: 3px;
+    transition: all 0.1s linear;
+    cursor: pointer;
+}
+
+div.media-dialog-group-button:HOVER {
+    background-color: #515151;
+}
+
+div.media-dialog-group-button:ACTIVE {
+    background-color: #414141;
+}
+
+div.media-dialog-group-button.current {
+    background-color: #317CAD;
+    color: white;
+}
+
+div.media-dialog-group-button.current:HOVER {
+    background-color: #3498db;
+}
+
+div.media-dialog-group-button.current:ACTIVE {
+    background-color: #317CAD;
+}
+
+div.media-dialog-list {
     overflow: auto;
 }
 
@@ -398,7 +440,7 @@ div.media-list-entry-name {
     white-space: nowrap;
 }
 
-div.media-list-entry-moment {
+div.media-list-entry-details {
     font-size: 1em;
     text-align: center;
     white-space: nowrap;
index f1fd3250f578b472d881b9032a92006a388df164..e07616f06a705160be0066ccb3fa7961d0ce536a 100644 (file)
@@ -1043,6 +1043,7 @@ function runPictureDialog(entries, pos) {
         nextArrow.css('display', pos < entries.length - 1 ? '' : 'none');
         
         $('div.modal-container').find('span.modal-title:last').html(entry.name);
+        updateModalDialogPosition();
     }
     
     prevArrow.click(function () {
@@ -1295,58 +1296,24 @@ function runAddCameraDialog() {
 
 
 function runMediaDialog(cameraId, mediaType) {
-    var dialogDiv = $(
-            '<div class="media-dialog">' +
-            '</div>');
+    var dialogDiv = $('<div class="media-dialog"></div>');
+    var mediaListDiv = $('<div class="media-dialog-list"></div>');
+    var groupsDiv = $('<div class="media-dialog-groups"></div>');
+    
+    dialogDiv.append(groupsDiv);
+    dialogDiv.append(mediaListDiv);
     
     var windowWidth = $(window).width();
     
     if (windowWidth <= 1000) {
-        dialogDiv.width(parseInt(windowWidth * 0.9));
-        dialogDiv.height(parseInt(windowWidth * 0.9 * 480 / 640));
+        mediaListDiv.width(parseInt(windowWidth * 0.9));
+        groupsDiv.width(parseInt(windowWidth * 0.9));
+        mediaListDiv.height(parseInt(windowWidth * 0.9 * 480 / 640));
     }
     else {
-        dialogDiv.width(parseInt(windowWidth * 0.5));
-        dialogDiv.height(parseInt(windowWidth * 0.5 * 480 / 640));
-    }
-    
-    function fetchMedia() {
-        var progress = $('<div style="text-align: center; margin: 2px;"><img src="' + staticUrl + 'img/small-progress.gif"></div>');
-        
-        cameraSelect.hide();
-        cameraSelect.before(progress);
-        cameraSelect.parent().find('div').remove(); /* remove any previous progress div */
-        
-        var data = {
-            host: hostEntry.val(),
-            port: portEntry.val(),
-            username: usernameEntry.val(),
-            password: passwordEntry.val()
-        };
-        
-        ajax('GET', '/config/list/', data, function (data) {
-            if (data == null || data.error) {
-                progress.remove();
-                if (passwordEntry.val()) { /* only show an error message when a password is supplied */
-                    showErrorMessage(data && data.error);
-                }
-                
-                return;
-            }
-            
-            cameraSelect.html('');
-            progress.remove();
-            
-            if (data.error || !data.cameras) {
-                return;
-            }
-
-            data.cameras.forEach(function (info) {
-                cameraSelect.append('<option value="' + info.id + '">' + info.name + '</option>');
-            });
-            
-            cameraSelect.show();
-        });
+        mediaListDiv.width(parseInt(windowWidth * 0.5));
+        groupsDiv.width(parseInt(windowWidth * 0.5));
+        mediaListDiv.height(parseInt(windowWidth * 0.45 * 480 / 640));
     }
     
     showModalDialog('<div class="modal-progress"></div>');
@@ -1374,6 +1341,7 @@ function runMediaDialog(cameraId, mediaType) {
                 'name': parts[parts.length - 1],
                 'cameraId': cameraId,
                 'momentStr': media.momentStr,
+                'sizeStr': media.sizeStr,
                 'timestamp': media.timestamp
             });
         });
@@ -1387,20 +1355,17 @@ function runMediaDialog(cameraId, mediaType) {
         var height = tempDiv.height();
         tempDiv.remove();
         
+        /* prepare the entries within each group */
         keys.forEach(function (key) {
-            if (key) {
-                var groupDiv = $('<div class="media-list-group-title">' + key + '</div>');
-                dialogDiv.append(groupDiv);
-            }
-            
             var entries = groups[key];
             entries.sortKey(function (e) {return e.timestamp;});
             
             entries.forEach(function (entry, pos) {
                 var entryDiv = $('<div class="media-list-entry"></div>');
                 
-                var previewImg = $('<img class="media-list-preview" src="/' + mediaType + '/' + cameraId + '/preview' + entry.path + '?height=' + height + '"/>');
+                var previewImg = $('<img class="media-list-preview" src="' + staticUrl + 'img/modal-progress.gif"/>');
                 entryDiv.append(previewImg);
+                previewImg[0]._src = '/' + mediaType + '/' + cameraId + '/preview' + entry.path + '?height=' + height;
                 
                 var downloadButton = $('<div class="media-list-download-button button">download</div>');
                 entryDiv.append(downloadButton);
@@ -1408,29 +1373,81 @@ function runMediaDialog(cameraId, mediaType) {
                 var nameDiv = $('<div class="media-list-entry-name">' + entry.name + '</div>');
                 entryDiv.append(nameDiv);
                 
-                var momentDiv = $('<div class="media-list-entry-moment">' + entry.momentStr + '</div>');
-                entryDiv.append(momentDiv);
+                var detailsDiv = $('<div class="media-list-entry-details"></div>');
+                detailsDiv.html(entry.momentStr + ' | ' + entry.sizeStr);
+                entryDiv.append(detailsDiv);
                 
-                downloadButton.click(function () {
+                downloadButton[0]._onClick = function () {
                     window.location.href = '/picture/' + cameraId + '/download' + entry.path;
                     
                     return false;
-                });
+                };
                 
-                entryDiv.click(function () {
+                entryDiv[0]._onClick = function () {
                     if (mediaType === 'picture') {
                         runPictureDialog(entries, pos);
                     }
-                });
+                };
                 
-                dialogDiv.append(entryDiv);
+                entry.div = entryDiv;
             });
         });
         
-        /* scroll to bottom */
-        dialogDiv.find('img.media-list-preview:last').load(function () {
-            dialogDiv.scrollTop(dialogDiv.prop('scrollHeight'));
-        });
+        function showGroup(key) {
+            groupsDiv.find('div.media-dialog-group-button').each(function () {
+                var $this = $(this);
+                if (this.key == key) {
+                    $this.addClass('current');
+                }
+                else {
+                    $this.removeClass('current');
+                }
+            });
+            
+            mediaListDiv.html('');
+
+//            var groupDiv = $('<div class="media-list-group-title">' + (key || '(ungrouped)') + '</div>');
+//            dialogDiv.append(groupDiv);
+            
+            var entries = groups[key];
+            entries.forEach(function (entry) {
+                mediaListDiv.append(entry.div);
+                entry.div.click(entry.div[0]._onClick);
+                
+                var downloadButton = entry.div.find('div.media-list-download-button');
+                downloadButton.click(downloadButton[0]._onClick);
+            });
+            
+            setTimeout(function () {
+                mediaListDiv.find('img.media-list-preview').each(function () {
+                    if (this._src) {
+                        this.src = this._src;
+                    }
+                    
+                    delete this._src;
+                });
+            }, 1000);
+        }
+        
+        if (keys.length) {
+            keys.forEach(function (key) {
+                var groupButton = $('<div class="media-dialog-group-button"></div>');
+                groupButton.text(key || '(ungrouped)');
+                groupButton[0].key = key;
+                
+                groupButton.click(function () {
+                    showGroup(key);
+                });
+                
+                groupsDiv.append(groupButton);
+            });
+            
+            showGroup(keys[0]);
+        }
+        else {
+            groupsDiv.html('(no media files)');
+            mediaListDiv.remove();
+        }
         
         var title;
         if (mediaType === 'picture') {
index 88198bbc990984a4d925e04170d8fd1cfcf71c94..2b188b41e630e07db8a21b8f8ba4c8091d69beda 100644 (file)
@@ -687,6 +687,9 @@ function makeModalDialogTitleBar(options) {
     
     var titleSpan = $('<span class="modal-title"></span>');
     titleSpan.html(options.title || '');
+    if (options.closeButton) {
+        titleSpan.css('margin', '0px 1.5em');
+    }
     
     titleBar.append(titleSpan);