boris-behav-obs 9.7__tar.gz → 9.7.2__tar.gz

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.
Files changed (127) hide show
  1. {boris_behav_obs-9.7 → boris_behav_obs-9.7.2}/PKG-INFO +2 -2
  2. {boris_behav_obs-9.7 → boris_behav_obs-9.7.2}/README.md +1 -1
  3. {boris_behav_obs-9.7 → boris_behav_obs-9.7.2}/boris/cmd_arguments.py +2 -0
  4. {boris_behav_obs-9.7 → boris_behav_obs-9.7.2}/boris/config.py +8 -2
  5. {boris_behav_obs-9.7 → boris_behav_obs-9.7.2}/boris/config_file.py +3 -3
  6. {boris_behav_obs-9.7 → boris_behav_obs-9.7.2}/boris/core.py +123 -94
  7. boris_behav_obs-9.7.2/boris/ipc_mpv.py +304 -0
  8. {boris_behav_obs-9.7 → boris_behav_obs-9.7.2}/boris/observation_operations.py +173 -230
  9. {boris_behav_obs-9.7 → boris_behav_obs-9.7.2}/boris/player_dock_widget.py +9 -4
  10. {boris_behav_obs-9.7 → boris_behav_obs-9.7.2}/boris/preferences.py +6 -0
  11. {boris_behav_obs-9.7 → boris_behav_obs-9.7.2}/boris/preferences_ui.py +46 -28
  12. {boris_behav_obs-9.7 → boris_behav_obs-9.7.2}/boris/project_functions.py +8 -0
  13. {boris_behav_obs-9.7 → boris_behav_obs-9.7.2}/boris/utilities.py +77 -56
  14. {boris_behav_obs-9.7 → boris_behav_obs-9.7.2}/boris/version.py +2 -2
  15. {boris_behav_obs-9.7 → boris_behav_obs-9.7.2}/boris/video_operations.py +1 -0
  16. {boris_behav_obs-9.7 → boris_behav_obs-9.7.2}/boris_behav_obs.egg-info/PKG-INFO +2 -2
  17. {boris_behav_obs-9.7 → boris_behav_obs-9.7.2}/boris_behav_obs.egg-info/SOURCES.txt +1 -1
  18. {boris_behav_obs-9.7 → boris_behav_obs-9.7.2}/pyproject.toml +1 -8
  19. boris_behav_obs-9.7/boris/mpv-1.0.3.py +0 -2102
  20. {boris_behav_obs-9.7 → boris_behav_obs-9.7.2}/LICENSE.TXT +0 -0
  21. {boris_behav_obs-9.7 → boris_behav_obs-9.7.2}/MANIFEST.in +0 -0
  22. {boris_behav_obs-9.7 → boris_behav_obs-9.7.2}/README.TXT +0 -0
  23. {boris_behav_obs-9.7 → boris_behav_obs-9.7.2}/boris/__init__.py +0 -0
  24. {boris_behav_obs-9.7 → boris_behav_obs-9.7.2}/boris/__main__.py +0 -0
  25. {boris_behav_obs-9.7 → boris_behav_obs-9.7.2}/boris/about.py +0 -0
  26. {boris_behav_obs-9.7 → boris_behav_obs-9.7.2}/boris/add_modifier.py +0 -0
  27. {boris_behav_obs-9.7 → boris_behav_obs-9.7.2}/boris/add_modifier_ui.py +0 -0
  28. {boris_behav_obs-9.7 → boris_behav_obs-9.7.2}/boris/advanced_event_filtering.py +0 -0
  29. {boris_behav_obs-9.7 → boris_behav_obs-9.7.2}/boris/analysis_plugins/__init__.py +0 -0
  30. {boris_behav_obs-9.7 → boris_behav_obs-9.7.2}/boris/analysis_plugins/_latency.py +0 -0
  31. {boris_behav_obs-9.7 → boris_behav_obs-9.7.2}/boris/analysis_plugins/irr_cohen_kappa.py +0 -0
  32. {boris_behav_obs-9.7 → boris_behav_obs-9.7.2}/boris/analysis_plugins/irr_cohen_kappa_with_modifiers.py +0 -0
  33. {boris_behav_obs-9.7 → boris_behav_obs-9.7.2}/boris/analysis_plugins/irr_weighted_cohen_kappa.py +0 -0
  34. {boris_behav_obs-9.7 → boris_behav_obs-9.7.2}/boris/analysis_plugins/irr_weighted_cohen_kappa_with_modifiers.py +0 -0
  35. {boris_behav_obs-9.7 → boris_behav_obs-9.7.2}/boris/analysis_plugins/list_of_dataframe_columns.py +0 -0
  36. {boris_behav_obs-9.7 → boris_behav_obs-9.7.2}/boris/analysis_plugins/number_of_occurences.py +0 -0
  37. {boris_behav_obs-9.7 → boris_behav_obs-9.7.2}/boris/analysis_plugins/number_of_occurences_by_independent_variable.py +0 -0
  38. {boris_behav_obs-9.7 → boris_behav_obs-9.7.2}/boris/analysis_plugins/time_budget.py +0 -0
  39. {boris_behav_obs-9.7 → boris_behav_obs-9.7.2}/boris/behav_coding_map_creator.py +0 -0
  40. {boris_behav_obs-9.7 → boris_behav_obs-9.7.2}/boris/behavior_binary_table.py +0 -0
  41. {boris_behav_obs-9.7 → boris_behav_obs-9.7.2}/boris/behaviors_coding_map.py +0 -0
  42. {boris_behav_obs-9.7 → boris_behav_obs-9.7.2}/boris/boris_cli.py +0 -0
  43. {boris_behav_obs-9.7 → boris_behav_obs-9.7.2}/boris/coding_pad.py +0 -0
  44. {boris_behav_obs-9.7 → boris_behav_obs-9.7.2}/boris/connections.py +0 -0
  45. {boris_behav_obs-9.7 → boris_behav_obs-9.7.2}/boris/converters.py +0 -0
  46. {boris_behav_obs-9.7 → boris_behav_obs-9.7.2}/boris/converters_ui.py +0 -0
  47. {boris_behav_obs-9.7 → boris_behav_obs-9.7.2}/boris/cooccurence.py +0 -0
  48. {boris_behav_obs-9.7 → boris_behav_obs-9.7.2}/boris/core_qrc.py +0 -0
  49. {boris_behav_obs-9.7 → boris_behav_obs-9.7.2}/boris/core_ui.py +0 -0
  50. {boris_behav_obs-9.7 → boris_behav_obs-9.7.2}/boris/db_functions.py +0 -0
  51. {boris_behav_obs-9.7 → boris_behav_obs-9.7.2}/boris/dev.py +0 -0
  52. {boris_behav_obs-9.7 → boris_behav_obs-9.7.2}/boris/dialog.py +0 -0
  53. {boris_behav_obs-9.7 → boris_behav_obs-9.7.2}/boris/duration_widget.py +0 -0
  54. {boris_behav_obs-9.7 → boris_behav_obs-9.7.2}/boris/edit_event.py +0 -0
  55. {boris_behav_obs-9.7 → boris_behav_obs-9.7.2}/boris/edit_event_ui.py +0 -0
  56. {boris_behav_obs-9.7 → boris_behav_obs-9.7.2}/boris/event_operations.py +0 -0
  57. {boris_behav_obs-9.7 → boris_behav_obs-9.7.2}/boris/events_cursor.py +0 -0
  58. {boris_behav_obs-9.7 → boris_behav_obs-9.7.2}/boris/events_snapshots.py +0 -0
  59. {boris_behav_obs-9.7 → boris_behav_obs-9.7.2}/boris/exclusion_matrix.py +0 -0
  60. {boris_behav_obs-9.7 → boris_behav_obs-9.7.2}/boris/export_events.py +0 -0
  61. {boris_behav_obs-9.7 → boris_behav_obs-9.7.2}/boris/export_observation.py +0 -0
  62. {boris_behav_obs-9.7 → boris_behav_obs-9.7.2}/boris/external_processes.py +0 -0
  63. {boris_behav_obs-9.7 → boris_behav_obs-9.7.2}/boris/geometric_measurement.py +0 -0
  64. {boris_behav_obs-9.7 → boris_behav_obs-9.7.2}/boris/gui_utilities.py +0 -0
  65. {boris_behav_obs-9.7 → boris_behav_obs-9.7.2}/boris/image_overlay.py +0 -0
  66. {boris_behav_obs-9.7 → boris_behav_obs-9.7.2}/boris/import_observations.py +0 -0
  67. {boris_behav_obs-9.7 → boris_behav_obs-9.7.2}/boris/irr.py +0 -0
  68. {boris_behav_obs-9.7 → boris_behav_obs-9.7.2}/boris/latency.py +0 -0
  69. {boris_behav_obs-9.7 → boris_behav_obs-9.7.2}/boris/measurement_widget.py +0 -0
  70. {boris_behav_obs-9.7 → boris_behav_obs-9.7.2}/boris/media_file.py +0 -0
  71. {boris_behav_obs-9.7 → boris_behav_obs-9.7.2}/boris/menu_options.py +0 -0
  72. {boris_behav_obs-9.7 → boris_behav_obs-9.7.2}/boris/modifier_coding_map_creator.py +0 -0
  73. {boris_behav_obs-9.7 → boris_behav_obs-9.7.2}/boris/modifiers_coding_map.py +0 -0
  74. {boris_behav_obs-9.7 → boris_behav_obs-9.7.2}/boris/mpv.py +0 -0
  75. {boris_behav_obs-9.7 → boris_behav_obs-9.7.2}/boris/mpv2.py +0 -0
  76. {boris_behav_obs-9.7 → boris_behav_obs-9.7.2}/boris/observation.py +0 -0
  77. {boris_behav_obs-9.7 → boris_behav_obs-9.7.2}/boris/observation_ui.py +0 -0
  78. {boris_behav_obs-9.7 → boris_behav_obs-9.7.2}/boris/observations_list.py +0 -0
  79. {boris_behav_obs-9.7 → boris_behav_obs-9.7.2}/boris/otx_parser.py +0 -0
  80. {boris_behav_obs-9.7 → boris_behav_obs-9.7.2}/boris/param_panel.py +0 -0
  81. {boris_behav_obs-9.7 → boris_behav_obs-9.7.2}/boris/param_panel_ui.py +0 -0
  82. {boris_behav_obs-9.7 → boris_behav_obs-9.7.2}/boris/plot_data_module.py +0 -0
  83. {boris_behav_obs-9.7 → boris_behav_obs-9.7.2}/boris/plot_events.py +0 -0
  84. {boris_behav_obs-9.7 → boris_behav_obs-9.7.2}/boris/plot_events_rt.py +0 -0
  85. {boris_behav_obs-9.7 → boris_behav_obs-9.7.2}/boris/plot_spectrogram_rt.py +0 -0
  86. {boris_behav_obs-9.7 → boris_behav_obs-9.7.2}/boris/plot_waveform_rt.py +0 -0
  87. {boris_behav_obs-9.7 → boris_behav_obs-9.7.2}/boris/plugins.py +0 -0
  88. {boris_behav_obs-9.7 → boris_behav_obs-9.7.2}/boris/portion/__init__.py +0 -0
  89. {boris_behav_obs-9.7 → boris_behav_obs-9.7.2}/boris/portion/const.py +0 -0
  90. {boris_behav_obs-9.7 → boris_behav_obs-9.7.2}/boris/portion/dict.py +0 -0
  91. {boris_behav_obs-9.7 → boris_behav_obs-9.7.2}/boris/portion/func.py +0 -0
  92. {boris_behav_obs-9.7 → boris_behav_obs-9.7.2}/boris/portion/interval.py +0 -0
  93. {boris_behav_obs-9.7 → boris_behav_obs-9.7.2}/boris/portion/io.py +0 -0
  94. {boris_behav_obs-9.7 → boris_behav_obs-9.7.2}/boris/project.py +0 -0
  95. {boris_behav_obs-9.7 → boris_behav_obs-9.7.2}/boris/project_import_export.py +0 -0
  96. {boris_behav_obs-9.7 → boris_behav_obs-9.7.2}/boris/project_ui.py +0 -0
  97. {boris_behav_obs-9.7 → boris_behav_obs-9.7.2}/boris/qrc_boris.py +0 -0
  98. {boris_behav_obs-9.7 → boris_behav_obs-9.7.2}/boris/qrc_boris5.py +0 -0
  99. {boris_behav_obs-9.7 → boris_behav_obs-9.7.2}/boris/select_modifiers.py +0 -0
  100. {boris_behav_obs-9.7 → boris_behav_obs-9.7.2}/boris/select_observations.py +0 -0
  101. {boris_behav_obs-9.7 → boris_behav_obs-9.7.2}/boris/select_subj_behav.py +0 -0
  102. {boris_behav_obs-9.7 → boris_behav_obs-9.7.2}/boris/state_events.py +0 -0
  103. {boris_behav_obs-9.7 → boris_behav_obs-9.7.2}/boris/subjects_pad.py +0 -0
  104. {boris_behav_obs-9.7 → boris_behav_obs-9.7.2}/boris/synthetic_time_budget.py +0 -0
  105. {boris_behav_obs-9.7 → boris_behav_obs-9.7.2}/boris/time_budget_functions.py +0 -0
  106. {boris_behav_obs-9.7 → boris_behav_obs-9.7.2}/boris/time_budget_widget.py +0 -0
  107. {boris_behav_obs-9.7 → boris_behav_obs-9.7.2}/boris/transitions.py +0 -0
  108. {boris_behav_obs-9.7 → boris_behav_obs-9.7.2}/boris/video_equalizer.py +0 -0
  109. {boris_behav_obs-9.7 → boris_behav_obs-9.7.2}/boris/video_equalizer_ui.py +0 -0
  110. {boris_behav_obs-9.7 → boris_behav_obs-9.7.2}/boris/view_df.py +0 -0
  111. {boris_behav_obs-9.7 → boris_behav_obs-9.7.2}/boris/view_df_ui.py +0 -0
  112. {boris_behav_obs-9.7 → boris_behav_obs-9.7.2}/boris/write_event.py +0 -0
  113. {boris_behav_obs-9.7 → boris_behav_obs-9.7.2}/boris_behav_obs.egg-info/dependency_links.txt +0 -0
  114. {boris_behav_obs-9.7 → boris_behav_obs-9.7.2}/boris_behav_obs.egg-info/entry_points.txt +0 -0
  115. {boris_behav_obs-9.7 → boris_behav_obs-9.7.2}/boris_behav_obs.egg-info/requires.txt +0 -0
  116. {boris_behav_obs-9.7 → boris_behav_obs-9.7.2}/boris_behav_obs.egg-info/top_level.txt +0 -0
  117. {boris_behav_obs-9.7 → boris_behav_obs-9.7.2}/setup.cfg +0 -0
  118. {boris_behav_obs-9.7 → boris_behav_obs-9.7.2}/tests/test_db_functions.py +0 -0
  119. {boris_behav_obs-9.7 → boris_behav_obs-9.7.2}/tests/test_export_observation.py +0 -0
  120. {boris_behav_obs-9.7 → boris_behav_obs-9.7.2}/tests/test_irr.py +0 -0
  121. {boris_behav_obs-9.7 → boris_behav_obs-9.7.2}/tests/test_observation_gui.py +0 -0
  122. {boris_behav_obs-9.7 → boris_behav_obs-9.7.2}/tests/test_otx_parser.py +0 -0
  123. {boris_behav_obs-9.7 → boris_behav_obs-9.7.2}/tests/test_preferences_gui.py +0 -0
  124. {boris_behav_obs-9.7 → boris_behav_obs-9.7.2}/tests/test_project_functions.py +0 -0
  125. {boris_behav_obs-9.7 → boris_behav_obs-9.7.2}/tests/test_time_budget.py +0 -0
  126. {boris_behav_obs-9.7 → boris_behav_obs-9.7.2}/tests/test_utilities.py +0 -0
  127. {boris_behav_obs-9.7 → boris_behav_obs-9.7.2}/tests/test_utilities2.py +0 -0
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: boris-behav-obs
3
- Version: 9.7
3
+ Version: 9.7.2
4
4
  Summary: BORIS - Behavioral Observation Research Interactive Software
5
5
  Author-email: Olivier Friard <olivier.friard@unito.it>
6
6
  License-Expression: GPL-3.0-only
@@ -52,7 +52,7 @@ It provides also some analysis tools like time budget and some plotting function
52
52
  <!-- The BO-RIS paper has more than [![BORIS citations counter](https://penelope.unito.it/friard/boris_scopus_citations.png) citations](https://www.boris.unito.it/citations) in peer-reviewed scientific publications. -->
53
53
 
54
54
 
55
- The BORIS paper has more than 2337 citations in peer-reviewed scientific publications.
55
+ The BORIS paper has more than 2407 citations in peer-reviewed scientific publications.
56
56
 
57
57
 
58
58
 
@@ -14,7 +14,7 @@ It provides also some analysis tools like time budget and some plotting function
14
14
  <!-- The BO-RIS paper has more than [![BORIS citations counter](https://penelope.unito.it/friard/boris_scopus_citations.png) citations](https://www.boris.unito.it/citations) in peer-reviewed scientific publications. -->
15
15
 
16
16
 
17
- The BORIS paper has more than 2337 citations in peer-reviewed scientific publications.
17
+ The BORIS paper has more than 2407 citations in peer-reviewed scientific publications.
18
18
 
19
19
 
20
20
 
@@ -35,6 +35,8 @@ def parse_arguments():
35
35
  parser.add_option("-n", "--nosplashscreen", action="store_true", default=False, help="No splash screen")
36
36
  parser.add_option("-p", "--project", action="store", default="", dest="project", help="Project file")
37
37
  parser.add_option("-o", "--observation", action="store", default="", dest="observation", help="Observation id")
38
+ parser.add_option("-i", "--ipc", action="store_true", default="", dest="ipc", help="MPV IPC mode")
39
+
38
40
  parser.add_option(
39
41
  "-f",
40
42
  "--no-first-launch-dialog",
@@ -22,8 +22,7 @@ This file is part of BORIS.
22
22
 
23
23
  programName: str = "BORIS"
24
24
 
25
-
26
- MACOS_CODE = "darwin"
25
+ # socket for MPV IPC mode
27
26
  MPV_SOCKET = "/tmp/mpvsocket"
28
27
 
29
28
 
@@ -133,6 +132,8 @@ POINT_EVENT_PLOT_COLOR = "black"
133
132
 
134
133
  CHAR_FORBIDDEN_IN_MODIFIERS = "(|),`~"
135
134
 
135
+ FAST_FORWARD_DEFAULT_VALUE:float = 10.0
136
+
136
137
  ADAPT_FAST_JUMP = "adapt_fast_jump"
137
138
  ADAPT_FAST_JUMP_DEFAULT = False
138
139
 
@@ -420,6 +421,10 @@ MPV_HWDEC_AUTOSAFE = "auto-safe"
420
421
  MPV_HWDEC_OPTIONS = (MPV_HWDEC_AUTO, MPV_HWDEC_AUTOSAFE, MPV_HWDEC_NO)
421
422
  MPV_HWDEC_DEFAULT_VALUE = MPV_HWDEC_AUTO
422
423
 
424
+ # frame step size (disabled)
425
+ # FRAME_STEP_SIZE: str = "frame_step_size"
426
+ # FRAME_STEP_SIZE_DEFAULT_VALUE: int = 1
427
+
423
428
  ANALYSIS_PLUGINS = "analysis_plugins"
424
429
  EXCLUDED_PLUGINS = "excluded_plugins"
425
430
  PERSONAL_PLUGINS_DIR = "personal_plugins_dir"
@@ -731,6 +736,7 @@ INIT_PARAM = {
731
736
  MPV_HWDEC: MPV_HWDEC_DEFAULT_VALUE,
732
737
  PROJECT_FILE_INDENTATION: PROJECT_FILE_INDENTATION_DEFAULT_VALUE,
733
738
  f"{MEDIA} tw fields": MEDIA_TW_EVENTS_FIELDS_DEFAULT,
739
+ # FRAME_STEP_SIZE: FRAME_STEP_SIZE_DEFAULT_VALUE,
734
740
  }
735
741
 
736
742
  SDIS_EXT = "sds"
@@ -82,11 +82,11 @@ def read(self):
82
82
 
83
83
  logging.debug(f"time format: {self.timeFormat}")
84
84
 
85
- self.fast = 10
85
+ self.fast = cfg.FAST_FORWARD_DEFAULT_VALUE
86
86
  try:
87
- self.fast = int(settings.value("Time/fast_forward_speed"))
87
+ self.fast = float(settings.value("Time/fast_forward_speed"))
88
88
  except Exception:
89
- self.fast = 10
89
+ self.fast = cfg.FAST_FORWARD_DEFAULT_VALUE
90
90
 
91
91
  logging.debug(f"Time/fast_forward_speed: {self.fast}")
92
92
 
@@ -43,7 +43,6 @@ import locale
43
43
  import tempfile
44
44
  import time
45
45
  import urllib.request
46
- from typing import Union, Tuple
47
46
  from decimal import Decimal as dec
48
47
  from decimal import ROUND_DOWN
49
48
  import gzip
@@ -150,7 +149,7 @@ if util.versiontuple(platform.python_version()) < util.versiontuple(MIN_PYTHON_V
150
149
  logging.critical(msg)
151
150
  sys.exit()
152
151
 
153
- if sys.platform == "darwin": # for MacOS
152
+ if sys.platform.startswith("darwin"): # for MacOS
154
153
  os.environ["LC_ALL"] = "en_US.UTF-8"
155
154
 
156
155
 
@@ -242,7 +241,7 @@ class MainWindow(QMainWindow, Ui_MainWindow):
242
241
  current_player: int = 0 # id of the selected (left click) video player
243
242
 
244
243
  mem_media_name: str = "" # record current media name. Use to check if media changed
245
- mem_playlist_index: Union[int, None] = None
244
+ mem_playlist_index: int | None = None
246
245
  saved_state = None
247
246
  user_move_slider: bool = False
248
247
  observationId: str = "" # current observation id
@@ -400,7 +399,7 @@ class MainWindow(QMainWindow, Ui_MainWindow):
400
399
 
401
400
  # if BORIS is running on Mac lock all dockwidget features
402
401
  # because Qdockwidgets may have a strange behavior
403
- if sys.platform == "darwin":
402
+ if sys.platform.startswith("darwin"):
404
403
  self.action_block_dockwidgets.setChecked(True)
405
404
  self.block_dockwidgets()
406
405
 
@@ -739,7 +738,7 @@ class MainWindow(QMainWindow, Ui_MainWindow):
739
738
  text: str = "Behaviors to show in ethogram list",
740
739
  table: str = cfg.ETHOGRAM,
741
740
  behavior_type: list = cfg.STATE_EVENT_TYPES,
742
- ) -> Tuple[bool, list]:
741
+ ) -> tuple[bool, list]:
743
742
  """
744
743
  allow user to:
745
744
  filter behaviors in ethogram widget
@@ -1428,55 +1427,60 @@ class MainWindow(QMainWindow, Ui_MainWindow):
1428
1427
  if not self.dw_player[player].player.playlist_count:
1429
1428
  return
1430
1429
 
1431
- # one media
1432
- if self.dw_player[player].player.playlist_count == 1:
1433
- if new_time < self.dw_player[player].player.duration:
1434
- new_time_float = round(float(new_time), 3)
1435
-
1436
- self.dw_player[player].player.seek(new_time_float, "absolute+exact")
1430
+ try:
1431
+ # one media
1432
+ if self.dw_player[player].player.playlist_count == 1:
1433
+ if new_time < self.dw_player[player].player.duration:
1434
+ new_time_float = round(float(new_time), 3)
1437
1435
 
1438
- if player == 0 and not self.user_move_slider:
1439
- self.video_slider.setValue(
1440
- round(self.dw_player[0].player.time_pos / self.dw_player[0].player.duration * (cfg.SLIDER_MAXIMUM - 1))
1441
- )
1442
- return 0
1443
- else:
1444
- return 1
1436
+ self.dw_player[player].player.seek(new_time_float, "absolute+exact")
1437
+ self.mpv_timer_out()
1445
1438
 
1446
- # many media
1447
- else:
1448
- if new_time < self.dw_player[player].cumul_media_durations_sec[-1]:
1449
- for idx, d in enumerate(self.dw_player[player].cumul_media_durations_sec[:-1]):
1450
- if d <= new_time < self.dw_player[player].cumul_media_durations_sec[idx + 1]:
1451
- self.dw_player[player].player.playlist_pos = idx
1452
- time.sleep(0.5)
1453
-
1454
- self.dw_player[player].player.seek(
1455
- round(
1456
- float(new_time)
1457
- - sum(self.dw_player[player].media_durations[0 : self.dw_player[player].player.playlist_pos]) / 1000,
1458
- 3,
1459
- ),
1460
- "absolute+exact",
1439
+ if player == 0 and not self.user_move_slider:
1440
+ self.video_slider.setValue(
1441
+ round(self.dw_player[0].player.time_pos / self.dw_player[0].player.duration * (cfg.SLIDER_MAXIMUM - 1))
1461
1442
  )
1443
+ return 0
1444
+ else:
1445
+ return 1
1462
1446
 
1463
- break
1447
+ # many media
1448
+ else:
1449
+ if new_time < self.dw_player[player].cumul_media_durations_sec[-1]:
1450
+ for idx, d in enumerate(self.dw_player[player].cumul_media_durations_sec[:-1]):
1451
+ if d <= new_time < self.dw_player[player].cumul_media_durations_sec[idx + 1]:
1452
+ self.dw_player[player].player.playlist_pos = idx
1453
+ time.sleep(0.5)
1454
+
1455
+ self.dw_player[player].player.seek(
1456
+ round(
1457
+ float(new_time)
1458
+ - sum(self.dw_player[player].media_durations[0 : self.dw_player[player].player.playlist_pos]) / 1000,
1459
+ 3,
1460
+ ),
1461
+ "absolute+exact",
1462
+ )
1464
1463
 
1465
- if player == 0 and not self.user_move_slider:
1466
- self.video_slider.setValue(
1467
- round(self.dw_player[0].player.time_pos / self.dw_player[0].player.duration * (cfg.SLIDER_MAXIMUM - 1))
1464
+ break
1465
+
1466
+ if player == 0 and not self.user_move_slider:
1467
+ self.video_slider.setValue(
1468
+ round(self.dw_player[0].player.time_pos / self.dw_player[0].player.duration * (cfg.SLIDER_MAXIMUM - 1))
1469
+ )
1470
+ return 0
1471
+ else:
1472
+ QMessageBox.warning(
1473
+ self,
1474
+ cfg.programName,
1475
+ (
1476
+ "The indicated position is greater than the total media duration "
1477
+ f"({util.seconds2time(self.dw_player[player].cumul_media_durations_sec[-1])})"
1478
+ ),
1468
1479
  )
1469
- return 0
1470
- else:
1471
- QMessageBox.warning(
1472
- self,
1473
- cfg.programName,
1474
- (
1475
- "The indicated position is greater than the total media duration "
1476
- f"({util.seconds2time(self.dw_player[player].cumul_media_durations_sec[-1])})"
1477
- ),
1478
- )
1479
- return 1
1480
+ return 1
1481
+ except Exception as e:
1482
+ print(f"error in seek mediaplayer function: {e}")
1483
+ return 0
1480
1484
 
1481
1485
  def jump_to(self) -> None:
1482
1486
  """
@@ -3677,14 +3681,19 @@ class MainWindow(QMainWindow, Ui_MainWindow):
3677
3681
  """
3678
3682
  show next frame
3679
3683
  """
3684
+ # frame_step_size = self.config_param.get(cfg.FRAME_STEP_SIZE, cfg.FRAME_STEP_SIZE_DEFAULT_VALUE)
3685
+
3680
3686
  if self.playerType == cfg.IMAGES:
3681
3687
  if self.image_idx < len(self.images_list) - 1:
3682
- self.image_idx += 1
3688
+ self.image_idx += 1 # frame_step_size
3683
3689
  self.extract_frame(self.dw_player[0])
3684
3690
 
3685
3691
  if self.playerType == cfg.MEDIA:
3686
3692
  for dw in self.dw_player:
3693
+ # for _ in range(frame_step_size):
3687
3694
  dw.player.frame_step()
3695
+ # time.sleep(0.5)
3696
+
3688
3697
  if self.geometric_measurements_mode:
3689
3698
  self.extract_frame(dw)
3690
3699
 
@@ -3692,6 +3701,8 @@ class MainWindow(QMainWindow, Ui_MainWindow):
3692
3701
  for idx in self.plot_data:
3693
3702
  self.timer_plot_data_out(self.plot_data[idx])
3694
3703
 
3704
+ self.mpv_timer_out()
3705
+
3695
3706
  if self.geometric_measurements_mode:
3696
3707
  geometric_measurement.redraw_measurements(self)
3697
3708
 
@@ -3709,6 +3720,7 @@ class MainWindow(QMainWindow, Ui_MainWindow):
3709
3720
  if self.playerType == cfg.MEDIA:
3710
3721
  for dw in self.dw_player:
3711
3722
  dw.player.frame_back_step()
3723
+
3712
3724
  if self.geometric_measurements_mode:
3713
3725
  self.extract_frame(dw)
3714
3726
 
@@ -3716,6 +3728,8 @@ class MainWindow(QMainWindow, Ui_MainWindow):
3716
3728
  for idx in self.plot_data:
3717
3729
  self.timer_plot_data_out(self.plot_data[idx])
3718
3730
 
3731
+ self.mpv_timer_out()
3732
+
3719
3733
  if self.geometric_measurements_mode:
3720
3734
  geometric_measurement.redraw_measurements(self)
3721
3735
 
@@ -3855,15 +3869,13 @@ class MainWindow(QMainWindow, Ui_MainWindow):
3855
3869
  write_event.write_event(self, event, cumulative_time)
3856
3870
  # write_event.write_event(self, event, self.getLaps())
3857
3871
 
3858
- def get_frame_index(self, player_idx: int = 0) -> Union[int, str]:
3872
+ def get_frame_index(self, player_idx: int = 0) -> int | str:
3859
3873
  """
3860
3874
  returns frame index for player player_idx
3861
3875
  """
3862
3876
 
3863
- if not sys.platform.startswith(cfg.MACOS_CODE):
3864
- estimated_frame_number = self.dw_player[player_idx].player.estimated_frame_number
3865
- else:
3866
- estimated_frame_number = observation_operations.send_command({"command": ["get_property", "estimated_frame_number"]})
3877
+ estimated_frame_number = self.dw_player[player_idx].player.estimated_frame_number
3878
+
3867
3879
  if estimated_frame_number is not None:
3868
3880
  return estimated_frame_number
3869
3881
  else:
@@ -3939,7 +3951,8 @@ class MainWindow(QMainWindow, Ui_MainWindow):
3939
3951
  if self.dw_player[0].player.duration is None:
3940
3952
  return
3941
3953
  video_position = slider_position * self.dw_player[0].player.duration
3942
- self.dw_player[0].player.command("seek", str(video_position), "absolute")
3954
+ # self.dw_player[0].player.command("seek", str(video_position), "absolute")
3955
+ self.dw_player[0].player.seek(video_position, "absolute")
3943
3956
 
3944
3957
  self.plot_timer_out()
3945
3958
 
@@ -4132,7 +4145,7 @@ class MainWindow(QMainWindow, Ui_MainWindow):
4132
4145
  self.dw_player[n_player].player.playlist_pos = self.dw_player[n_player].player.playlist_count - 1
4133
4146
  self.seek_mediaplayer(self.dw_player[n_player].media_durations[-1], player=n_player)
4134
4147
 
4135
- def mpv_timer_out(self, value: Union[float, None], scroll_slider=True):
4148
+ def mpv_timer_out(self, value: float | None = None, scroll_slider=True):
4136
4149
  """
4137
4150
  print the media current position and total length for MPV player
4138
4151
  scroll video slider to video position
@@ -4147,8 +4160,8 @@ class MainWindow(QMainWindow, Ui_MainWindow):
4147
4160
  frame_idx = self.get_frame_index()
4148
4161
  # frame_idx = 0
4149
4162
 
4150
- if value is None:
4151
- current_media_time_pos = 0
4163
+ if value is None: # ipc mpv
4164
+ current_media_time_pos = self.dw_player[0].player.time_pos
4152
4165
  else:
4153
4166
  current_media_time_pos = value
4154
4167
 
@@ -4186,22 +4199,19 @@ class MainWindow(QMainWindow, Ui_MainWindow):
4186
4199
 
4187
4200
  ct0 = cumulative_time_pos
4188
4201
 
4189
- if not sys.platform.startswith(cfg.MACOS_CODE):
4190
- if self.dw_player[0].player.time_pos is not None:
4191
- for n_player in range(1, len(self.dw_player)):
4192
- ct = self.getLaps(n_player=n_player)
4202
+ if self.dw_player[0].player.time_pos is not None:
4203
+ for n_player in range(1, len(self.dw_player)):
4204
+ ct = self.getLaps(n_player=n_player)
4193
4205
 
4194
- # sync players 2..8 if time diff >= 1 s
4195
- if (
4196
- abs(ct0 - (ct + dec(self.pj[cfg.OBSERVATIONS][self.observationId][cfg.MEDIA_INFO][cfg.OFFSET][str(n_player + 1)])))
4197
- >= 1
4198
- ):
4199
- self.sync_time(n_player, ct0) # self.seek_mediaplayer(ct0, n_player)
4206
+ # sync players 2..8 if time diff >= 1 s
4207
+ if abs(ct0 - (ct + dec(self.pj[cfg.OBSERVATIONS][self.observationId][cfg.MEDIA_INFO][cfg.OFFSET][str(n_player + 1)]))) >= 1:
4208
+ self.sync_time(n_player, ct0) # self.seek_mediaplayer(ct0, n_player)
4200
4209
 
4201
4210
  currentTimeOffset = dec(cumulative_time_pos + self.pj[cfg.OBSERVATIONS][self.observationId][cfg.TIME_OFFSET])
4202
4211
 
4203
4212
  all_media_duration = sum(self.dw_player[0].media_durations) / 1000
4204
4213
  current_media_duration = self.dw_player[0].player.duration # mediaplayer_length
4214
+
4205
4215
  self.mediaTotalLength = current_media_duration
4206
4216
 
4207
4217
  # current state(s)
@@ -4301,6 +4311,8 @@ class MainWindow(QMainWindow, Ui_MainWindow):
4301
4311
 
4302
4312
  self.actionPlay.setIcon(QIcon(f":/play_{gui_utilities.theme_mode()}"))
4303
4313
 
4314
+ print(f"{msg=}")
4315
+
4304
4316
  if msg:
4305
4317
  self.lb_current_media_time.setText(msg)
4306
4318
 
@@ -4317,14 +4329,6 @@ class MainWindow(QMainWindow, Ui_MainWindow):
4317
4329
 
4318
4330
  logging.info("Media end reached")
4319
4331
 
4320
- """
4321
- print(f"{self.dw_player[0].player.time_pos=}")
4322
- print(f"{self.dw_player[0].player.pause=}")
4323
- print(f"{self.dw_player[0].player.core_idle=}")
4324
- print(f"{self.dw_player[0].player.eof_reached=}")
4325
- print(f"{self.dw_player[0].player.playlist_pos=}")
4326
- """
4327
-
4328
4332
  if self.pj[cfg.OBSERVATIONS][self.observationId][cfg.CLOSE_BEHAVIORS_BETWEEN_VIDEOS]:
4329
4333
  if self.dw_player[0].player.eof_reached and self.dw_player[0].player.core_idle:
4330
4334
  if self.dw_player[0].player.playlist_pos == len(self.dw_player[0].player.playlist) - 1:
@@ -4480,7 +4484,7 @@ class MainWindow(QMainWindow, Ui_MainWindow):
4480
4484
  for x in self.pj[cfg.OBSERVATIONS][obs_id][cfg.EVENTS]
4481
4485
  )
4482
4486
 
4483
- def choose_behavior(self, obs_key) -> Union[None, str]:
4487
+ def choose_behavior(self, obs_key) -> None | str:
4484
4488
  """
4485
4489
  fill listwidget with all behaviors coded by key
4486
4490
 
@@ -4512,7 +4516,7 @@ class MainWindow(QMainWindow, Ui_MainWindow):
4512
4516
  else:
4513
4517
  return None
4514
4518
 
4515
- def choose_subject(self, subject_key) -> Union[None, str]:
4519
+ def choose_subject(self, subject_key) -> None | str:
4516
4520
  """
4517
4521
  fill listwidget with all subjects coded by key
4518
4522
 
@@ -4594,18 +4598,13 @@ class MainWindow(QMainWindow, Ui_MainWindow):
4594
4598
 
4595
4599
  if self.playerType == cfg.MEDIA:
4596
4600
  # cumulative time
4597
- if not sys.platform.startswith(cfg.MACOS_CODE):
4598
- mem_laps = sum(self.dw_player[n_player].media_durations[0 : self.dw_player[n_player].player.playlist_pos]) + (
4599
- 0 if self.dw_player[n_player].player.time_pos is None else self.dw_player[n_player].player.time_pos * 1000
4600
- )
4601
- else:
4602
- time_pos = observation_operations.send_command({"command": ["get_property", "time-pos"]})
4603
- # TODO: fix!
4604
- return dec(time_pos)
4601
+ mem_laps = sum(self.dw_player[n_player].media_durations[0 : self.dw_player[n_player].player.playlist_pos]) + (
4602
+ 0 if self.dw_player[n_player].player.time_pos is None else self.dw_player[n_player].player.time_pos * 1000
4603
+ )
4605
4604
 
4606
4605
  return dec(str(round(mem_laps / 1000, 3)))
4607
4606
 
4608
- def get_obs_time(self, n_player: int = 0) -> Tuple[dec, dec | None]:
4607
+ def get_obs_time(self, n_player: int = 0) -> tuple[dec, dec | None]:
4609
4608
  """
4610
4609
  returns time in current media and cumulative time from begining of observation
4611
4610
  do not add time offset
@@ -5389,6 +5388,18 @@ class MainWindow(QMainWindow, Ui_MainWindow):
5389
5388
  """
5390
5389
  logging.debug("function: closeEvent")
5391
5390
 
5391
+ # close MPV in IPC mode
5392
+ if self.MPV_IPC_MODE:
5393
+ try:
5394
+ for idx, p in enumerate(self.dw_player):
5395
+ p.player.process.terminate()
5396
+ try:
5397
+ p.player.process.wait(timeout=3) # wait up to 3s
5398
+ except subprocess.TimeoutExpired:
5399
+ p.player.process.kill() # force if still alive
5400
+ except Exception as e:
5401
+ logging.warning(f"Error stopping MPV process #{idx}: {e}")
5402
+
5392
5403
  # check if re-encoding
5393
5404
  if self.processes:
5394
5405
  if (
@@ -5442,6 +5453,8 @@ class MainWindow(QMainWindow, Ui_MainWindow):
5442
5453
  check if first player ended
5443
5454
  """
5444
5455
 
5456
+ print("play_video")
5457
+
5445
5458
  if self.geometric_measurements_mode:
5446
5459
  return
5447
5460
 
@@ -5463,6 +5476,9 @@ class MainWindow(QMainWindow, Ui_MainWindow):
5463
5476
 
5464
5477
  self.statusbar.showMessage("", 0)
5465
5478
 
5479
+ if self.ipc_mpv_timer is not None:
5480
+ self.ipc_mpv_timer.start()
5481
+
5466
5482
  self.plot_timer.start()
5467
5483
 
5468
5484
  # start all timer for plotting data
@@ -5494,6 +5510,10 @@ class MainWindow(QMainWindow, Ui_MainWindow):
5494
5510
  for data_timer in self.ext_data_timer_list:
5495
5511
  data_timer.stop()
5496
5512
 
5513
+ if self.ipc_mpv_timer is not None:
5514
+ self.ipc_mpv_timer.stop()
5515
+ self.mpv_timer_out()
5516
+
5497
5517
  player.player.pause = True
5498
5518
 
5499
5519
  self.lb_player_status.setText(msg)
@@ -5543,13 +5563,6 @@ class MainWindow(QMainWindow, Ui_MainWindow):
5543
5563
 
5544
5564
  self.update_visualizations()
5545
5565
 
5546
- # subtitles
5547
- """
5548
- st_track_number = 0 if self.config_param[DISPLAY_SUBTITLES] else -1
5549
- for player in self.dw_player:
5550
- player.mediaplayer.video_set_spu(st_track_number)
5551
- """
5552
-
5553
5566
  def jumpForward_activated(self):
5554
5567
  """
5555
5568
  forward from current position
@@ -5806,6 +5819,22 @@ def main():
5806
5819
  results.ptText.appendHtml(f"Some issues were found in the project<br><br>{msg}")
5807
5820
  results.show()
5808
5821
 
5822
+ # check mpv IPC mode
5823
+ window.MPV_IPC_MODE = False
5824
+ if options.ipc or sys.platform.startswith("darwin"):
5825
+ window.MPV_IPC_MODE = True
5826
+ # check if mpv is available
5827
+ if not shutil.which("mpv"):
5828
+ logging.critical("The mpv command is not available on the path")
5829
+ QMessageBox.critical(
5830
+ None,
5831
+ cfg.programName,
5832
+ ("The mpv command is not available on the path"),
5833
+ QMessageBox.Ok | QMessageBox.Default,
5834
+ QMessageBox.NoButton,
5835
+ )
5836
+ sys.exit()
5837
+
5809
5838
  window.show()
5810
5839
  window.raise_() # for overlapping widget (?)
5811
5840