]> www.vanbest.org Git - motioneye-debian/commitdiff
added disk usage support
authorCalin Crisan <ccrisan@gmail.com>
Sat, 9 Nov 2013 15:15:45 +0000 (17:15 +0200)
committerCalin Crisan <ccrisan@gmail.com>
Sat, 9 Nov 2013 15:18:01 +0000 (17:18 +0200)
doc/todo.txt
src/config.py
src/handlers.py
src/utils.py
static/css/main.css
static/js/main.js
static/js/ui.js
templates/main.html

index f231b0ad2d003dd7a5fe870cbfb2edcf758eed4f..ae41efb774aaec6cefa6f7da2ad79a9c9c7182a7 100644 (file)
@@ -1,4 +1,3 @@
--> disk usage at bottom
 -> make camera frames positions configurable
 -> add a view log functionality
 -> add a previewer for snapshots
index ed255b82bce239bf7ea70cf93709fd97c72102b5..851e64ad5bbee8c2bde8a9c43bfa08eb27953ab5 100644 (file)
@@ -23,6 +23,7 @@ import re
 from collections import OrderedDict
 
 import settings
+import utils
 import v4l2ctl
 
 
@@ -556,9 +557,11 @@ def camera_ui_to_dict(ui):
 
     return data
     
+
 def camera_dict_to_ui(data):
     if data['@proto'] == 'v4l2':
         device_uri = data['videodevice']
+        disk_used, disk_total = utils.get_disk_usage(data['target_dir'])
     
     else:
         device_uri = '%(host)s:%(port)s/config/%(camera_id)s' % {
@@ -567,6 +570,8 @@ def camera_dict_to_ui(data):
                 'host': data['@host'],
                 'port': data['@port'],
                 'camera_id': data['@remote_camera_id']}
+        
+        disk_used, disk_total = data['disk_used'], data['disk_total']
     
     ui = {
         # device
@@ -588,6 +593,8 @@ def camera_dict_to_ui(data):
         'network_username': data['@network_username'],
         'network_password': data['@network_password'],
         'root_directory': data.get('target_dir'),
+        'disk_used': disk_used,
+        'disk_total': disk_total,
         
         # text overlay
         'text_overlay': False,
index d8a04e6ece64ad0cc8aab824f878b992c15db468..309ceae70a71cdeb61908c7a0d6a10b169fd5031 100644 (file)
@@ -486,6 +486,8 @@ class ConfigHandler(BaseHandler):
                 
                 tmp_config = config.camera_ui_to_dict(remote_ui_config)
                 tmp_config.update(camera_config)
+                tmp_config['disk_used'] = remote_ui_config['disk_used']
+                tmp_config['disk_total'] = remote_ui_config['disk_total']
                 ui_config = config.camera_dict_to_ui(tmp_config)
                 ui_config['available_resolutions'] = remote_ui_config['available_resolutions']
                 
@@ -509,7 +511,8 @@ class ConfigHandler(BaseHandler):
             motionctl.restart()
             
         self.finish_json()
-        
+
+
 class SnapshotHandler(BaseHandler):
     @asynchronous
     def get(self, camera_id, op, filename=None):
index c059e941011cb587e44c4ed94c654eb8165670d4..4fad4d8f3569c0f7c9bd5db214915c555830021b 100644 (file)
@@ -16,6 +16,8 @@
 # along with this program.  If not, see <http://www.gnu.org/licenses/>. 
 
 import datetime
+import logging
+import os
 
 
 def pretty_date_time(date_time, tzinfo=None):
@@ -165,3 +167,26 @@ def pretty_duration(duration):
         format = '-' + format
 
     return format.format(d=days, h=hours, m=minutes, s=seconds)
+
+
+def get_disk_usage(path):
+    logging.debug('getting disk usage for path %(path)s...' % {
+            'path': path})
+
+    try:    
+        result = os.statvfs(path)
+    
+    except OSError as e:
+        logging.error('failed to execute statvfs: %(msg)s' % {'msg': unicode(e)})
+        
+        return None
+
+    block_size = result.f_frsize
+    free_blocks = result.f_bfree
+    total_blocks = result.f_blocks
+    
+    free_size = free_blocks * block_size
+    total_size = total_blocks * block_size
+    used_size = total_size - free_size
+    
+    return (used_size, total_size)
index ae0c25155e528dc26356cf343e560fe06198f601..a559729f7fec43509fb1643b3037dee1c224ae14 100644 (file)
@@ -63,15 +63,21 @@ div.footer {
     position: absolute;
     bottom: 5px;
     width: 100%;
-    height: 2.2em;
+    height: 3em;
     font-size: 0.7em;
     color: #aaa;
     text-align: center;
 }
 
+div.copyright-note {
+    border-top: 1px solid #333;
+    padding-top: 0.2em;
+    margin: 0px 15%;
+}
+
 div.page-container {
     transition: all 0.2s linear;
-    padding: 55px 5px 2.2em 5px;
+    padding: 55px 5px 3em 5px;
 }
 
 div.page-container.stretched {
@@ -304,6 +310,35 @@ input[type=text].working-schedule.number {
     width: 50px;
 }
 
+span.disk-usage-text {
+    vertical-align: middle;
+}
+
+div.disk-usage-bar-container {
+    position: relative;
+    width: 90%;
+    height: 1em;
+    border: 1px solid #555;
+    vertical-align: middle;
+    margin: 0px 0.2em;
+    text-align: center;
+    line-height: 1em;
+}
+
+div.disk-usage-bar-fill {
+    position: absolute;
+    left: 0px;
+    top: 0px;
+    bottom: 0px;
+    width: 0%;
+    background-color: #555;
+}
+
+span.disk-usage-percent {
+    font-size: 0.8em;
+    position: relative;
+}
+
 div.rpi,
 tr.rpi {
     display: none;
index 172dcb883ea8483a631d75e9a17c59a8a9d5802c..a210093f9936eb6b61d68783493e4349ac1f3b96 100644 (file)
@@ -604,6 +604,10 @@ function dict2CameraUi(dict) {
     $('#networkUsernameEntry').val(dict['network_username']);
     $('#networkPasswordEntry').val(dict['network_password']);
     $('#rootDirectoryEntry').val(dict['root_directory']);
+    var percent = parseInt(dict['disk_used'] * 100 / dict['disk_total']);
+    $('#diskUsageBarFill').css('width', percent + '%');
+    $('#diskUsageText').html(
+            (dict['disk_used'] / 1073741824).toFixed(1)  + '/' + (dict['disk_total'] / 1073741824).toFixed(1) + ' GB (' + percent + '%)');
     
     /* text overlay */
     $('#textOverlaySwitch')[0].checked = dict['text_overlay'];
index 43a5d85815814c812bcd63d53455ccd57ac85bcd..b4d2d5cda618cddfcd89a315213c3053bc6ad416 100644 (file)
@@ -561,8 +561,8 @@ function updateModalDialogPosition() {
     var modalWidth = container.width();
     var modalHeight = container.height();
     
-    container.css('left', (windowWidth - modalWidth) / 2);
-    container.css('top', (windowHeight - modalHeight) / 2);
+    container.css('left', Math.floor((windowWidth - modalWidth) / 2));
+    container.css('top', Math.floor((windowHeight - modalHeight) / 2));
 }
 
 function makeModalDialogButtons(buttonsInfo) {
index bced036333e5b8bdd46fbe7a236c9c9c52d6cb5a..25a05a7907344dee2e1a58a914f954203f1c03e5 100644 (file)
                         <td class="settings-item-value"><input type="text" class="styled storage" id="rootDirectoryEntry"></td>
                         <td><span class="help-mark" title="the root path (on the selected storage device) where the files will be saved">?</span></td>
                     </tr>
+                    <tr class="settings-item advanced-setting">
+                        <td colspan="100"><div class="settings-item-separator"></div></td>
+                    </tr>
+                    <tr class="settings-item advanced-setting">
+                        <td class="settings-item-label"><span class="settings-item-label">Disk Usage</span></td>
+                        <td class="settings-item-value">
+                            <div class="disk-usage-bar-container">
+                                <div class="disk-usage-bar-fill" id="diskUsageBarFill"></div>
+                                <span class="disk-usage-percent" id="diskUsageText"></span>
+                            </div>
+                        </td>
+                        <td><span class="help-mark" title="the used/total size of the disk where the root directory resides">?</span></td>
+                    </tr>
                 </table>
                 
                 <div class="settings-section-title advanced-setting"><input type="checkbox" class="styled section text-overlay" id="textOverlaySwitch">Text Overlay</div>
             <img class="main-loading-progress" src="{{STATIC_URL}}img/main-loading-progress.gif">
         </div>
         <div class="footer">
-            <div class="system-info">free space: 100MB/300MB</div>
             <div class="copyright-note">copyright &copy; Calin Crisan 2013</div>
         </div> 
     </div>