simo 2.7.14__py3-none-any.whl → 2.7.16__py3-none-any.whl
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Potentially problematic release.
This version of simo might be problematic. Click here for more details.
- simo/__pycache__/__init__.cpython-312.pyc +0 -0
- simo/__pycache__/asgi.cpython-312.pyc +0 -0
- simo/__pycache__/celeryc.cpython-312.pyc +0 -0
- simo/__pycache__/conf.cpython-312.pyc +0 -0
- simo/__pycache__/settings.cpython-312.pyc +0 -0
- simo/__pycache__/urls.cpython-312.pyc +0 -0
- simo/automation/__pycache__/__init__.cpython-312.pyc +0 -0
- simo/automation/__pycache__/app_widgets.cpython-312.pyc +0 -0
- simo/automation/__pycache__/controllers.cpython-312.pyc +0 -0
- simo/automation/__pycache__/forms.cpython-312.pyc +0 -0
- simo/automation/__pycache__/gateways.cpython-312.pyc +0 -0
- simo/automation/__pycache__/helpers.cpython-312.pyc +0 -0
- simo/automation/__pycache__/models.cpython-312.pyc +0 -0
- simo/automation/__pycache__/serializers.cpython-312.pyc +0 -0
- simo/automation/__pycache__/state.cpython-312.pyc +0 -0
- simo/automation/gateways.py +6 -5
- simo/automation/migrations/__pycache__/0001_initial.cpython-312.pyc +0 -0
- simo/automation/migrations/__pycache__/0002_update_helpers_in_scripts.cpython-312.pyc +0 -0
- simo/automation/migrations/__pycache__/__init__.cpython-312.pyc +0 -0
- simo/backups/__pycache__/__init__.cpython-312.pyc +0 -0
- simo/backups/__pycache__/admin.cpython-312.pyc +0 -0
- simo/backups/__pycache__/dynamic_settings.cpython-312.pyc +0 -0
- simo/backups/__pycache__/models.cpython-312.pyc +0 -0
- simo/backups/migrations/__pycache__/0001_initial.cpython-312.pyc +0 -0
- simo/backups/migrations/__pycache__/0002_backuplog_backup_level_backup_size.cpython-312.pyc +0 -0
- simo/backups/migrations/__pycache__/0003_alter_backuplog_options_alter_backup_size.cpython-312.pyc +0 -0
- simo/backups/migrations/__pycache__/0004_alter_backup_options_alter_backuplog_options_and_more.cpython-312.pyc +0 -0
- simo/backups/migrations/__pycache__/__init__.cpython-312.pyc +0 -0
- simo/core/__pycache__/__init__.cpython-312.pyc +0 -0
- simo/core/__pycache__/admin.cpython-312.pyc +0 -0
- simo/core/__pycache__/api.cpython-312.pyc +0 -0
- simo/core/__pycache__/api_auth.cpython-312.pyc +0 -0
- simo/core/__pycache__/api_meta.cpython-312.pyc +0 -0
- simo/core/__pycache__/api_meta.cpython-38.pyc +0 -0
- simo/core/__pycache__/app_widgets.cpython-312.pyc +0 -0
- simo/core/__pycache__/apps.cpython-312.pyc +0 -0
- simo/core/__pycache__/auto_urls.cpython-312.pyc +0 -0
- simo/core/__pycache__/autocomplete_views.cpython-312.pyc +0 -0
- simo/core/__pycache__/base_types.cpython-312.pyc +0 -0
- simo/core/__pycache__/context.cpython-312.pyc +0 -0
- simo/core/__pycache__/controllers.cpython-312.pyc +0 -0
- simo/core/__pycache__/dynamic_settings.cpython-312.pyc +0 -0
- simo/core/__pycache__/events.cpython-312.pyc +0 -0
- simo/core/__pycache__/filters.cpython-312.pyc +0 -0
- simo/core/__pycache__/form_fields.cpython-312.pyc +0 -0
- simo/core/__pycache__/form_fields.cpython-38.pyc +0 -0
- simo/core/__pycache__/forms.cpython-312.pyc +0 -0
- simo/core/__pycache__/gateways.cpython-312.pyc +0 -0
- simo/core/__pycache__/loggers.cpython-312.pyc +0 -0
- simo/core/__pycache__/managers.cpython-312.pyc +0 -0
- simo/core/__pycache__/middleware.cpython-312.pyc +0 -0
- simo/core/__pycache__/models.cpython-312.pyc +0 -0
- simo/core/__pycache__/permissions.cpython-312.pyc +0 -0
- simo/core/__pycache__/routing.cpython-312.pyc +0 -0
- simo/core/__pycache__/serializers.cpython-312.pyc +0 -0
- simo/core/__pycache__/serializers.cpython-38.pyc +0 -0
- simo/core/__pycache__/signal_receivers.cpython-312.pyc +0 -0
- simo/core/__pycache__/socket_consumers.cpython-312.pyc +0 -0
- simo/core/__pycache__/storage.cpython-312.pyc +0 -0
- simo/core/__pycache__/tasks.cpython-312.pyc +0 -0
- simo/core/__pycache__/todos.cpython-312.pyc +0 -0
- simo/core/__pycache__/views.cpython-312.pyc +0 -0
- simo/core/__pycache__/widgets.cpython-312.pyc +0 -0
- simo/core/api_meta.py +2 -1
- simo/core/db_backend/__pycache__/__init__.cpython-312.pyc +0 -0
- simo/core/db_backend/__pycache__/base.cpython-312.pyc +0 -0
- simo/core/drf_braces/__pycache__/__init__.cpython-312.pyc +0 -0
- simo/core/drf_braces/__pycache__/utils.cpython-312.pyc +0 -0
- simo/core/drf_braces/fields/__pycache__/__init__.cpython-312.pyc +0 -0
- simo/core/drf_braces/fields/__pycache__/_fields.cpython-312.pyc +0 -0
- simo/core/drf_braces/fields/__pycache__/custom.cpython-312.pyc +0 -0
- simo/core/drf_braces/fields/__pycache__/mixins.cpython-312.pyc +0 -0
- simo/core/drf_braces/fields/__pycache__/modified.cpython-312.pyc +0 -0
- simo/core/drf_braces/serializers/__pycache__/__init__.cpython-312.pyc +0 -0
- simo/core/drf_braces/serializers/__pycache__/form_serializer.cpython-312.pyc +0 -0
- simo/core/form_fields.py +6 -0
- simo/core/management/__pycache__/__init__.cpython-312.pyc +0 -0
- simo/core/management/commands/__pycache__/__init__.cpython-312.pyc +0 -0
- simo/core/management/commands/__pycache__/gateways_manager.cpython-312.pyc +0 -0
- simo/core/management/commands/__pycache__/on_http_start.cpython-38.pyc +0 -0
- simo/core/management/commands/on_http_start.py +16 -0
- simo/core/migrations/0049_alter_gateway_type.py +18 -0
- simo/core/migrations/__pycache__/0001_initial.cpython-312.pyc +0 -0
- simo/core/migrations/__pycache__/0002_load_icons.cpython-312.pyc +0 -0
- simo/core/migrations/__pycache__/0003_create_default_zones_and_categories.cpython-312.pyc +0 -0
- simo/core/migrations/__pycache__/0004_create_generic.cpython-312.pyc +0 -0
- simo/core/migrations/__pycache__/0005_component_subcomponents.cpython-312.pyc +0 -0
- simo/core/migrations/__pycache__/0006_alter_component_subcomponents.cpython-312.pyc +0 -0
- simo/core/migrations/__pycache__/0007_component_change_init_to.cpython-312.pyc +0 -0
- simo/core/migrations/__pycache__/0008_alter_component_change_init_to.cpython-312.pyc +0 -0
- simo/core/migrations/__pycache__/0009_auto_20220707_1404.cpython-312.pyc +0 -0
- simo/core/migrations/__pycache__/0010_historyaggregate.cpython-312.pyc +0 -0
- simo/core/migrations/__pycache__/0011_component_last_change.cpython-312.pyc +0 -0
- simo/core/migrations/__pycache__/0012_instance.cpython-312.pyc +0 -0
- simo/core/migrations/__pycache__/0013_auto_20231003_0754.cpython-312.pyc +0 -0
- simo/core/migrations/__pycache__/0014_zone_instance.cpython-312.pyc +0 -0
- simo/core/migrations/__pycache__/0015_auto_20231004_1113.cpython-312.pyc +0 -0
- simo/core/migrations/__pycache__/0016_auto_20231004_1113.cpython-312.pyc +0 -0
- simo/core/migrations/__pycache__/0017_auto_20231004_1313.cpython-312.pyc +0 -0
- simo/core/migrations/__pycache__/0018_auto_20231005_0622.cpython-312.pyc +0 -0
- simo/core/migrations/__pycache__/0019_alter_gateway_type.cpython-312.pyc +0 -0
- simo/core/migrations/__pycache__/0020_component_meta.cpython-312.pyc +0 -0
- simo/core/migrations/__pycache__/0021_auto_20231020_1041.cpython-312.pyc +0 -0
- simo/core/migrations/__pycache__/0022_auto_20231221_0735.cpython-312.pyc +0 -0
- simo/core/migrations/__pycache__/0023_auto_20231229_1352.cpython-312.pyc +0 -0
- simo/core/migrations/__pycache__/0024_alter_instance_device_report_history_days.cpython-312.pyc +0 -0
- simo/core/migrations/__pycache__/0025_auto_20240122_1321.cpython-312.pyc +0 -0
- simo/core/migrations/__pycache__/0026_category_instance.cpython-312.pyc +0 -0
- simo/core/migrations/__pycache__/0027_remove_component_tags.cpython-312.pyc +0 -0
- simo/core/migrations/__pycache__/0028_rename_subcomponents_component_slaves.cpython-312.pyc +0 -0
- simo/core/migrations/__pycache__/0029_auto_20240229_1331.cpython-312.pyc +0 -0
- simo/core/migrations/__pycache__/0030_alter_instance_timezone.cpython-312.pyc +0 -0
- simo/core/migrations/__pycache__/0031_auto_20240429_1231.cpython-312.pyc +0 -0
- simo/core/migrations/__pycache__/0032_auto_20240506_0834.cpython-312.pyc +0 -0
- simo/core/migrations/__pycache__/0033_auto_20240509_0821.cpython-312.pyc +0 -0
- simo/core/migrations/__pycache__/0034_component_error_msg.cpython-312.pyc +0 -0
- simo/core/migrations/__pycache__/0035_remove_instance_share_location.cpython-312.pyc +0 -0
- simo/core/migrations/__pycache__/0036_auto_20240521_0823.cpython-312.pyc +0 -0
- simo/core/migrations/__pycache__/0037_auto_20240606_1057.cpython-312.pyc +0 -0
- simo/core/migrations/__pycache__/0038_remove_instance_cover_image_and_more.cpython-312.pyc +0 -0
- simo/core/migrations/__pycache__/0039_instance_is_active_alter_instance_timezone.cpython-312.pyc +0 -0
- simo/core/migrations/__pycache__/0040_alter_instance_name.cpython-312.pyc +0 -0
- simo/core/migrations/__pycache__/0041_alter_instance_slug.cpython-312.pyc +0 -0
- simo/core/migrations/__pycache__/0042_alter_instance_timezone.cpython-312.pyc +0 -0
- simo/core/migrations/__pycache__/0043_alter_category_instance_alter_instance_timezone_and_more.cpython-312.pyc +0 -0
- simo/core/migrations/__pycache__/0044_alter_gateway_type.cpython-312.pyc +0 -0
- simo/core/migrations/__pycache__/0045_alter_instance_device_report_history_days_and_more.cpython-312.pyc +0 -0
- simo/core/migrations/__pycache__/0046_component_value_translation_alter_gateway_type.cpython-312.pyc +0 -0
- simo/core/migrations/__pycache__/0047_alter_component_value_translation.cpython-312.pyc +0 -0
- simo/core/migrations/__pycache__/0048_publicfile_privatefile.cpython-312.pyc +0 -0
- simo/core/migrations/__pycache__/0049_alter_gateway_type.cpython-312.pyc +0 -0
- simo/core/migrations/__pycache__/__init__.cpython-312.pyc +0 -0
- simo/core/serializers.py +8 -3
- simo/core/templatetags/__pycache__/__init__.cpython-312.pyc +0 -0
- simo/core/templatetags/__pycache__/components_list.cpython-312.pyc +0 -0
- simo/core/utils/__pycache__/__init__.cpython-312.pyc +0 -0
- simo/core/utils/__pycache__/admin.cpython-312.pyc +0 -0
- simo/core/utils/__pycache__/api.cpython-312.pyc +0 -0
- simo/core/utils/__pycache__/cache.cpython-312.pyc +0 -0
- simo/core/utils/__pycache__/config_values.cpython-312.pyc +0 -0
- simo/core/utils/__pycache__/converters.cpython-312.pyc +0 -0
- simo/core/utils/__pycache__/easing.cpython-312.pyc +0 -0
- simo/core/utils/__pycache__/form_fields.cpython-312.pyc +0 -0
- simo/core/utils/__pycache__/form_widgets.cpython-312.pyc +0 -0
- simo/core/utils/__pycache__/formsets.cpython-312.pyc +0 -0
- simo/core/utils/__pycache__/helpers.cpython-312.pyc +0 -0
- simo/core/utils/__pycache__/json.cpython-312.pyc +0 -0
- simo/core/utils/__pycache__/logs.cpython-312.pyc +0 -0
- simo/core/utils/__pycache__/mixins.cpython-312.pyc +0 -0
- simo/core/utils/__pycache__/model_helpers.cpython-312.pyc +0 -0
- simo/core/utils/__pycache__/operations.cpython-312.pyc +0 -0
- simo/core/utils/__pycache__/relay.cpython-312.pyc +0 -0
- simo/core/utils/__pycache__/serialization.cpython-312.pyc +0 -0
- simo/core/utils/__pycache__/type_constants.cpython-312.pyc +0 -0
- simo/core/utils/__pycache__/validators.cpython-312.pyc +0 -0
- simo/fleet/__pycache__/__init__.cpython-312.pyc +0 -0
- simo/fleet/__pycache__/admin.cpython-312.pyc +0 -0
- simo/fleet/__pycache__/api.cpython-312.pyc +0 -0
- simo/fleet/__pycache__/auto_urls.cpython-312.pyc +0 -0
- simo/fleet/__pycache__/base_types.cpython-312.pyc +0 -0
- simo/fleet/__pycache__/controllers.cpython-312.pyc +0 -0
- simo/fleet/__pycache__/forms.cpython-312.pyc +0 -0
- simo/fleet/__pycache__/gateways.cpython-312.pyc +0 -0
- simo/fleet/__pycache__/managers.cpython-312.pyc +0 -0
- simo/fleet/__pycache__/models.cpython-312.pyc +0 -0
- simo/fleet/__pycache__/routing.cpython-312.pyc +0 -0
- simo/fleet/__pycache__/serializers.cpython-312.pyc +0 -0
- simo/fleet/__pycache__/socket_consumers.cpython-312.pyc +0 -0
- simo/fleet/__pycache__/utils.cpython-312.pyc +0 -0
- simo/fleet/__pycache__/views.cpython-312.pyc +0 -0
- simo/fleet/controllers.py +8 -0
- simo/fleet/migrations/__pycache__/0001_initial.cpython-312.pyc +0 -0
- simo/fleet/migrations/__pycache__/0002_auto_20220422_0743.cpython-312.pyc +0 -0
- simo/fleet/migrations/__pycache__/0003_auto_20220422_0752.cpython-312.pyc +0 -0
- simo/fleet/migrations/__pycache__/0004_auto_20220422_0818.cpython-312.pyc +0 -0
- simo/fleet/migrations/__pycache__/0005_auto_20220428_0900.cpython-312.pyc +0 -0
- simo/fleet/migrations/__pycache__/0006_rename_mac_colonel_uid.cpython-312.pyc +0 -0
- simo/fleet/migrations/__pycache__/0007_colonel_socket_connected.cpython-312.pyc +0 -0
- simo/fleet/migrations/__pycache__/0008_i2cinterface.cpython-312.pyc +0 -0
- simo/fleet/migrations/__pycache__/0009_i2cinterface_name.cpython-312.pyc +0 -0
- simo/fleet/migrations/__pycache__/0010_auto_20220602_0746.cpython-312.pyc +0 -0
- simo/fleet/migrations/__pycache__/0011_i2cinterface_freq.cpython-312.pyc +0 -0
- simo/fleet/migrations/__pycache__/0012_colonel_logs_stream.cpython-312.pyc +0 -0
- simo/fleet/migrations/__pycache__/0013_alter_colonel_last_seen.cpython-312.pyc +0 -0
- simo/fleet/migrations/__pycache__/0014_auto_20220614_0659.cpython-312.pyc +0 -0
- simo/fleet/migrations/__pycache__/0015_auto_20220614_0754.cpython-312.pyc +0 -0
- simo/fleet/migrations/__pycache__/0016_auto_20220704_0840.cpython-312.pyc +0 -0
- simo/fleet/migrations/__pycache__/0017_alter_colonel_secret.cpython-312.pyc +0 -0
- simo/fleet/migrations/__pycache__/0018_colonel_instance.cpython-312.pyc +0 -0
- simo/fleet/migrations/__pycache__/0019_auto_20231006_0749.cpython-312.pyc +0 -0
- simo/fleet/migrations/__pycache__/0020_instanceoptions.cpython-312.pyc +0 -0
- simo/fleet/migrations/__pycache__/0021_auto_20231006_0819.cpython-312.pyc +0 -0
- simo/fleet/migrations/__pycache__/0022_remove_colonel_secret.cpython-312.pyc +0 -0
- simo/fleet/migrations/__pycache__/0023_colonel_is_authorized.cpython-312.pyc +0 -0
- simo/fleet/migrations/__pycache__/0024_colonel_pwm_frequency.cpython-312.pyc +0 -0
- simo/fleet/migrations/__pycache__/0025_auto_20240130_1334.cpython-312.pyc +0 -0
- simo/fleet/migrations/__pycache__/0026_rename_i2cinterface_scl_pin_and_more.cpython-312.pyc +0 -0
- simo/fleet/migrations/__pycache__/0027_auto_20240306_0802.cpython-312.pyc +0 -0
- simo/fleet/migrations/__pycache__/0028_remove_i2cinterface_scl_pin_no_and_more.cpython-312.pyc +0 -0
- simo/fleet/migrations/__pycache__/0029_alter_i2cinterface_scl_pin_and_more.cpython-312.pyc +0 -0
- simo/fleet/migrations/__pycache__/0030_colonelpin_label_alter_colonel_type.cpython-312.pyc +0 -0
- simo/fleet/migrations/__pycache__/0031_alter_colonel_type.cpython-312.pyc +0 -0
- simo/fleet/migrations/__pycache__/0032_auto_20240415_0736.cpython-312.pyc +0 -0
- simo/fleet/migrations/__pycache__/0033_auto_20240415_0736.cpython-312.pyc +0 -0
- simo/fleet/migrations/__pycache__/0034_auto_20240418_0735.cpython-312.pyc +0 -0
- simo/fleet/migrations/__pycache__/0035_auto_20240514_0855.cpython-312.pyc +0 -0
- simo/fleet/migrations/__pycache__/0036_auto_20240605_0702.cpython-312.pyc +0 -0
- simo/fleet/migrations/__pycache__/0037_alter_colonelpin_options_alter_colonelpin_no_and_more.cpython-312.pyc +0 -0
- simo/fleet/migrations/__pycache__/0038_alter_colonel_type.cpython-312.pyc +0 -0
- simo/fleet/migrations/__pycache__/0039_auto_20241016_1047.cpython-312.pyc +0 -0
- simo/fleet/migrations/__pycache__/0040_alter_colonel_pwm_frequency.cpython-312.pyc +0 -0
- simo/fleet/migrations/__pycache__/0041_alter_colonel_instance_and_more.cpython-312.pyc +0 -0
- simo/fleet/migrations/__pycache__/0042_auto_20241120_1028.cpython-312.pyc +0 -0
- simo/fleet/migrations/__pycache__/0043_auto_20241203_0930.cpython-312.pyc +0 -0
- simo/fleet/migrations/__pycache__/0044_auto_20241210_0707.cpython-312.pyc +0 -0
- simo/fleet/migrations/__pycache__/__init__.cpython-312.pyc +0 -0
- simo/generic/__pycache__/__init__.cpython-312.pyc +0 -0
- simo/generic/__pycache__/app_widgets.cpython-312.pyc +0 -0
- simo/generic/__pycache__/base_types.cpython-312.pyc +0 -0
- simo/generic/__pycache__/controllers.cpython-312.pyc +0 -0
- simo/generic/__pycache__/forms.cpython-312.pyc +0 -0
- simo/generic/__pycache__/gateways.cpython-312.pyc +0 -0
- simo/generic/__pycache__/models.cpython-312.pyc +0 -0
- simo/generic/__pycache__/routing.cpython-312.pyc +0 -0
- simo/generic/__pycache__/socket_consumers.cpython-312.pyc +0 -0
- simo/generic/controllers.py +10 -0
- simo/generic/forms.py +15 -11
- simo/generic/gateways.py +43 -43
- simo/generic/migrations/__pycache__/0001_initial.cpython-312.pyc +0 -0
- simo/generic/migrations/__pycache__/0002_auto_20241126_0726.cpython-312.pyc +0 -0
- simo/generic/migrations/__pycache__/__init__.cpython-312.pyc +0 -0
- simo/multimedia/__pycache__/__init__.cpython-312.pyc +0 -0
- simo/multimedia/__pycache__/admin.cpython-312.pyc +0 -0
- simo/multimedia/__pycache__/api.cpython-312.pyc +0 -0
- simo/multimedia/__pycache__/app_widgets.cpython-312.pyc +0 -0
- simo/multimedia/__pycache__/app_widgets.cpython-38.pyc +0 -0
- simo/multimedia/__pycache__/auto_urls.cpython-312.pyc +0 -0
- simo/multimedia/__pycache__/base_types.cpython-312.pyc +0 -0
- simo/multimedia/__pycache__/controllers.cpython-312.pyc +0 -0
- simo/multimedia/__pycache__/forms.cpython-312.pyc +0 -0
- simo/multimedia/__pycache__/models.cpython-312.pyc +0 -0
- simo/multimedia/__pycache__/serializers.cpython-312.pyc +0 -0
- simo/multimedia/__pycache__/views.cpython-312.pyc +0 -0
- simo/multimedia/admin.py +7 -7
- simo/multimedia/app_widgets.py +1 -1
- simo/multimedia/auto_urls.py +5 -2
- simo/multimedia/controllers.py +17 -12
- simo/multimedia/migrations/0006_remove_sound_length_sound_duration.py +22 -0
- simo/multimedia/migrations/__pycache__/0001_initial.cpython-312.pyc +0 -0
- simo/multimedia/migrations/__pycache__/0002_sound_length.cpython-312.pyc +0 -0
- simo/multimedia/migrations/__pycache__/0003_alter_sound_length.cpython-312.pyc +0 -0
- simo/multimedia/migrations/__pycache__/0004_auto_20231023_1055.cpython-312.pyc +0 -0
- simo/multimedia/migrations/__pycache__/0005_remove_sound_slug_sound_date_uploaded.cpython-312.pyc +0 -0
- simo/multimedia/migrations/__pycache__/0006_remove_sound_length_sound_duration.cpython-312.pyc +0 -0
- simo/multimedia/migrations/__pycache__/__init__.cpython-312.pyc +0 -0
- simo/multimedia/models.py +8 -4
- simo/multimedia/views.py +63 -1
- simo/notifications/__pycache__/__init__.cpython-312.pyc +0 -0
- simo/notifications/__pycache__/admin.cpython-312.pyc +0 -0
- simo/notifications/__pycache__/api.cpython-312.pyc +0 -0
- simo/notifications/__pycache__/models.cpython-312.pyc +0 -0
- simo/notifications/__pycache__/serializers.cpython-312.pyc +0 -0
- simo/notifications/migrations/__pycache__/0001_initial.cpython-312.pyc +0 -0
- simo/notifications/migrations/__pycache__/0002_notification_instance.cpython-312.pyc +0 -0
- simo/notifications/migrations/__pycache__/0003_alter_notification_instance.cpython-312.pyc +0 -0
- simo/notifications/migrations/__pycache__/__init__.cpython-312.pyc +0 -0
- simo/urls.py +6 -2
- simo/users/__pycache__/__init__.cpython-312.pyc +0 -0
- simo/users/__pycache__/admin.cpython-312.pyc +0 -0
- simo/users/__pycache__/api.cpython-312.pyc +0 -0
- simo/users/__pycache__/apps.cpython-312.pyc +0 -0
- simo/users/__pycache__/auth_backends.cpython-312.pyc +0 -0
- simo/users/__pycache__/auto_urls.cpython-312.pyc +0 -0
- simo/users/__pycache__/dynamic_settings.cpython-312.pyc +0 -0
- simo/users/__pycache__/managers.cpython-312.pyc +0 -0
- simo/users/__pycache__/middleware.cpython-312.pyc +0 -0
- simo/users/__pycache__/models.cpython-312.pyc +0 -0
- simo/users/__pycache__/permissions.cpython-312.pyc +0 -0
- simo/users/__pycache__/serializers.cpython-312.pyc +0 -0
- simo/users/__pycache__/sso_urls.cpython-312.pyc +0 -0
- simo/users/__pycache__/sso_views.cpython-312.pyc +0 -0
- simo/users/__pycache__/utils.cpython-312.pyc +0 -0
- simo/users/__pycache__/views.cpython-312.pyc +0 -0
- simo/users/migrations/__pycache__/0001_initial.cpython-312.pyc +0 -0
- simo/users/migrations/__pycache__/0002_componentpermission.cpython-312.pyc +0 -0
- simo/users/migrations/__pycache__/0003_create_roles_and_system_user.cpython-312.pyc +0 -0
- simo/users/migrations/__pycache__/0004_user_secret_key.cpython-312.pyc +0 -0
- simo/users/migrations/__pycache__/0005_permissionsrole_instance.cpython-312.pyc +0 -0
- simo/users/migrations/__pycache__/0006_auto_20231003_0850.cpython-312.pyc +0 -0
- simo/users/migrations/__pycache__/0007_auto_20231003_1228.cpython-312.pyc +0 -0
- simo/users/migrations/__pycache__/0008_auto_20231003_1229.cpython-312.pyc +0 -0
- simo/users/migrations/__pycache__/0009_remove_user_role.cpython-312.pyc +0 -0
- simo/users/migrations/__pycache__/0010_auto_20231004_1313.cpython-312.pyc +0 -0
- simo/users/migrations/__pycache__/0011_auto_20231004_1313.cpython-312.pyc +0 -0
- simo/users/migrations/__pycache__/0012_alter_userinstancerole_unique_together.cpython-312.pyc +0 -0
- simo/users/migrations/__pycache__/0013_remove_user_roles.cpython-312.pyc +0 -0
- simo/users/migrations/__pycache__/0014_user_roles.cpython-312.pyc +0 -0
- simo/users/migrations/__pycache__/0015_remove_user_at_home.cpython-312.pyc +0 -0
- simo/users/migrations/__pycache__/0016_auto_20231005_1050.cpython-312.pyc +0 -0
- simo/users/migrations/__pycache__/0017_auto_20231221_0735.cpython-312.pyc +0 -0
- simo/users/migrations/__pycache__/0018_user_is_god.cpython-312.pyc +0 -0
- simo/users/migrations/__pycache__/0019_auto_20231221_1155.cpython-312.pyc +0 -0
- simo/users/migrations/__pycache__/0020_rename_is_god_user_is_master.cpython-312.pyc +0 -0
- simo/users/migrations/__pycache__/0021_alter_permissionsrole_instance.cpython-312.pyc +0 -0
- simo/users/migrations/__pycache__/0022_userdevicereportlog_instance.cpython-312.pyc +0 -0
- simo/users/migrations/__pycache__/0023_auto_20240105_0719.cpython-312.pyc +0 -0
- simo/users/migrations/__pycache__/0024_fingerprint.cpython-312.pyc +0 -0
- simo/users/migrations/__pycache__/0025_rename_name_fingerprint_type_and_more.cpython-312.pyc +0 -0
- simo/users/migrations/__pycache__/0026_fingerprint_name.cpython-312.pyc +0 -0
- simo/users/migrations/__pycache__/0027_permissionsrole_can_manage_components.cpython-312.pyc +0 -0
- simo/users/migrations/__pycache__/0028_auto_20240506_1146.cpython-312.pyc +0 -0
- simo/users/migrations/__pycache__/0029_alter_instanceuser_instance.cpython-312.pyc +0 -0
- simo/users/migrations/__pycache__/0030_userdevice_users.cpython-312.pyc +0 -0
- simo/users/migrations/__pycache__/0031_auto_20240923_1115.cpython-312.pyc +0 -0
- simo/users/migrations/__pycache__/0032_remove_userdevice_user_alter_userdevice_users.cpython-312.pyc +0 -0
- simo/users/migrations/__pycache__/0033_alter_user_ssh_key.cpython-312.pyc +0 -0
- simo/users/migrations/__pycache__/0034_instanceuser_last_seen_location_and_more.cpython-312.pyc +0 -0
- simo/users/migrations/__pycache__/0035_instanceuser_last_seen_speed_kmh_and_more.cpython-312.pyc +0 -0
- simo/users/migrations/__pycache__/0036_instanceuser_phone_on_charge_user_phone_on_charge.cpython-312.pyc +0 -0
- simo/users/migrations/__pycache__/0037_rename_last_seen_location_datetime_instanceuser_last_seen_and_more.cpython-312.pyc +0 -0
- simo/users/migrations/__pycache__/0038_userdevicereportlog_at_home_and_more.cpython-312.pyc +0 -0
- simo/users/migrations/__pycache__/0039_auto_20241117_1039.cpython-312.pyc +0 -0
- simo/users/migrations/__pycache__/0040_userdevicereportlog_location_smoothed_and_more.cpython-312.pyc +0 -0
- simo/users/migrations/__pycache__/0041_userdevicereportlog_speed_kmh_received.cpython-312.pyc +0 -0
- simo/users/migrations/__pycache__/0042_remove_userdevicereportlog_location_smoothed_and_more.cpython-312.pyc +0 -0
- simo/users/migrations/__pycache__/0043_userdevicereportlog_avg_speed_kmh.cpython-312.pyc +0 -0
- simo/users/migrations/__pycache__/__init__.cpython-312.pyc +0 -0
- simo-2.7.16.dist-info/METADATA +56 -0
- {simo-2.7.14.dist-info → simo-2.7.16.dist-info}/RECORD +333 -27
- {simo-2.7.14.dist-info → simo-2.7.16.dist-info}/WHEEL +1 -1
- simo-2.7.14.dist-info/METADATA +0 -54
- {simo-2.7.14.dist-info → simo-2.7.16.dist-info}/LICENSE.md +0 -0
- {simo-2.7.14.dist-info → simo-2.7.16.dist-info}/entry_points.txt +0 -0
- {simo-2.7.14.dist-info → simo-2.7.16.dist-info}/top_level.txt +0 -0
simo/fleet/controllers.py
CHANGED
|
@@ -72,6 +72,14 @@ class FleeDeviceMixin:
|
|
|
72
72
|
config[key] = val
|
|
73
73
|
return config
|
|
74
74
|
|
|
75
|
+
def _call_cmd(self, method, *args, **kwargs):
|
|
76
|
+
GatewayObjectCommand(
|
|
77
|
+
self.component.gateway,
|
|
78
|
+
Colonel(id=self.component.config['colonel']),
|
|
79
|
+
id=self.component.id, command='call', method=method,
|
|
80
|
+
args=args, kwargs=kwargs
|
|
81
|
+
).publish()
|
|
82
|
+
|
|
75
83
|
|
|
76
84
|
class BasicSensorMixin:
|
|
77
85
|
gateway_class = FleetGatewayHandler
|
|
Binary file
|
|
Binary file
|
|
Binary file
|
|
Binary file
|
|
Binary file
|
|
Binary file
|
|
Binary file
|
simo/fleet/migrations/__pycache__/0028_remove_i2cinterface_scl_pin_no_and_more.cpython-312.pyc
ADDED
|
Binary file
|
|
Binary file
|
|
Binary file
|
|
Binary file
|
|
Binary file
|
|
Binary file
|
|
Binary file
|
|
Binary file
|
|
Binary file
|
|
Binary file
|
|
Binary file
|
|
Binary file
|
|
Binary file
|
|
Binary file
|
|
Binary file
|
|
Binary file
|
simo/generic/controllers.py
CHANGED
|
@@ -1059,6 +1059,16 @@ class AudioAlert(Switch):
|
|
|
1059
1059
|
name = _("Audio Alert")
|
|
1060
1060
|
config_form = AudioAlertConfigForm
|
|
1061
1061
|
|
|
1062
|
+
def send(self, value):
|
|
1063
|
+
for player in Component.objects.filter(
|
|
1064
|
+
id__in=self.component.config['players']
|
|
1065
|
+
):
|
|
1066
|
+
if value:
|
|
1067
|
+
player.play_alert(self.component.id)
|
|
1068
|
+
else:
|
|
1069
|
+
self.component.set(False)
|
|
1070
|
+
player.cancel_alert()
|
|
1071
|
+
|
|
1062
1072
|
|
|
1063
1073
|
class StateSelect(ControllerBase):
|
|
1064
1074
|
gateway_class = GenericGatewayHandler
|
simo/generic/forms.py
CHANGED
|
@@ -7,7 +7,7 @@ from django.db.models import Q
|
|
|
7
7
|
from django.utils.translation import gettext_lazy as _
|
|
8
8
|
from django.core.files.uploadedfile import InMemoryUploadedFile
|
|
9
9
|
from simo.core.forms import HiddenField, BaseComponentForm
|
|
10
|
-
from simo.core.models import
|
|
10
|
+
from simo.core.models import Component
|
|
11
11
|
from simo.core.controllers import (
|
|
12
12
|
NumericSensor, MultiSensor, Switch, Dimmer
|
|
13
13
|
)
|
|
@@ -22,6 +22,7 @@ from simo.core.form_fields import (
|
|
|
22
22
|
)
|
|
23
23
|
from simo.core.forms import DimmerConfigForm, SwitchForm
|
|
24
24
|
from simo.core.form_fields import SoundField
|
|
25
|
+
from simo.multimedia.models import Sound
|
|
25
26
|
|
|
26
27
|
ACTION_METHODS = (
|
|
27
28
|
('turn_on', "Turn ON"), ('turn_off', "Turn OFF"),
|
|
@@ -625,8 +626,9 @@ class AudioAlertConfigForm(BaseComponentForm):
|
|
|
625
626
|
loop = forms.BooleanField(initial=False, required=False)
|
|
626
627
|
volume = forms.IntegerField(initial=30, min_value=2, max_value=100)
|
|
627
628
|
players = Select2ModelMultipleChoiceField(
|
|
628
|
-
queryset=Component.objects.
|
|
629
|
+
queryset=Component.objects.filter(base_type='audio-player'),
|
|
629
630
|
url='autocomplete-component',
|
|
631
|
+
forward=(forward.Const(['audio-player',], 'base_type'),)
|
|
630
632
|
)
|
|
631
633
|
|
|
632
634
|
def __init__(self, *args, **kwargs):
|
|
@@ -669,24 +671,26 @@ class AudioAlertConfigForm(BaseComponentForm):
|
|
|
669
671
|
|
|
670
672
|
return self.cleaned_data['sound']
|
|
671
673
|
|
|
672
|
-
|
|
673
674
|
def save(self, commit=True):
|
|
674
675
|
obj = super().save(commit=commit)
|
|
675
676
|
if type(self.cleaned_data['sound']) != InMemoryUploadedFile:
|
|
676
677
|
return obj
|
|
677
678
|
|
|
678
|
-
|
|
679
|
-
|
|
679
|
+
sound = Sound(
|
|
680
|
+
name=self.cleaned_data['sound'].name,
|
|
681
|
+
duration=self.cleaned_data['sound'].duration
|
|
682
|
+
)
|
|
683
|
+
sound.file.save(
|
|
680
684
|
self.cleaned_data['sound'].name, self.cleaned_data['sound'],
|
|
681
685
|
save=True
|
|
682
686
|
)
|
|
683
|
-
|
|
684
|
-
id=self.instance.config.get('
|
|
685
|
-
)
|
|
686
|
-
|
|
687
|
-
org.delete()
|
|
688
|
-
self.instance.config['public_file_id'] = public_file.id
|
|
687
|
+
Sound.objects.filter(
|
|
688
|
+
id=self.instance.config.get('sound_id', 0)
|
|
689
|
+
).delete()
|
|
690
|
+
self.instance.config['sound_id'] = sound.id
|
|
689
691
|
self.instance.config['duration'] = self.cleaned_data['sound'].duration
|
|
692
|
+
self.instance.config['stream_url'] = sound.stream_url()
|
|
693
|
+
self.instance.config['file_url'] = sound.get_absolute_url()
|
|
690
694
|
self.instance.config['sound'] = self.cleaned_data['sound'].name
|
|
691
695
|
self.instance.save()
|
|
692
696
|
return obj
|
simo/generic/gateways.py
CHANGED
|
@@ -130,49 +130,49 @@ class GroupButtonsHandler:
|
|
|
130
130
|
group.toggle()
|
|
131
131
|
|
|
132
132
|
|
|
133
|
-
class AudioAlertsHandler:
|
|
134
|
-
|
|
135
|
-
|
|
136
|
-
|
|
137
|
-
|
|
138
|
-
|
|
139
|
-
|
|
140
|
-
|
|
141
|
-
|
|
142
|
-
|
|
143
|
-
|
|
144
|
-
|
|
145
|
-
|
|
146
|
-
|
|
147
|
-
|
|
148
|
-
|
|
149
|
-
|
|
150
|
-
|
|
151
|
-
|
|
152
|
-
|
|
153
|
-
|
|
154
|
-
|
|
155
|
-
|
|
156
|
-
|
|
157
|
-
|
|
158
|
-
|
|
159
|
-
|
|
160
|
-
|
|
161
|
-
|
|
162
|
-
|
|
163
|
-
|
|
164
|
-
|
|
165
|
-
|
|
166
|
-
|
|
167
|
-
|
|
168
|
-
|
|
169
|
-
|
|
170
|
-
|
|
171
|
-
|
|
133
|
+
# class AudioAlertsHandler:
|
|
134
|
+
#
|
|
135
|
+
# def control_audio_alert(self, component, val):
|
|
136
|
+
# if val:
|
|
137
|
+
# public_file = PublicFile.objects.filter(
|
|
138
|
+
# component=component
|
|
139
|
+
# ).first()
|
|
140
|
+
# if not public_file:
|
|
141
|
+
# return
|
|
142
|
+
# uri = f"http://{get_self_ip()}{public_file.get_absolute_url()}"
|
|
143
|
+
# loop = component.config.get('loop', False)
|
|
144
|
+
# for pl_id in component.config.get('players', []):
|
|
145
|
+
# player = Component.objects.filter(
|
|
146
|
+
# id=pl_id, base_type='audio-player'
|
|
147
|
+
# ).first()
|
|
148
|
+
# if not player:
|
|
149
|
+
# continue
|
|
150
|
+
# player.play_alert(
|
|
151
|
+
# uri,
|
|
152
|
+
# component.config.get('loop', False),
|
|
153
|
+
# component.config.get('volume', 50)
|
|
154
|
+
# )
|
|
155
|
+
# if not loop:
|
|
156
|
+
# def set_done(comp):
|
|
157
|
+
# comp.set(False)
|
|
158
|
+
# threading.Timer(
|
|
159
|
+
# component.config.get('duration', 1),
|
|
160
|
+
# set_done, args=[component]
|
|
161
|
+
# )
|
|
162
|
+
# component.set(True)
|
|
163
|
+
# else:
|
|
164
|
+
# for pl_id in component.config.get('players', []):
|
|
165
|
+
# player = Component.objects.filter(
|
|
166
|
+
# id=pl_id, base_type='audio-player'
|
|
167
|
+
# ).first()
|
|
168
|
+
# if not player:
|
|
169
|
+
# continue
|
|
170
|
+
# player.cancel_alert()
|
|
171
|
+
# component.set(False)
|
|
172
172
|
|
|
173
173
|
|
|
174
174
|
class GenericGatewayHandler(
|
|
175
|
-
BaseObjectCommandsGatewayHandler, GroupButtonsHandler
|
|
175
|
+
BaseObjectCommandsGatewayHandler, GroupButtonsHandler
|
|
176
176
|
):
|
|
177
177
|
name = "Generic"
|
|
178
178
|
config_form = BaseGatewayForm
|
|
@@ -268,7 +268,7 @@ class GenericGatewayHandler(
|
|
|
268
268
|
|
|
269
269
|
def on_mqtt_message(self, client, userdata, msg):
|
|
270
270
|
print("Mqtt message: ", msg.payload)
|
|
271
|
-
from simo.generic.controllers import AlarmGroup
|
|
271
|
+
from simo.generic.controllers import AlarmGroup#, #AudioAlert
|
|
272
272
|
|
|
273
273
|
payload = json.loads(msg.payload)
|
|
274
274
|
drop_current_instance()
|
|
@@ -278,8 +278,8 @@ class GenericGatewayHandler(
|
|
|
278
278
|
try:
|
|
279
279
|
if component.controller_uid == AlarmGroup.uid:
|
|
280
280
|
self.control_alarm_group(component, payload.get('set_val'))
|
|
281
|
-
elif component.controller_uid == AudioAlert.uid:
|
|
282
|
-
|
|
281
|
+
# elif component.controller_uid == AudioAlert.uid:
|
|
282
|
+
# self.control_audio_alert(component, payload.get('set_val'))
|
|
283
283
|
else:
|
|
284
284
|
component.controller.set(payload.get('set_val'))
|
|
285
285
|
except Exception:
|
|
Binary file
|
|
Binary file
|
|
Binary file
|
|
Binary file
|
|
Binary file
|
|
Binary file
|
|
Binary file
|
|
Binary file
|
|
Binary file
|
|
Binary file
|
|
Binary file
|
|
Binary file
|
|
Binary file
|
|
Binary file
|
simo/multimedia/admin.py
CHANGED
|
@@ -7,23 +7,23 @@ from .forms import SoundModelForm
|
|
|
7
7
|
|
|
8
8
|
@admin.register(Sound)
|
|
9
9
|
class SoundAdmin(admin.ModelAdmin):
|
|
10
|
-
list_display = 'id', 'name', 'file', '
|
|
10
|
+
list_display = 'id', 'name', 'file', 'duration_display', 'date_uploaded'
|
|
11
11
|
search_fields = 'name', 'file'
|
|
12
12
|
list_display_links = 'id', 'name',
|
|
13
13
|
form = SoundModelForm
|
|
14
|
-
readonly_fields = '
|
|
14
|
+
readonly_fields = 'duration_display',
|
|
15
15
|
|
|
16
|
-
def
|
|
17
|
-
if obj and obj.
|
|
18
|
-
return str(timedelta(seconds=obj.
|
|
16
|
+
def duration_display(self, obj=None):
|
|
17
|
+
if obj and obj.duration != None:
|
|
18
|
+
return str(timedelta(seconds=obj.duration))
|
|
19
19
|
|
|
20
|
-
|
|
20
|
+
duration_display.short_description = 'duration'
|
|
21
21
|
|
|
22
22
|
def save_model(self, request, obj, form, change):
|
|
23
23
|
super().save_model(request, obj, form, change)
|
|
24
24
|
# need to keep it here as using admin interface skips post_save signals
|
|
25
25
|
try:
|
|
26
|
-
obj.
|
|
26
|
+
obj.duration = int(
|
|
27
27
|
librosa.core.get_duration(
|
|
28
28
|
sr=22050, filename=obj.file.path
|
|
29
29
|
)
|
simo/multimedia/app_widgets.py
CHANGED
simo/multimedia/auto_urls.py
CHANGED
|
@@ -1,10 +1,13 @@
|
|
|
1
1
|
from django.urls import path, re_path
|
|
2
|
-
from .views import SoundAutocomplete
|
|
2
|
+
from .views import SoundAutocomplete, sound_stream
|
|
3
3
|
|
|
4
4
|
|
|
5
5
|
urlpatterns = [
|
|
6
6
|
path(
|
|
7
|
-
'autocomplete-sound',
|
|
7
|
+
'autocomplete-sound/',
|
|
8
8
|
SoundAutocomplete.as_view(), name='autocomplete-sound'
|
|
9
|
+
),
|
|
10
|
+
path(
|
|
11
|
+
'sound-<int:sound_id>-stream/', sound_stream, name='sound-stream'
|
|
9
12
|
)
|
|
10
13
|
]
|
simo/multimedia/controllers.py
CHANGED
|
@@ -17,6 +17,7 @@ class BasePlayer(Switch):
|
|
|
17
17
|
'duration': None,
|
|
18
18
|
'position': None,
|
|
19
19
|
'title': None,
|
|
20
|
+
'image_url': None,
|
|
20
21
|
'library': []
|
|
21
22
|
}
|
|
22
23
|
default_value = 'stopped'
|
|
@@ -89,18 +90,22 @@ class BasePlayer(Switch):
|
|
|
89
90
|
assert 0 <= volume <= 100
|
|
90
91
|
self.send({"play_uri": uri, 'volume': volume})
|
|
91
92
|
|
|
92
|
-
def play_alert(self, val, loop=False, volume=None):
|
|
93
|
-
|
|
94
|
-
|
|
95
|
-
|
|
96
|
-
|
|
97
|
-
|
|
98
|
-
|
|
99
|
-
|
|
100
|
-
|
|
101
|
-
|
|
102
|
-
|
|
103
|
-
|
|
93
|
+
# def play_alert(self, val, loop=False, volume=None):
|
|
94
|
+
# '''
|
|
95
|
+
# Plays alert and goes back to whatever was playing initially
|
|
96
|
+
# :param val: uri
|
|
97
|
+
# :param loop: Repeat infinitely
|
|
98
|
+
# :param volume: volume at which to play
|
|
99
|
+
# :return:
|
|
100
|
+
# '''
|
|
101
|
+
# assert type(val) == str
|
|
102
|
+
# if volume:
|
|
103
|
+
# assert 0 <= volume <= 100
|
|
104
|
+
# self.send({"alert": val, 'loop': loop, 'volume': volume})
|
|
105
|
+
|
|
106
|
+
|
|
107
|
+
def play_alert(self, id):
|
|
108
|
+
self.send({"alert": id})
|
|
104
109
|
|
|
105
110
|
def cancel_alert(self):
|
|
106
111
|
'''Cancel alert if it's currently playing'''
|
|
@@ -0,0 +1,22 @@
|
|
|
1
|
+
# Generated by Django 4.2.10 on 2024-12-22 07:42
|
|
2
|
+
|
|
3
|
+
from django.db import migrations, models
|
|
4
|
+
|
|
5
|
+
|
|
6
|
+
class Migration(migrations.Migration):
|
|
7
|
+
|
|
8
|
+
dependencies = [
|
|
9
|
+
('multimedia', '0005_remove_sound_slug_sound_date_uploaded'),
|
|
10
|
+
]
|
|
11
|
+
|
|
12
|
+
operations = [
|
|
13
|
+
migrations.RemoveField(
|
|
14
|
+
model_name='sound',
|
|
15
|
+
name='length',
|
|
16
|
+
),
|
|
17
|
+
migrations.AddField(
|
|
18
|
+
model_name='sound',
|
|
19
|
+
name='duration',
|
|
20
|
+
field=models.PositiveIntegerField(default=0, editable=False, help_text='Sound duration in seconds'),
|
|
21
|
+
),
|
|
22
|
+
]
|
|
Binary file
|
|
Binary file
|
simo/multimedia/migrations/__pycache__/0005_remove_sound_slug_sound_date_uploaded.cpython-312.pyc
ADDED
|
Binary file
|
simo/multimedia/migrations/__pycache__/0006_remove_sound_length_sound_duration.cpython-312.pyc
ADDED
|
Binary file
|
|
Binary file
|
simo/multimedia/models.py
CHANGED
|
@@ -1,4 +1,5 @@
|
|
|
1
1
|
import os, librosa
|
|
2
|
+
from django.urls import reverse
|
|
2
3
|
from django.db import models
|
|
3
4
|
from django.db.models.signals import post_save, post_delete
|
|
4
5
|
from django.dispatch import receiver
|
|
@@ -15,8 +16,8 @@ class Sound(models.Model):
|
|
|
15
16
|
)
|
|
16
17
|
)
|
|
17
18
|
note = models.TextField(null=True, blank=True)
|
|
18
|
-
|
|
19
|
-
editable=False, default=0, help_text='Sound
|
|
19
|
+
duration = models.PositiveIntegerField(
|
|
20
|
+
editable=False, default=0, help_text='Sound duration in seconds'
|
|
20
21
|
)
|
|
21
22
|
date_uploaded = models.DateTimeField(auto_now_add=True)
|
|
22
23
|
|
|
@@ -26,11 +27,14 @@ class Sound(models.Model):
|
|
|
26
27
|
def get_absolute_url(self):
|
|
27
28
|
return self.file.url
|
|
28
29
|
|
|
30
|
+
def stream_url(self):
|
|
31
|
+
return reverse('sound-stream', kwargs={'sound_id': self.id})
|
|
32
|
+
|
|
29
33
|
|
|
30
34
|
@receiver(post_save, sender=Sound)
|
|
31
35
|
def determine_duration(sender, instance, created, **kwargs):
|
|
32
|
-
if not instance.
|
|
33
|
-
instance.
|
|
36
|
+
if not instance.duration:
|
|
37
|
+
instance.duration = int(
|
|
34
38
|
librosa.core.get_duration(
|
|
35
39
|
sr=22050, filename=instance.file.path
|
|
36
40
|
)
|
simo/multimedia/views.py
CHANGED
|
@@ -1,4 +1,9 @@
|
|
|
1
|
+
import re, os
|
|
1
2
|
from django.http import Http404
|
|
3
|
+
from django.conf import settings
|
|
4
|
+
from wsgiref.util import FileWrapper
|
|
5
|
+
from django.shortcuts import get_object_or_404
|
|
6
|
+
from django.http import StreamingHttpResponse
|
|
2
7
|
from dal import autocomplete
|
|
3
8
|
from simo.core.utils.helpers import search_queryset
|
|
4
9
|
from .models import Sound
|
|
@@ -16,4 +21,61 @@ class SoundAutocomplete(autocomplete.Select2QuerySetView):
|
|
|
16
21
|
qs = qs.filter(pk__in=self.request.GET['value'].split(','))
|
|
17
22
|
elif self.q:
|
|
18
23
|
qs = search_queryset(qs, self.q, ('name', 'slug'))
|
|
19
|
-
return qs
|
|
24
|
+
return qs
|
|
25
|
+
|
|
26
|
+
|
|
27
|
+
|
|
28
|
+
|
|
29
|
+
|
|
30
|
+
def file_iterator(file_path, chunk_size=8192, offset=0, length=None):
|
|
31
|
+
with open(file_path, "rb") as f:
|
|
32
|
+
f.seek(offset, os.SEEK_SET)
|
|
33
|
+
remaining = length
|
|
34
|
+
while True:
|
|
35
|
+
bytes_length = (
|
|
36
|
+
chunk_size
|
|
37
|
+
if remaining is None
|
|
38
|
+
else min(remaining, chunk_size)
|
|
39
|
+
)
|
|
40
|
+
data = f.read(bytes_length)
|
|
41
|
+
if not data:
|
|
42
|
+
break
|
|
43
|
+
if remaining:
|
|
44
|
+
remaining -= len(data)
|
|
45
|
+
yield data
|
|
46
|
+
|
|
47
|
+
|
|
48
|
+
|
|
49
|
+
def sound_stream(request, sound_id):
|
|
50
|
+
sound = get_object_or_404(Sound, id=sound_id)
|
|
51
|
+
path = sound.file.path
|
|
52
|
+
content_type = "audio/" + path.split('.')[-1]
|
|
53
|
+
|
|
54
|
+
range_header = request.META.get("HTTP_RANGE", "").strip()
|
|
55
|
+
RANGE_RE = re.compile(r"bytes\s*=\s*(\d+)\s*-\s*(\d*)", re.I)
|
|
56
|
+
range_match = RANGE_RE.match(range_header)
|
|
57
|
+
size = os.path.getsize(path)
|
|
58
|
+
|
|
59
|
+
if range_match:
|
|
60
|
+
print(f"RANGE HEADER: {range_header}")
|
|
61
|
+
first_byte, last_byte = range_match.groups()
|
|
62
|
+
first_byte = int(first_byte) if first_byte else 0
|
|
63
|
+
last_byte = (
|
|
64
|
+
first_byte + 1024 * 1024 * 8
|
|
65
|
+
) # The max volume of the response body is 8M per piece
|
|
66
|
+
if last_byte >= size:
|
|
67
|
+
last_byte = size - 1
|
|
68
|
+
length = last_byte - first_byte + 1
|
|
69
|
+
response = StreamingHttpResponse(
|
|
70
|
+
file_iterator(path, offset=first_byte, length=length),
|
|
71
|
+
status=206,
|
|
72
|
+
content_type=content_type,
|
|
73
|
+
)
|
|
74
|
+
response["Content-Range"] = f"bytes {first_byte}-{last_byte}/{size}"
|
|
75
|
+
|
|
76
|
+
else:
|
|
77
|
+
response = StreamingHttpResponse(
|
|
78
|
+
FileWrapper(open(path, "rb")), content_type=content_type
|
|
79
|
+
)
|
|
80
|
+
response["Accept-Ranges"] = "bytes"
|
|
81
|
+
return response
|