'share': camera['@network_share_name'],
'username': camera['@network_username'],
'password': camera['@network_password'],
-
})
return mounts
if ui['root_directory'].startswith('/'):
ui['root_directory'] = ui['root_directory'][1:]
data['target_dir'] = os.path.join(mount_point, ui['root_directory'])
+
+ elif ui['storage_device'].startswith('local-disk'):
+ target_dev = ui['storage_device'][10:].replace('-', '/')
+ mounted_partitions = diskctl.list_mounted_partitions()
+ partition = mounted_partitions[target_dev]
+ mount_point = partition['mount_point']
+
+ if ui['root_directory'].startswith('/'):
+ ui['root_directory'] = ui['root_directory'][1:]
+ data['target_dir'] = os.path.normpath(os.path.join(mount_point, ui['root_directory']))
else:
data['target_dir'] = ui['root_directory']
mount_point = smbctl.make_mount_point(data['@network_server'], data['@network_share_name'], data['@network_username'])
ui['root_directory'] = data['target_dir'][len(mount_point):]
+ elif data['@storage_device'].startswith('local-disk'):
+ target_dev = data['@storage_device'][10:].replace('-', '/')
+ mounted_partitions = diskctl.list_mounted_partitions()
+ for partition in mounted_partitions.values():
+ if partition['target'] == target_dev and data['target_dir'].startswith(partition['mount_point']):
+ ui['root_directory'] = data['target_dir'][len(partition['mount_point']):] or '/'
+ break
+
+ else: # not found for some reason
+ logging.error('could not find mounted partition for device "%s" and target dir "%s"' % (target_dev, data['target_dir']))
+ ui['root_directory'] = data['target_dir']
+
else:
ui['root_directory'] = data['target_dir']
data.setdefault('framerate', 2)
data.setdefault('rotate', 0)
- data.setdefault('@storage_device', 'local-disk')
+ data.setdefault('@storage_device', 'custom-path')
data.setdefault('@network_server', '')
data.setdefault('@network_share_name', '')
data.setdefault('@network_username', '')
logging.error('failed to list mounted disks: %s' % e, exc_info=True)
return mounted_disks
+
+
+def list_mounted_partitions():
+ mounted_partitions = {}
+
+ try:
+ disks = _list_disks()
+ mounts_by_target = dict((m['target'], m) for m in _list_mounts())
+
+ for disk in disks:
+ for partition in disk['partitions']:
+ mount = mounts_by_target.get(partition['target'])
+ if mount:
+ partition.update(mount)
+ mounted_partitions[partition['target']] = partition
+
+ except Exception as e:
+ logging.error('failed to list mounted partitions: %s' % e, exc_info=True)
+
+ return mounted_partitions
});
};
+String.prototype.replaceAll = String.prototype.replaceAll || function (oldStr, newStr) {
+ var p, s = this;
+ while ((p = s.indexOf(oldStr)) >= 0) {
+ s = s.substring(0, p) + newStr + s.substring(p + oldStr.length, s.length);
+ }
+
+ return s.toString();
+};
+
/* UI initialization */
$('#workingScheduleSwitch').change(updateConfigUi);
$('#wifiSwitch').change(updateConfigUi);
+ $('#storageDeviceSelect').change(function () {
+ $('#rootDirectoryEntry').val('/');
+ });
+
+ $('#rootDirectoryEntry').change(function () {
+ if (this.value.charAt(0) !== '/') {
+ this.value = '/' + this.value;
+ }
+ });
+
/* fetch & push handlers */
$('#videoDeviceSelect').change(function () {
if ($('#videoDeviceSelect').val() === 'add') {
}
/* storage device */
- var smbShares = $('#storageDeviceSelect').data('smb_shares');
- if ($('#storageDeviceSelect').val() === 'local-disk' || !smbShares) {
+ if ($('#storageDeviceSelect').val() !== 'network-share') {
$('#networkServerEntry').parents('tr:eq(0)').each(markHide);
$('#networkUsernameEntry').parents('tr:eq(0)').each(markHide);
$('#networkPasswordEntry').parents('tr:eq(0)').each(markHide);
$('#networkShareNameEntry').parents('tr:eq(0)').each(markHide);
}
- if (!smbShares) {
- $('#storageDeviceSelect').parents('tr:eq(0)').each(markHide);
- }
/* auto brightness */
if ($('#autoBrightnessSwitch').get(0).checked) {
$('#framerateSlider').val(dict['framerate']);
/* file storage */
- $('#storageDeviceSelect').data('smb_shares', dict['smb_shares']);
- $('#storageDeviceSelect').val(dict['storage_device']);
+ $('#storageDeviceSelect').empty();
+ dict['available_disks'] = dict['available_disks'] || [];
+ var storageDeviceOptions = {};
+ dict['available_disks'].forEach(function (disk) {
+ disk.partitions.forEach(function (partition) {
+ var target = partition.target.replaceAll('/', '-');
+ var option = 'local-disk' + target;
+ var label = partition.vendor;
+ if (partition.model) {
+ label += ' ' + partition.model;
+ }
+ if (disk.partitions.length > 1) {
+ label += '/part' + partition.part_no;
+ }
+ label += ' (' + partition.target + ')';
+
+ storageDeviceOptions[option] = true;
+
+ $('#storageDeviceSelect').append('<option value="' + option + '">' + label + '</option>');
+ });
+ });
+ $('#storageDeviceSelect').append('<option value="custom-path">Custom Path</option>');
+ if (dict['smb_shares']) {
+ $('#storageDeviceSelect').append('<option value="network-share">Network Share</option>');
+ }
+
+ if (storageDeviceOptions[dict['storage_device']]) {
+ $('#storageDeviceSelect').val(dict['storage_device']);
+ }
+ else {
+ $('#storageDeviceSelect').val('custom-path');
+ }
$('#networkServerEntry').val(dict['network_server']);
$('#networkShareNameEntry').val(dict['network_share_name']);
$('#networkUsernameEntry').val(dict['network_username']);
<td class="settings-item-label"><span class="settings-item-label">Storage Device</span></td>
<td class="settings-item-value">
<select class="styled storage" id="storageDeviceSelect">
- <option value="local-disk">Local Disk</option>
- <option value="network-share">Network Share</option>
</select>
</td>
<td><span class="help-mark" title="indicates the storage device where the image and video files will be saved">?</span></td>